Fix no text displayed issue when font embedded and font subsetting enabled
[pdfium.git] / core / src / fxge / ge / fx_ge_text.cpp
1 // Copyright 2014 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4  
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7 #include "../../../include/fxge/fx_ge.h"
8 #include "../../../include/fxge/fx_freetype.h"
9 #include "../../../include/fxcodec/fx_codec.h"
10 #include "text_int.h"
11 #undef FX_GAMMA
12 #undef FX_GAMMA_INVERSE
13 #define FX_GAMMA(value)                 (value)
14 #define FX_GAMMA_INVERSE(value) (value)
15 FX_RECT FXGE_GetGlyphsBBox(FXTEXT_GLYPHPOS* pGlyphAndPos, int nChars, int anti_alias, FX_FLOAT retinaScaleX, FX_FLOAT retinaScaleY)
16 {
17     FX_RECT rect(0, 0, 0, 0);
18     FX_BOOL bStarted = FALSE;
19     for (int iChar = 0; iChar < nChars; iChar ++) {
20         FXTEXT_GLYPHPOS& glyph = pGlyphAndPos[iChar];
21         const CFX_GlyphBitmap* pGlyph = glyph.m_pGlyph;
22         if (pGlyph == NULL) {
23             continue;
24         }
25         int char_left = glyph.m_OriginX + pGlyph->m_Left;
26         int char_width = (int)(pGlyph->m_Bitmap.GetWidth() / retinaScaleX);
27         if (anti_alias == FXFT_RENDER_MODE_LCD) {
28             char_width /= 3;
29         }
30         int char_right = char_left + char_width;
31         int char_top = glyph.m_OriginY - pGlyph->m_Top;
32         int char_bottom = char_top + (int)(pGlyph->m_Bitmap.GetHeight() / retinaScaleY);
33         if (!bStarted) {
34             rect.left = char_left;
35             rect.right = char_right;
36             rect.top = char_top;
37             rect.bottom = char_bottom;
38             bStarted = TRUE;
39         } else {
40             if (rect.left > char_left) {
41                 rect.left = char_left;
42             }
43             if (rect.right < char_right) {
44                 rect.right = char_right;
45             }
46             if (rect.top > char_top) {
47                 rect.top = char_top;
48             }
49             if (rect.bottom < char_bottom) {
50                 rect.bottom = char_bottom;
51             }
52         }
53     }
54     return rect;
55 }
56 static void _AdjustGlyphSpace(FXTEXT_GLYPHPOS* pGlyphAndPos, int nChars)
57 {
58     ASSERT(nChars > 1);
59     FX_BOOL bVertical = FALSE;
60     if (pGlyphAndPos[nChars - 1].m_OriginX == pGlyphAndPos[0].m_OriginX) {
61         bVertical = TRUE;
62     } else if (pGlyphAndPos[nChars - 1].m_OriginY != pGlyphAndPos[0].m_OriginY) {
63         return;
64     }
65     int i = nChars - 1;
66     int* next_origin = bVertical ? &pGlyphAndPos[i].m_OriginY : &pGlyphAndPos[i].m_OriginX;
67     FX_FLOAT next_origin_f = bVertical ? pGlyphAndPos[i].m_fOriginY : pGlyphAndPos[i].m_fOriginX;
68     for (i --; i > 0; i --) {
69         int* this_origin = bVertical ? &pGlyphAndPos[i].m_OriginY : &pGlyphAndPos[i].m_OriginX;
70         FX_FLOAT this_origin_f = bVertical ? pGlyphAndPos[i].m_fOriginY : pGlyphAndPos[i].m_fOriginX;
71         int space = (*next_origin) - (*this_origin);
72         FX_FLOAT space_f = next_origin_f - this_origin_f;
73         FX_FLOAT error = (FX_FLOAT)(FXSYS_fabs(space_f) - FXSYS_fabs((FX_FLOAT)(space)));
74         if (error > 0.5f) {
75             *this_origin += space > 0 ? -1 : 1;
76         }
77         next_origin = this_origin;
78         next_origin_f = this_origin_f;
79     }
80 }
81 static const FX_BYTE g_TextGammaAdjust[256] = {
82     0, 2, 3, 4, 6, 7, 8, 10, 11, 12, 13, 15, 16, 17, 18, 19,
83     21, 22, 23, 24, 25, 26, 27, 29, 30, 31, 32, 33, 34, 35, 36, 38,
84     39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 51, 52, 53, 54, 55,
85     56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 71, 72,
86     73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88,
87     89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104,
88     105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120,
89     121, 122, 123, 124, 125, 126, 127, 128, 129, 129, 130, 131, 132, 133, 134, 135,
90     136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151,
91     152, 153, 154, 155, 156, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166,
92     167, 168, 169, 170, 171, 172, 173, 174, 174, 175, 176, 177, 178, 179, 180, 181,
93     182, 183, 184, 185, 186, 187, 188, 189, 190, 190, 191, 192, 193, 194, 195, 196,
94     197, 198, 199, 200, 201, 202, 203, 204, 204, 205, 206, 207, 208, 209, 210, 211,
95     212, 213, 214, 215, 216, 217, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226,
96     227, 228, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 239, 240,
97     241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 250, 251, 252, 253, 254, 255,
98 };
99 #define ADJUST_ALPHA(background, foreground, src_alpha, text_flags, a) \
100     src_alpha = g_TextGammaAdjust[(FX_BYTE)src_alpha];
101 void _Color2Argb(FX_ARGB& argb, FX_DWORD color, int alpha_flag, void* pIccTransform)
102 {
103     if (pIccTransform == NULL && !FXGETFLAG_COLORTYPE(alpha_flag)) {
104         argb = color;
105         return;
106     }
107     if (!CFX_GEModule::Get()->GetCodecModule() || !CFX_GEModule::Get()->GetCodecModule()->GetIccModule()) {
108         pIccTransform = NULL;
109     }
110     FX_BYTE bgra[4];
111     if (pIccTransform) {
112         ICodec_IccModule* pIccModule = CFX_GEModule::Get()->GetCodecModule()->GetIccModule();
113         color = FXGETFLAG_COLORTYPE(alpha_flag) ? FXCMYK_TODIB(color) : FXARGB_TODIB(color);
114         pIccModule->TranslateScanline(pIccTransform, bgra, (FX_LPCBYTE)&color, 1);
115         bgra[3] = FXGETFLAG_COLORTYPE(alpha_flag) ?
116                   (alpha_flag >> 24) ? FXGETFLAG_ALPHA_FILL(alpha_flag) : FXGETFLAG_ALPHA_STROKE(alpha_flag) :
117                   FXARGB_A(color);
118         argb = FXARGB_MAKE(bgra[3], bgra[2], bgra[1], bgra[0]);
119         return;
120     }
121     AdobeCMYK_to_sRGB1(FXSYS_GetCValue(color), FXSYS_GetMValue(color),
122                        FXSYS_GetYValue(color), FXSYS_GetKValue(color),
123                        bgra[2], bgra[1], bgra[0]);
124     bgra[3] = (alpha_flag >> 24) ? FXGETFLAG_ALPHA_FILL(alpha_flag) : FXGETFLAG_ALPHA_STROKE(alpha_flag);
125     argb = FXARGB_MAKE(bgra[3], bgra[2], bgra[1], bgra[0]);
126 }
127 FX_BOOL CFX_RenderDevice::DrawNormalText(int nChars, const FXTEXT_CHARPOS* pCharPos,
128         CFX_Font* pFont, CFX_FontCache* pCache,
129         FX_FLOAT font_size, const CFX_AffineMatrix* pText2Device,
130         FX_DWORD fill_color, FX_DWORD text_flags,
131         int alpha_flag, void* pIccTransform)
132 {
133     int nativetext_flags = text_flags;
134     if (m_DeviceClass != FXDC_DISPLAY) {
135         if (!(text_flags & FXTEXT_PRINTGRAPHICTEXT)) {
136 #if _FXM_PLATFORM_  == _FXM_PLATFORM_APPLE_
137             if (!(text_flags & FXFONT_CIDFONT) && pFont->GetPsName().Find(CFX_WideString::FromLocal("+ZJHL")) == -1)
138 #ifdef FOXIT_CHROME_BUILD
139                 if (pFont->GetPsName() != CFX_WideString::FromLocal("CNAAJI+cmex10"))
140 #endif
141 #endif
142                     if (m_pDeviceDriver->DrawDeviceText(nChars, pCharPos, pFont, pCache, pText2Device, font_size, fill_color, alpha_flag, pIccTransform)) {
143                         return TRUE;
144                     }
145         }
146         int alpha = FXGETFLAG_COLORTYPE(alpha_flag) ? FXGETFLAG_ALPHA_FILL(alpha_flag) : FXARGB_A(fill_color);
147         if (alpha < 255) {
148             return FALSE;
149         }
150     } else if (!(text_flags & FXTEXT_NO_NATIVETEXT)) {
151 #if _FXM_PLATFORM_  == _FXM_PLATFORM_APPLE_
152         if (!(text_flags & FXFONT_CIDFONT))
153 #ifdef FOXIT_CHROME_BUILD
154             if (pFont->GetPsName() != CFX_WideString::FromLocal("CNAAJI+cmex10"))
155 #endif
156 #endif
157                 if (m_pDeviceDriver->DrawDeviceText(nChars, pCharPos, pFont, pCache, pText2Device, font_size, fill_color, alpha_flag, pIccTransform)) {
158                     return TRUE;
159                 }
160     }
161     CFX_AffineMatrix char2device, deviceCtm, text2Device;
162     if (pText2Device) {
163         char2device = *pText2Device;
164         text2Device = *pText2Device;
165     }
166     char2device.Scale(font_size, -font_size);
167     if (FXSYS_fabs(char2device.a) + FXSYS_fabs(char2device.b) > 50 * 1.0f ||
168             ((m_DeviceClass == FXDC_PRINTER && !m_pDeviceDriver->IsPSPrintDriver())
169              && !(text_flags & FXTEXT_PRINTIMAGETEXT))) {
170         if (pFont->GetFace() != NULL || (pFont->GetSubstFont()->m_SubstFlags & FXFONT_SUBST_GLYPHPATH)) {
171             int nPathFlags = (text_flags & FXTEXT_NOSMOOTH) == 0 ? 0 : FXFILL_NOPATHSMOOTH;
172             return DrawTextPath(nChars, pCharPos, pFont, pCache, font_size, pText2Device, NULL, NULL, fill_color, 0, NULL, nPathFlags, alpha_flag, pIccTransform);
173         }
174     }
175     int anti_alias = FXFT_RENDER_MODE_MONO;
176     FX_BOOL bNormal = FALSE;
177     if ((text_flags & FXTEXT_NOSMOOTH) == 0) {
178         if (m_DeviceClass == FXDC_DISPLAY && m_bpp > 1) {
179             FX_BOOL bClearType;
180             if (pFont->GetFace() == NULL && !(pFont->GetSubstFont()->m_SubstFlags & FXFONT_SUBST_CLEARTYPE)) {
181                 bClearType = FALSE;
182             } else {
183                 bClearType = text_flags & FXTEXT_CLEARTYPE;
184             }
185             if ((m_RenderCaps & (FXRC_ALPHA_OUTPUT | FXRC_CMYK_OUTPUT))) {
186                 anti_alias = FXFT_RENDER_MODE_LCD;
187                 bNormal = TRUE;
188             } else if (m_bpp < 16) {
189                 anti_alias = FXFT_RENDER_MODE_NORMAL;
190             } else {
191                 if (bClearType == FALSE) {
192                     anti_alias = FXFT_RENDER_MODE_LCD;
193                     bNormal = TRUE;
194                 } else {
195                     anti_alias = FXFT_RENDER_MODE_LCD;
196                 }
197             }
198         }
199     }
200     if (pCache == NULL) {
201         pCache = CFX_GEModule::Get()->GetFontCache();
202     }
203     CFX_FaceCache* pFaceCache = pCache->GetCachedFace(pFont);
204     FX_FONTCACHE_DEFINE(pCache, pFont);
205     FXTEXT_GLYPHPOS* pGlyphAndPos = FX_Alloc(FXTEXT_GLYPHPOS, nChars);
206     if (!pGlyphAndPos) {
207         return FALSE;
208     }
209     int iChar;
210     deviceCtm = char2device;
211     CFX_AffineMatrix matrixCTM = GetCTM();
212     FX_FLOAT scale_x = FXSYS_fabs(matrixCTM.a);
213     FX_FLOAT scale_y = FXSYS_fabs(matrixCTM.d);
214     deviceCtm.Concat(scale_x, 0, 0, scale_y, 0, 0);
215     text2Device.Concat(scale_x, 0, 0, scale_y, 0, 0);
216     for (iChar = 0; iChar < nChars; iChar ++) {
217         FXTEXT_GLYPHPOS& glyph = pGlyphAndPos[iChar];
218         const FXTEXT_CHARPOS& charpos = pCharPos[iChar];
219         glyph.m_fOriginX = charpos.m_OriginX;
220         glyph.m_fOriginY = charpos.m_OriginY;
221         text2Device.Transform(glyph.m_fOriginX, glyph.m_fOriginY);
222         if (anti_alias < FXFT_RENDER_MODE_LCD) {
223             glyph.m_OriginX = FXSYS_round(glyph.m_fOriginX);
224         } else {
225             glyph.m_OriginX = (int)FXSYS_floor(glyph.m_fOriginX);
226         }
227         glyph.m_OriginY = FXSYS_round(glyph.m_fOriginY);
228         if (charpos.m_bGlyphAdjust) {
229             CFX_AffineMatrix new_matrix(charpos.m_AdjustMatrix[0], charpos.m_AdjustMatrix[1],
230                                         charpos.m_AdjustMatrix[2], charpos.m_AdjustMatrix[3], 0, 0);
231             new_matrix.Concat(deviceCtm);
232             glyph.m_pGlyph = pFaceCache->LoadGlyphBitmap(pFont, charpos.m_GlyphIndex, charpos.m_bFontStyle, &new_matrix,
233                              charpos.m_FontCharWidth, anti_alias, nativetext_flags);
234         } else
235             glyph.m_pGlyph = pFaceCache->LoadGlyphBitmap(pFont, charpos.m_GlyphIndex, charpos.m_bFontStyle, &deviceCtm,
236                              charpos.m_FontCharWidth, anti_alias, nativetext_flags);
237     }
238     if (anti_alias < FXFT_RENDER_MODE_LCD && nChars > 1) {
239         _AdjustGlyphSpace(pGlyphAndPos, nChars);
240     }
241     FX_RECT bmp_rect1 = FXGE_GetGlyphsBBox(pGlyphAndPos, nChars, anti_alias);
242     if (scale_x > 1 && scale_y > 1) {
243         bmp_rect1.left--;
244         bmp_rect1.top --;
245         bmp_rect1.right ++;
246         bmp_rect1.bottom ++;
247     }
248     FX_RECT bmp_rect(FXSYS_round((FX_FLOAT)(bmp_rect1.left) / scale_x), FXSYS_round((FX_FLOAT)(bmp_rect1.top) / scale_y),
249                      FXSYS_round((FX_FLOAT)bmp_rect1.right / scale_x), FXSYS_round((FX_FLOAT)bmp_rect1.bottom / scale_y));
250     bmp_rect.Intersect(m_ClipBox);
251     if (bmp_rect.IsEmpty()) {
252         FX_Free(pGlyphAndPos);
253         return TRUE;
254     }
255     int pixel_width = FXSYS_round(bmp_rect.Width() * scale_x);
256     int pixel_height = FXSYS_round(bmp_rect.Height() * scale_y);
257     int pixel_left = FXSYS_round(bmp_rect.left * scale_x);
258     int pixel_top = FXSYS_round(bmp_rect.top * scale_y);
259     if (anti_alias == FXFT_RENDER_MODE_MONO) {
260         CFX_DIBitmap bitmap;
261         if (!bitmap.Create(pixel_width, pixel_height, FXDIB_1bppMask)) {
262             FX_Free(pGlyphAndPos);
263             return FALSE;
264         }
265         bitmap.Clear(0);
266         for (iChar = 0; iChar < nChars; iChar ++) {
267             FXTEXT_GLYPHPOS& glyph = pGlyphAndPos[iChar];
268             if (glyph.m_pGlyph == NULL) {
269                 continue;
270             }
271             const CFX_DIBitmap* pGlyph = &glyph.m_pGlyph->m_Bitmap;
272             bitmap.TransferBitmap(glyph.m_OriginX + glyph.m_pGlyph->m_Left - pixel_left,
273                                   glyph.m_OriginY - glyph.m_pGlyph->m_Top - pixel_top,
274                                   pGlyph->GetWidth(), pGlyph->GetHeight(), pGlyph, 0, 0);
275         }
276         FX_Free(pGlyphAndPos);
277         return SetBitMask(&bitmap, bmp_rect.left, bmp_rect.top, fill_color);
278     }
279     CFX_DIBitmap bitmap;
280     if (m_bpp == 8) {
281         if (!bitmap.Create(pixel_width, pixel_height, FXDIB_8bppMask)) {
282             FX_Free(pGlyphAndPos);
283             return FALSE;
284         }
285     } else {
286         if (!CreateCompatibleBitmap(&bitmap, pixel_width, pixel_height)) {
287             FX_Free(pGlyphAndPos);
288             return FALSE;
289         }
290     }
291     if (!bitmap.HasAlpha() && !bitmap.IsAlphaMask()) {
292         bitmap.Clear(0xFFFFFFFF);
293         if (!GetDIBits(&bitmap, bmp_rect.left, bmp_rect.top)) {
294             FX_Free(pGlyphAndPos);
295             return FALSE;
296         }
297     } else {
298         bitmap.Clear(0);
299         if (bitmap.m_pAlphaMask) {
300             bitmap.m_pAlphaMask->Clear(0);
301         }
302     }
303     int dest_width = pixel_width;
304     FX_LPBYTE dest_buf = bitmap.GetBuffer();
305     int dest_pitch = bitmap.GetPitch();
306     int Bpp = bitmap.GetBPP() / 8;
307     int a, r, g, b;
308     if (anti_alias == FXFT_RENDER_MODE_LCD) {
309         _Color2Argb(fill_color, fill_color, alpha_flag | (1 << 24), pIccTransform);
310         ArgbDecode(fill_color, a, r, g, b);
311         r = FX_GAMMA(r);
312         g = FX_GAMMA(g);
313         b = FX_GAMMA(b);
314     }
315     for (iChar = 0; iChar < nChars; iChar ++) {
316         FXTEXT_GLYPHPOS& glyph = pGlyphAndPos[iChar];
317         if (glyph.m_pGlyph == NULL) {
318             continue;
319         }
320         const CFX_DIBitmap* pGlyph = &glyph.m_pGlyph->m_Bitmap;
321         int left = glyph.m_OriginX + glyph.m_pGlyph->m_Left - pixel_left;
322         int top = glyph.m_OriginY - glyph.m_pGlyph->m_Top - pixel_top;
323         int ncols = pGlyph->GetWidth();
324         int nrows = pGlyph->GetHeight();
325         if (anti_alias == FXFT_RENDER_MODE_NORMAL) {
326             if (!bitmap.CompositeMask(left, top, ncols, nrows, pGlyph, fill_color,
327                                       0, 0, FXDIB_BLEND_NORMAL, NULL, FALSE, alpha_flag, pIccTransform)) {
328                 FX_Free(pGlyphAndPos);
329                 return FALSE;
330             }
331             continue;
332         }
333         FX_BOOL bBGRStripe = text_flags & FXTEXT_BGR_STRIPE;
334         ncols /= 3;
335         int x_subpixel = (int)(glyph.m_fOriginX * 3) % 3;
336         FX_LPBYTE src_buf = pGlyph->GetBuffer();
337         int src_pitch = pGlyph->GetPitch();
338         int start_col = left;
339         if (start_col < 0) {
340             start_col = 0;
341         }
342         int end_col = left + ncols;
343         if (end_col > dest_width) {
344             end_col = dest_width;
345         }
346         if (start_col >= end_col) {
347             continue;
348         }
349         if (bitmap.GetFormat() == FXDIB_Argb) {
350             for (int row = 0; row < nrows; row ++) {
351                 int dest_row = row + top;
352                 if (dest_row < 0 || dest_row >= bitmap.GetHeight()) {
353                     continue;
354                 }
355                 FX_LPBYTE src_scan = src_buf + row * src_pitch + (start_col - left) * 3;
356                 FX_LPBYTE dest_scan = dest_buf + dest_row * dest_pitch + (start_col << 2);
357                 if (bBGRStripe) {
358                     if (x_subpixel == 0) {
359                         for (int col = start_col; col < end_col; col ++) {
360                             int src_alpha = src_scan[2];
361                             src_alpha = src_alpha * a / 255;
362                             dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
363                             src_alpha = src_scan[1];
364                             src_alpha = src_alpha * a / 255;
365                             dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
366                             src_alpha = src_scan[0];
367                             src_alpha = src_alpha * a / 255;
368                             dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
369                             dest_scan[3] = 255;
370                             dest_scan += 4;
371                             src_scan += 3;
372                         }
373                     } else if (x_subpixel == 1) {
374                         int src_alpha = src_scan[1];
375                         ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
376                         src_alpha = src_alpha * a / 255;
377                         dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
378                         src_alpha = src_scan[0];
379                         ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
380                         src_alpha = src_alpha * a / 255;
381                         dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
382                         if (start_col > left) {
383                             src_alpha = src_scan[-1];
384                             ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
385                             src_alpha = src_alpha * a / 255;
386                             dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
387                         }
388                         dest_scan[3] = 255;
389                         dest_scan += 4;
390                         src_scan += 3;
391                         for (int col = start_col + 1; col < end_col - 1; col ++) {
392                             int src_alpha = src_scan[1];
393                             ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
394                             src_alpha = src_alpha * a / 255;
395                             dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
396                             src_alpha = src_scan[0];
397                             ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
398                             src_alpha = src_alpha * a / 255;
399                             dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
400                             src_alpha = src_scan[-1];
401                             ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
402                             src_alpha = src_alpha * a / 255;
403                             dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
404                             dest_scan[3] = 255;
405                             dest_scan += 4;
406                             src_scan += 3;
407                         }
408                     } else {
409                         int src_alpha = src_scan[0];
410                         ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
411                         src_alpha = src_alpha * a / 255;
412                         dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
413                         if (start_col > left) {
414                             src_alpha = src_scan[-1];
415                             ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
416                             src_alpha = src_alpha * a / 255;
417                             dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
418                             src_alpha = src_scan[-2];
419                             ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
420                             src_alpha = src_alpha * a / 255;
421                             dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
422                         }
423                         dest_scan[3] = 255;
424                         dest_scan += 4;
425                         src_scan += 3;
426                         for (int col = start_col + 1; col < end_col - 1; col ++) {
427                             int src_alpha = src_scan[0];
428                             ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
429                             src_alpha = src_alpha * a / 255;
430                             dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
431                             src_alpha = src_scan[-1];
432                             ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
433                             src_alpha = src_alpha * a / 255;
434                             dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
435                             src_alpha = src_scan[-2];
436                             ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
437                             src_alpha = src_alpha * a / 255;
438                             dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
439                             dest_scan[3] = 255;
440                             dest_scan += 4;
441                             src_scan += 3;
442                         }
443                     }
444                 } else {
445                     if (x_subpixel == 0) {
446                         for (int col = start_col; col < end_col; col ++) {
447                             if (bNormal) {
448                                 int src_alpha1 = (src_scan[0] + src_scan[1] + src_scan[2]) / 3;
449                                 ADJUST_ALPHA(dest_scan[2], r, src_alpha1, nativetext_flags, a);
450                                 src_alpha1 = src_alpha1 * a / 255;
451                                 FX_BYTE back_alpha = dest_scan[3];
452                                 if (back_alpha == 0) {
453                                     FXARGB_SETDIB(dest_scan, FXARGB_MAKE(src_alpha1, r, g, b));
454                                     dest_scan += 4;
455                                     src_scan += 3;
456                                     continue;
457                                 }
458                                 if (src_alpha1 == 0) {
459                                     dest_scan += 4;
460                                     src_scan += 3;
461                                     continue;
462                                 }
463                                 FX_BYTE dest_alpha = back_alpha + src_alpha1 - back_alpha * src_alpha1 / 255;
464                                 dest_scan[3] = dest_alpha;
465                                 int alpha_ratio = src_alpha1 * 255 / dest_alpha;
466                                 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, alpha_ratio));
467                                 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, alpha_ratio));
468                                 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, alpha_ratio));
469                                 dest_scan += 4;
470                                 src_scan += 3;
471                                 continue;
472                             }
473                             int src_alpha = src_scan[0];
474                             ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
475                             src_alpha = src_alpha * a / 255;
476                             dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
477                             src_alpha = src_scan[1];
478                             ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
479                             src_alpha = src_alpha * a / 255;
480                             dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
481                             src_alpha = src_scan[2];
482                             ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
483                             src_alpha = src_alpha * a / 255;
484                             dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
485                             dest_scan[3] = 255;
486                             dest_scan += 4;
487                             src_scan += 3;
488                         }
489                     } else if (x_subpixel == 1) {
490                         if (bNormal) {
491                             int src_alpha1 = start_col > left ? ((src_scan[-1] + src_scan[0] + src_scan[1]) / 3) : ((src_scan[0] + src_scan[1]) / 3);
492                             ADJUST_ALPHA(dest_scan[2], r, src_alpha1, nativetext_flags, a);
493                             src_alpha1 = src_alpha1 * a / 255;
494                             if (src_alpha1 == 0) {
495                                 dest_scan += 4;
496                                 src_scan += 3;
497                             } else {
498                                 FX_BYTE back_alpha = dest_scan[3];
499                                 if (back_alpha == 0) {
500                                     FXARGB_SETDIB(dest_scan, FXARGB_MAKE(src_alpha1, r, g, b));
501                                 } else {
502                                     FX_BYTE dest_alpha = back_alpha + src_alpha1 - back_alpha * src_alpha1 / 255;
503                                     dest_scan[3] = dest_alpha;
504                                     int alpha_ratio = src_alpha1 * 255 / dest_alpha;
505                                     dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, alpha_ratio));
506                                     dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, alpha_ratio));
507                                     dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, alpha_ratio));
508                                 }
509                                 dest_scan += 4;
510                                 src_scan += 3;
511                             }
512                         } else {
513                             if (start_col > left) {
514                                 int src_alpha = src_scan[-1];
515                                 ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
516                                 src_alpha = src_alpha * a / 255;
517                                 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
518                             }
519                             int src_alpha = src_scan[0];
520                             ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
521                             src_alpha = src_alpha * a / 255;
522                             dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
523                             src_alpha = src_scan[1];
524                             ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
525                             src_alpha = src_alpha * a / 255;
526                             dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
527                             dest_scan[3] = 255;
528                             dest_scan += 4;
529                             src_scan += 3;
530                         }
531                         for (int col = start_col + 1; col < end_col; col ++) {
532                             if (bNormal) {
533                                 int src_alpha1 = (src_scan[-1] + src_scan[0] + src_scan[1]) / 3;
534                                 ADJUST_ALPHA(dest_scan[2], r, src_alpha1, nativetext_flags, a);
535                                 src_alpha1 = src_alpha1 * a / 255;
536                                 FX_BYTE back_alpha = dest_scan[3];
537                                 if (back_alpha == 0) {
538                                     FXARGB_SETDIB(dest_scan, FXARGB_MAKE(src_alpha1, r, g, b));
539                                     dest_scan += 4;
540                                     src_scan += 3;
541                                     continue;
542                                 }
543                                 if (src_alpha1 == 0) {
544                                     dest_scan += 4;
545                                     src_scan += 3;
546                                     continue;
547                                 }
548                                 FX_BYTE dest_alpha = back_alpha + src_alpha1 - back_alpha * src_alpha1 / 255;
549                                 dest_scan[3] = dest_alpha;
550                                 int alpha_ratio = src_alpha1 * 255 / dest_alpha;
551                                 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, alpha_ratio));
552                                 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, alpha_ratio));
553                                 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, alpha_ratio));
554                                 dest_scan += 4;
555                                 src_scan += 3;
556                                 continue;
557                             }
558                             int src_alpha = src_scan[-1];
559                             ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
560                             src_alpha = src_alpha * a / 255;
561                             dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
562                             src_alpha = src_scan[0];
563                             ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
564                             src_alpha = src_alpha * a / 255;
565                             dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
566                             src_alpha = src_scan[1];
567                             ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
568                             src_alpha = src_alpha * a / 255;
569                             dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
570                             dest_scan[3] = 255;
571                             dest_scan += 4;
572                             src_scan += 3;
573                         }
574                     } else {
575                         if (bNormal) {
576                             int src_alpha1 = start_col > left ? ((src_scan[-2] + src_scan[-1] + src_scan[0]) / 3) : ((src_scan[0]) / 3);
577                             ADJUST_ALPHA(dest_scan[2], r, src_alpha1, nativetext_flags, a);
578                             src_alpha1 = src_alpha1 * a / 255;
579                             if (src_alpha1 == 0) {
580                                 dest_scan += 4;
581                                 src_scan += 3;
582                             } else {
583                                 FX_BYTE back_alpha = dest_scan[3];
584                                 if (back_alpha == 0) {
585                                     FXARGB_SETDIB(dest_scan, FXARGB_MAKE(src_alpha1, r, g, b));
586                                 } else {
587                                     FX_BYTE dest_alpha = back_alpha + src_alpha1 - back_alpha * src_alpha1 / 255;
588                                     dest_scan[3] = dest_alpha;
589                                     int alpha_ratio = src_alpha1 * 255 / dest_alpha;
590                                     dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, alpha_ratio));
591                                     dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, alpha_ratio));
592                                     dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, alpha_ratio));
593                                 }
594                                 dest_scan += 4;
595                                 src_scan += 3;
596                             }
597                         } else {
598                             if (start_col > left) {
599                                 int src_alpha = src_scan[-2];
600                                 ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
601                                 src_alpha = src_alpha * a / 255;
602                                 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
603                                 src_alpha = src_scan[-1];
604                                 ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
605                                 src_alpha = src_alpha * a / 255;
606                                 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
607                             }
608                             int src_alpha = src_scan[0];
609                             ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
610                             src_alpha = src_alpha * a / 255;
611                             dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
612                             dest_scan[3] = 255;
613                             dest_scan += 4;
614                             src_scan += 3;
615                         }
616                         for (int col = start_col + 1; col < end_col; col ++) {
617                             if (bNormal) {
618                                 int src_alpha1 = (src_scan[-2] + src_scan[-1] + src_scan[0]) / 3;
619                                 ADJUST_ALPHA(dest_scan[2], r, src_alpha1, nativetext_flags, a);
620                                 src_alpha1 = src_alpha1 * a / 255;
621                                 FX_BYTE back_alpha = dest_scan[3];
622                                 if (back_alpha == 0) {
623                                     FXARGB_SETDIB(dest_scan, FXARGB_MAKE(src_alpha1, r, g, b));
624                                     dest_scan += 4;
625                                     src_scan += 3;
626                                     continue;
627                                 }
628                                 if (src_alpha1 == 0) {
629                                     dest_scan += 4;
630                                     src_scan += 3;
631                                     continue;
632                                 }
633                                 FX_BYTE dest_alpha = back_alpha + src_alpha1 - back_alpha * src_alpha1 / 255;
634                                 dest_scan[3] = dest_alpha;
635                                 int alpha_ratio = src_alpha1 * 255 / dest_alpha;
636                                 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, alpha_ratio));
637                                 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, alpha_ratio));
638                                 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, alpha_ratio));
639                                 dest_scan += 4;
640                                 src_scan += 3;
641                                 continue;
642                             }
643                             int src_alpha = src_scan[-2];
644                             ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
645                             src_alpha = src_alpha * a / 255;
646                             dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
647                             src_alpha = src_scan[-1];
648                             ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
649                             src_alpha = src_alpha * a / 255;
650                             dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
651                             src_alpha = src_scan[0];
652                             ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
653                             src_alpha = src_alpha * a / 255;
654                             dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
655                             dest_scan[3] = 255;
656                             dest_scan += 4;
657                             src_scan += 3;
658                         }
659                     }
660                 }
661             }
662         } else {
663             for (int row = 0; row < nrows; row ++) {
664                 int dest_row = row + top;
665                 if (dest_row < 0 || dest_row >= bitmap.GetHeight()) {
666                     continue;
667                 }
668                 FX_LPBYTE src_scan = src_buf + row * src_pitch + (start_col - left) * 3;
669                 FX_LPBYTE dest_scan = dest_buf + dest_row * dest_pitch + start_col * Bpp;
670                 if (bBGRStripe) {
671                     if (x_subpixel == 0) {
672                         for (int col = start_col; col < end_col; col ++) {
673                             int src_alpha = src_scan[2];
674                             ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
675                             src_alpha = src_alpha * a / 255;
676                             dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
677                             src_alpha = src_scan[1];
678                             ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
679                             src_alpha = src_alpha * a / 255;
680                             dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
681                             src_alpha = src_scan[0];
682                             ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
683                             src_alpha = src_alpha * a / 255;
684                             dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
685                             dest_scan += Bpp;
686                             src_scan += 3;
687                         }
688                     } else if (x_subpixel == 1) {
689                         int src_alpha = src_scan[1];
690                         ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
691                         src_alpha = src_alpha * a / 255;
692                         dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
693                         src_alpha = src_scan[0];
694                         ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
695                         src_alpha = src_alpha * a / 255;
696                         dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
697                         if (start_col > left) {
698                             src_alpha = src_scan[-1];
699                             ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
700                             src_alpha = src_alpha * a / 255;
701                             dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
702                         }
703                         dest_scan += Bpp;
704                         src_scan += 3;
705                         for (int col = start_col + 1; col < end_col - 1; col ++) {
706                             int src_alpha = src_scan[1];
707                             ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
708                             src_alpha = src_alpha * a / 255;
709                             dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
710                             src_alpha = src_scan[0];
711                             ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
712                             src_alpha = src_alpha * a / 255;
713                             dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
714                             src_alpha = src_scan[-1];
715                             ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
716                             src_alpha = src_alpha * a / 255;
717                             dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
718                             dest_scan += Bpp;
719                             src_scan += 3;
720                         }
721                     } else {
722                         int src_alpha = src_scan[0];
723                         ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
724                         src_alpha = src_alpha * a / 255;
725                         dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
726                         if (start_col > left) {
727                             src_alpha = src_scan[-1];
728                             ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
729                             src_alpha = src_alpha * a / 255;
730                             dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
731                             src_alpha = src_scan[-2];
732                             ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
733                             src_alpha = src_alpha * a / 255;
734                             dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
735                         }
736                         dest_scan += Bpp;
737                         src_scan += 3;
738                         for (int col = start_col + 1; col < end_col - 1; col ++) {
739                             int src_alpha = src_scan[0];
740                             ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
741                             src_alpha = src_alpha * a / 255;
742                             dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
743                             src_alpha = src_scan[-1];
744                             ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
745                             src_alpha = src_alpha * a / 255;
746                             dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
747                             src_alpha = src_scan[-2];
748                             ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
749                             src_alpha = src_alpha * a / 255;
750                             dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
751                             dest_scan += Bpp;
752                             src_scan += 3;
753                         }
754                     }
755                 } else {
756                     if (x_subpixel == 0) {
757                         for (int col = start_col; col < end_col; col ++) {
758                             if (bNormal) {
759                                 int src_alpha1 = (src_scan[0] + src_scan[1] + src_scan[2]) / 3;
760                                 ADJUST_ALPHA(dest_scan[2], r, src_alpha1, nativetext_flags, a);
761                                 src_alpha1 = src_alpha1 * a / 255;
762                                 if (src_alpha1 == 0) {
763                                     dest_scan += Bpp;
764                                     src_scan += 3;
765                                     continue;
766                                 }
767                                 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha1));
768                                 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha1));
769                                 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha1));
770                                 dest_scan += Bpp;
771                                 src_scan += 3;
772                                 continue;
773                             }
774                             int src_alpha = src_scan[0];
775                             ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
776                             src_alpha = src_alpha * a / 255;
777                             dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
778                             src_alpha = src_scan[1];
779                             ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
780                             src_alpha = src_alpha * a / 255;
781                             dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
782                             src_alpha = src_scan[2];
783                             ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
784                             src_alpha = src_alpha * a / 255;
785                             dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
786                             dest_scan += Bpp;
787                             src_scan += 3;
788                         }
789                     } else if (x_subpixel == 1) {
790                         if (bNormal) {
791                             int src_alpha1 = start_col > left ? (src_scan[0] + src_scan[1] + src_scan[-1]) / 3 : (src_scan[0] + src_scan[1]) / 3;
792                             ADJUST_ALPHA(dest_scan[2], r, src_alpha1, nativetext_flags, a);
793                             src_alpha1 = src_alpha1 * a / 255;
794                             dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha1));
795                             dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha1));
796                             dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha1));
797                             dest_scan += Bpp;
798                             src_scan += 3;
799                         } else {
800                             if (start_col > left) {
801                                 int src_alpha = src_scan[-1];
802                                 ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
803                                 src_alpha = src_alpha * a / 255;
804                                 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
805                             }
806                             int src_alpha = src_scan[0];
807                             ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
808                             src_alpha = src_alpha * a / 255;
809                             dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
810                             src_alpha = src_scan[1];
811                             ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
812                             src_alpha = src_alpha * a / 255;
813                             dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
814                             dest_scan += Bpp;
815                             src_scan += 3;
816                         }
817                         for (int col = start_col + 1; col < end_col; col ++) {
818                             if (bNormal) {
819                                 int src_alpha1 = (src_scan[0] + src_scan[1] + src_scan[-1]) / 3;
820                                 ADJUST_ALPHA(dest_scan[2], r, src_alpha1, nativetext_flags, a);
821                                 src_alpha1 = src_alpha1 * a / 255;
822                                 if (src_alpha1 == 0) {
823                                     dest_scan += Bpp;
824                                     src_scan += 3;
825                                     continue;
826                                 }
827                                 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha1));
828                                 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha1));
829                                 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha1));
830                                 dest_scan += Bpp;
831                                 src_scan += 3;
832                                 continue;
833                             }
834                             int src_alpha = src_scan[-1];
835                             ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
836                             src_alpha = src_alpha * a / 255;
837                             dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
838                             src_alpha = src_scan[0];
839                             ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
840                             src_alpha = src_alpha * a / 255;
841                             dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
842                             src_alpha = src_scan[1];
843                             ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
844                             src_alpha = src_alpha * a / 255;
845                             dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
846                             dest_scan += Bpp;
847                             src_scan += 3;
848                         }
849                     } else {
850                         if (bNormal) {
851                             int src_alpha1 = start_col > left ? (src_scan[0] + src_scan[-2] + src_scan[-1]) / 3 : src_scan[0] / 3;
852                             ADJUST_ALPHA(dest_scan[2], r, src_alpha1, nativetext_flags, a);
853                             src_alpha1 = src_alpha1 * a / 255;
854                             dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha1));
855                             dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha1));
856                             dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha1));
857                             dest_scan += Bpp;
858                             src_scan += 3;
859                         } else {
860                             if (start_col > left) {
861                                 int src_alpha = src_scan[-2];
862                                 ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
863                                 src_alpha = src_alpha * a / 255;
864                                 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
865                                 src_alpha = src_scan[-1];
866                                 ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
867                                 src_alpha = src_alpha * a / 255;
868                                 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
869                             }
870                             int src_alpha = src_scan[0];
871                             ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
872                             src_alpha = src_alpha * a / 255;
873                             dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
874                             dest_scan += Bpp;
875                             src_scan += 3;
876                         }
877                         for (int col = start_col + 1; col < end_col; col ++) {
878                             if (bNormal) {
879                                 int src_alpha1 = ((int)(src_scan[0]) + (int)(src_scan[-2]) + (int)(src_scan[-1])) / 3;
880                                 ADJUST_ALPHA(dest_scan[2], r, src_alpha1, nativetext_flags, a);
881                                 src_alpha1 = src_alpha1 * a / 255;
882                                 if (src_alpha1 == 0) {
883                                     dest_scan += Bpp;
884                                     src_scan += 3;
885                                     continue;
886                                 }
887                                 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha1));
888                                 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha1));
889                                 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha1));
890                                 dest_scan += Bpp;
891                                 src_scan += 3;
892                                 continue;
893                             }
894                             int src_alpha = src_scan[-2];
895                             ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
896                             src_alpha = src_alpha * a / 255;
897                             dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
898                             src_alpha = src_scan[-1];
899                             ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
900                             src_alpha = src_alpha * a / 255;
901                             dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
902                             src_alpha = src_scan[0];
903                             ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
904                             src_alpha = src_alpha * a / 255;
905                             dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
906                             dest_scan += Bpp;
907                             src_scan += 3;
908                         }
909                     }
910                 }
911             }
912         }
913     }
914     if (bitmap.IsAlphaMask()) {
915         SetBitMask(&bitmap, bmp_rect.left, bmp_rect.top, fill_color, alpha_flag, pIccTransform);
916     } else {
917         SetDIBits(&bitmap, bmp_rect.left, bmp_rect.top);
918     }
919     FX_Free(pGlyphAndPos);
920     return TRUE;
921 }
922 FX_BOOL CFX_RenderDevice::DrawTextPath(int nChars, const FXTEXT_CHARPOS* pCharPos,
923                                        CFX_Font* pFont, CFX_FontCache* pCache,
924                                        FX_FLOAT font_size, const CFX_AffineMatrix* pText2User,
925                                        const CFX_AffineMatrix* pUser2Device, const CFX_GraphStateData* pGraphState,
926                                        FX_DWORD fill_color, FX_ARGB stroke_color, CFX_PathData* pClippingPath, int nFlag,
927                                        int alpha_flag, void* pIccTransform, int blend_type)
928 {
929     if (pCache == NULL) {
930         pCache = CFX_GEModule::Get()->GetFontCache();
931     }
932     CFX_FaceCache* pFaceCache = pCache->GetCachedFace(pFont);
933     FX_FONTCACHE_DEFINE(pCache, pFont);
934     for (int iChar = 0; iChar < nChars; iChar ++) {
935         const FXTEXT_CHARPOS& charpos = pCharPos[iChar];
936         CFX_AffineMatrix matrix;
937         if (charpos.m_bGlyphAdjust)
938             matrix.Set(charpos.m_AdjustMatrix[0], charpos.m_AdjustMatrix[1],
939                        charpos.m_AdjustMatrix[2], charpos.m_AdjustMatrix[3], 0, 0);
940         matrix.Concat(font_size, 0, 0, font_size, charpos.m_OriginX, charpos.m_OriginY);
941         const CFX_PathData* pPath = pFaceCache->LoadGlyphPath(pFont, charpos.m_GlyphIndex, charpos.m_FontCharWidth);
942         if (pPath == NULL) {
943             continue;
944         }
945         matrix.Concat(*pText2User);
946         CFX_PathData TransformedPath(*pPath);
947         TransformedPath.Transform(&matrix);
948         FX_BOOL bHasAlpha = FXGETFLAG_COLORTYPE(alpha_flag) ?
949                             (FXGETFLAG_ALPHA_FILL(alpha_flag) || FXGETFLAG_ALPHA_STROKE(alpha_flag)) :
950                             (fill_color || stroke_color);
951         if (bHasAlpha) {
952             int fill_mode = nFlag;
953             if (FXGETFLAG_COLORTYPE(alpha_flag)) {
954                 if (FXGETFLAG_ALPHA_FILL(alpha_flag)) {
955                     fill_mode |= FXFILL_WINDING;
956                 }
957             } else {
958                 if (fill_color) {
959                     fill_mode |= FXFILL_WINDING;
960                 }
961             }
962             fill_mode |= FX_FILL_TEXT_MODE;
963             if (!DrawPath(&TransformedPath, pUser2Device, pGraphState, fill_color, stroke_color, fill_mode, alpha_flag, pIccTransform, blend_type)) {
964                 return FALSE;
965             }
966         }
967         if (pClippingPath) {
968             pClippingPath->Append(&TransformedPath, pUser2Device);
969         }
970     }
971     return TRUE;
972 }
973 CFX_FontCache::~CFX_FontCache()
974 {
975     FreeCache(TRUE);
976 }
977 CFX_FaceCache* CFX_FontCache::GetCachedFace(CFX_Font* pFont)
978 {
979     FX_BOOL bExternal = pFont->GetFace() == NULL;
980     void* face = bExternal ? pFont->GetSubstFont()->m_ExtHandle : pFont->GetFace();
981     CFX_FTCacheMap& map =  bExternal ? m_ExtFaceMap : m_FTFaceMap;
982     CFX_CountedFaceCache* counted_face_cache = NULL;
983     if (map.Lookup((FXFT_Face)face, counted_face_cache)) {
984         counted_face_cache->m_nCount++;
985         return counted_face_cache->m_Obj;
986     }
987     CFX_FaceCache* face_cache = NULL;
988     face_cache = FX_NEW CFX_FaceCache(bExternal ? NULL : (FXFT_Face)face);
989     if (face_cache == NULL)     {
990         return NULL;
991     }
992     counted_face_cache = FX_NEW CFX_CountedFaceCache;
993     if (!counted_face_cache) {
994         if (face_cache) {
995             delete face_cache;
996             face_cache = NULL;
997         }
998         return NULL;
999     }
1000     counted_face_cache->m_nCount = 2;
1001     counted_face_cache->m_Obj = face_cache;
1002     map.SetAt((FXFT_Face)face, counted_face_cache);
1003     return face_cache;
1004 }
1005 void CFX_FontCache::ReleaseCachedFace(CFX_Font* pFont)
1006 {
1007     FX_BOOL bExternal = pFont->GetFace() == NULL;
1008     void* face = bExternal ? pFont->GetSubstFont()->m_ExtHandle : pFont->GetFace();
1009     CFX_FTCacheMap& map =  bExternal ? m_ExtFaceMap : m_FTFaceMap;
1010     CFX_CountedFaceCache* counted_face_cache = NULL;
1011     if (!map.Lookup((FXFT_Face)face, counted_face_cache)) {
1012         return;
1013     }
1014     if (counted_face_cache->m_nCount > 1) {
1015         counted_face_cache->m_nCount--;
1016     }
1017 }
1018 void CFX_FontCache::FreeCache(FX_BOOL bRelease)
1019 {
1020     {
1021         FX_POSITION pos;
1022         pos = m_FTFaceMap.GetStartPosition();
1023         while (pos) {
1024             FXFT_Face face;
1025             CFX_CountedFaceCache* cache;
1026             m_FTFaceMap.GetNextAssoc(pos, face, cache);
1027             if (bRelease || cache->m_nCount < 2) {
1028                 delete cache->m_Obj;
1029                 delete cache;
1030                 m_FTFaceMap.RemoveKey(face);
1031             }
1032         }
1033         pos = m_ExtFaceMap.GetStartPosition();
1034         while (pos) {
1035             FXFT_Face face;
1036             CFX_CountedFaceCache* cache;
1037             m_ExtFaceMap.GetNextAssoc(pos, face, cache);
1038             if (bRelease || cache->m_nCount < 2) {
1039                 delete cache->m_Obj;
1040                 delete cache;
1041                 m_ExtFaceMap.RemoveKey(face);
1042             }
1043         }
1044     }
1045 }
1046 CFX_FaceCache::CFX_FaceCache(FXFT_Face face)
1047 {
1048     m_Face = face;
1049     m_pBitmap = NULL;
1050 }
1051 CFX_FaceCache::~CFX_FaceCache()
1052 {
1053     FX_POSITION pos = m_SizeMap.GetStartPosition();
1054     CFX_ByteString Key;
1055     CFX_SizeGlyphCache* pSizeCache = NULL;
1056     while(pos) {
1057         m_SizeMap.GetNextAssoc( pos, Key, (void*&)pSizeCache);
1058         delete pSizeCache;
1059     }
1060     m_SizeMap.RemoveAll();
1061     pos = m_PathMap.GetStartPosition();
1062     FX_LPVOID key1;
1063     CFX_PathData* pPath;
1064     while (pos) {
1065         m_PathMap.GetNextAssoc(pos, key1, (FX_LPVOID&)pPath);
1066         delete pPath;
1067     }
1068     if (m_pBitmap) {
1069         delete m_pBitmap;
1070     }
1071     m_PathMap.RemoveAll();
1072 }
1073 #if _FXM_PLATFORM_  != _FXM_PLATFORM_APPLE_
1074 void CFX_FaceCache::InitPlatform()
1075 {
1076 }
1077 #endif
1078 CFX_GlyphBitmap* CFX_FaceCache::LookUpGlyphBitmap(CFX_Font* pFont, const CFX_AffineMatrix* pMatrix,
1079         CFX_ByteStringC& FaceGlyphsKey, FX_DWORD glyph_index, FX_BOOL bFontStyle,
1080         int dest_width, int anti_alias)
1081 {
1082     CFX_SizeGlyphCache* pSizeCache = NULL;
1083     if (!m_SizeMap.Lookup(FaceGlyphsKey, (void*&)pSizeCache)) {
1084         pSizeCache = FX_NEW CFX_SizeGlyphCache;
1085         if (pSizeCache == NULL) {
1086             return NULL;
1087         }
1088         m_SizeMap.SetAt(FaceGlyphsKey, pSizeCache);
1089     }
1090     CFX_GlyphBitmap* pGlyphBitmap = NULL;
1091     if (pSizeCache->m_GlyphMap.Lookup((FX_LPVOID)(FX_UINTPTR)glyph_index, (void*&)pGlyphBitmap)) {
1092         return pGlyphBitmap;
1093     }
1094     pGlyphBitmap = RenderGlyph(pFont, glyph_index, bFontStyle, pMatrix, dest_width, anti_alias);
1095     if (pGlyphBitmap == NULL)   {
1096         return NULL;
1097     }
1098     pSizeCache->m_GlyphMap.SetAt((FX_LPVOID)(FX_UINTPTR)glyph_index, pGlyphBitmap);
1099     return pGlyphBitmap;
1100 }
1101 const CFX_GlyphBitmap* CFX_FaceCache::LoadGlyphBitmap(CFX_Font* pFont, FX_DWORD glyph_index, FX_BOOL bFontStyle, const CFX_AffineMatrix* pMatrix,
1102         int dest_width, int anti_alias, int& text_flags)
1103 {
1104     if (glyph_index == (FX_DWORD) - 1) {
1105         return NULL;
1106     }
1107     _CFX_UniqueKeyGen keygen;
1108 #if _FXM_PLATFORM_  != _FXM_PLATFORM_APPLE_
1109     if (pFont->GetSubstFont())
1110         keygen.Generate(9, (int)(pMatrix->a * 10000), (int)(pMatrix->b * 10000),
1111                         (int)(pMatrix->c * 10000), (int)(pMatrix->d * 10000), dest_width, anti_alias,
1112                         pFont->GetSubstFont()->m_Weight, pFont->GetSubstFont()->m_ItalicAngle, pFont->IsVertical());
1113     else
1114         keygen.Generate(6, (int)(pMatrix->a * 10000), (int)(pMatrix->b * 10000),
1115                         (int)(pMatrix->c * 10000), (int)(pMatrix->d * 10000), dest_width, anti_alias);
1116 #else
1117     if (text_flags & FXTEXT_NO_NATIVETEXT) {
1118         if (pFont->GetSubstFont())
1119             keygen.Generate(9, (int)(pMatrix->a * 10000), (int)(pMatrix->b * 10000),
1120                             (int)(pMatrix->c * 10000), (int)(pMatrix->d * 10000), dest_width, anti_alias,
1121                             pFont->GetSubstFont()->m_Weight, pFont->GetSubstFont()->m_ItalicAngle, pFont->IsVertical());
1122         else
1123             keygen.Generate(6, (int)(pMatrix->a * 10000), (int)(pMatrix->b * 10000),
1124                             (int)(pMatrix->c * 10000), (int)(pMatrix->d * 10000), dest_width, anti_alias);
1125     } else {
1126         if (pFont->GetSubstFont())
1127             keygen.Generate(10, (int)(pMatrix->a * 10000), (int)(pMatrix->b * 10000),
1128                             (int)(pMatrix->c * 10000), (int)(pMatrix->d * 10000), dest_width, anti_alias,
1129                             pFont->GetSubstFont()->m_Weight, pFont->GetSubstFont()->m_ItalicAngle, pFont->IsVertical(), 3);
1130         else
1131             keygen.Generate(7, (int)(pMatrix->a * 10000), (int)(pMatrix->b * 10000),
1132                             (int)(pMatrix->c * 10000), (int)(pMatrix->d * 10000), dest_width, anti_alias, 3);
1133     }
1134 #endif
1135     CFX_ByteStringC FaceGlyphsKey(keygen.m_Key, keygen.m_KeyLen);
1136 #if _FXM_PLATFORM_  != _FXM_PLATFORM_APPLE_
1137     return LookUpGlyphBitmap(pFont, pMatrix, FaceGlyphsKey, glyph_index, bFontStyle, dest_width, anti_alias);
1138 #else
1139     if (text_flags & FXTEXT_NO_NATIVETEXT) {
1140         return LookUpGlyphBitmap(pFont, pMatrix, FaceGlyphsKey, glyph_index, bFontStyle, dest_width, anti_alias);
1141     } else {
1142         CFX_GlyphBitmap* pGlyphBitmap;
1143         CFX_SizeGlyphCache* pSizeCache = NULL;
1144         if (m_SizeMap.Lookup(FaceGlyphsKey, (void*&)pSizeCache)) {
1145             if (pSizeCache->m_GlyphMap.Lookup((FX_LPVOID)(FX_UINTPTR)glyph_index, (void*&)pGlyphBitmap)) {
1146                 return pGlyphBitmap;
1147             }
1148             pGlyphBitmap = RenderGlyph_Nativetext(pFont, glyph_index, pMatrix, dest_width, anti_alias);
1149             if (pGlyphBitmap) {
1150                 pSizeCache->m_GlyphMap.SetAt((FX_LPVOID)(FX_UINTPTR)glyph_index, pGlyphBitmap);
1151                 return pGlyphBitmap;
1152             }
1153         } else {
1154             pGlyphBitmap = RenderGlyph_Nativetext(pFont, glyph_index, pMatrix, dest_width, anti_alias);
1155             if (pGlyphBitmap) {
1156                 pSizeCache = FX_NEW CFX_SizeGlyphCache;
1157                 if (pSizeCache == NULL) {
1158                     return NULL;
1159                 }
1160                 m_SizeMap.SetAt(FaceGlyphsKey, pSizeCache);
1161                 pSizeCache->m_GlyphMap.SetAt((FX_LPVOID)(FX_UINTPTR)glyph_index, pGlyphBitmap);
1162                 return pGlyphBitmap;
1163             }
1164         }
1165         if (pFont->GetSubstFont())
1166             keygen.Generate(9, (int)(pMatrix->a * 10000), (int)(pMatrix->b * 10000),
1167                             (int)(pMatrix->c * 10000), (int)(pMatrix->d * 10000), dest_width, anti_alias,
1168                             pFont->GetSubstFont()->m_Weight, pFont->GetSubstFont()->m_ItalicAngle, pFont->IsVertical());
1169         else
1170             keygen.Generate(6, (int)(pMatrix->a * 10000), (int)(pMatrix->b * 10000),
1171                             (int)(pMatrix->c * 10000), (int)(pMatrix->d * 10000), dest_width, anti_alias);
1172         CFX_ByteStringC FaceGlyphsKey(keygen.m_Key, keygen.m_KeyLen);
1173         text_flags |= FXTEXT_NO_NATIVETEXT;
1174         return LookUpGlyphBitmap(pFont, pMatrix, FaceGlyphsKey, glyph_index, bFontStyle, dest_width, anti_alias);
1175     }
1176 #endif
1177 }
1178 CFX_SizeGlyphCache::~CFX_SizeGlyphCache()
1179 {
1180     FX_POSITION pos = m_GlyphMap.GetStartPosition();
1181     FX_LPVOID Key;
1182     CFX_GlyphBitmap* pGlyphBitmap = NULL;
1183     while(pos) {
1184         m_GlyphMap.GetNextAssoc(pos, Key, (void*&)pGlyphBitmap);
1185         delete pGlyphBitmap;
1186     }
1187     m_GlyphMap.RemoveAll();
1188 }
1189 #define CONTRAST_RAMP_STEP      1
1190 void CFX_Font::AdjustMMParams(int glyph_index, int dest_width, int weight)
1191 {
1192     FXFT_MM_Var pMasters = NULL;
1193     FXFT_Get_MM_Var(m_Face, &pMasters);
1194     if (pMasters == NULL) {
1195         return;
1196     }
1197     long coords[2];
1198     if (weight == 0) {
1199         coords[0] = FXFT_Get_MM_Axis_Def(FXFT_Get_MM_Axis(pMasters, 0)) / 65536;
1200     } else {
1201         coords[0] = weight;
1202     }
1203     if (dest_width == 0) {
1204         coords[1] = FXFT_Get_MM_Axis_Def(FXFT_Get_MM_Axis(pMasters, 1)) / 65536;
1205     } else {
1206         int min_param = FXFT_Get_MM_Axis_Min(FXFT_Get_MM_Axis(pMasters, 1)) / 65536;
1207         int max_param = FXFT_Get_MM_Axis_Max(FXFT_Get_MM_Axis(pMasters, 1)) / 65536;
1208         coords[1] = min_param;
1209         int error = FXFT_Set_MM_Design_Coordinates(m_Face, 2, coords);
1210         error = FXFT_Load_Glyph(m_Face, glyph_index, FXFT_LOAD_NO_SCALE | FXFT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH);
1211         int min_width = FXFT_Get_Glyph_HoriAdvance(m_Face) * 1000 / FXFT_Get_Face_UnitsPerEM(m_Face);
1212         coords[1] = max_param;
1213         error = FXFT_Set_MM_Design_Coordinates(m_Face, 2, coords);
1214         error = FXFT_Load_Glyph(m_Face, glyph_index, FXFT_LOAD_NO_SCALE | FXFT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH);
1215         int max_width = FXFT_Get_Glyph_HoriAdvance(m_Face) * 1000 / FXFT_Get_Face_UnitsPerEM(m_Face);
1216         if (max_width == min_width) {
1217             return;
1218         }
1219         int param = min_param + (max_param - min_param) * (dest_width - min_width) / (max_width - min_width);
1220         coords[1] = param;
1221     }
1222     FXFT_Free(m_Face, pMasters);
1223     FXFT_Set_MM_Design_Coordinates(m_Face, 2, coords);
1224 }
1225 static const size_t ANGLESKEW_ARRAY_SIZE = 30;
1226 static const char g_AngleSkew[ANGLESKEW_ARRAY_SIZE] = {
1227     0, 2, 3, 5, 7, 9, 11, 12, 14, 16,
1228     18, 19, 21, 23, 25, 27, 29, 31, 32, 34,
1229     36, 38, 40, 42, 45, 47, 49, 51, 53, 55,
1230 };
1231 static const size_t WEIGHTPOW_ARRAY_SIZE = 100;
1232 static const FX_BYTE g_WeightPow[WEIGHTPOW_ARRAY_SIZE] = {
1233     0, 3, 6, 7, 8, 9, 11, 12, 14, 15, 16, 17, 18, 19, 20,
1234     21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 35, 36, 36,
1235     37, 37, 37, 38, 38, 38, 39, 39, 39, 40, 40, 40, 41, 41, 41, 42, 42, 42,
1236     42, 43, 43, 43, 44, 44, 44, 44, 45, 45, 45, 45, 46, 46, 46, 46, 47, 47,
1237     47, 47, 48, 48, 48, 48, 48, 49, 49, 49, 49, 50, 50, 50, 50, 50, 51, 51,
1238     51, 51, 51, 52, 52, 52, 52, 52, 53, 53, 53, 53, 53,
1239 };
1240 static const FX_BYTE g_WeightPow_11[WEIGHTPOW_ARRAY_SIZE] = {
1241     0, 4, 7, 8, 9, 10, 12, 13, 15, 17, 18, 19, 20, 21, 22,
1242     23, 24, 25, 26, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 39, 39, 40, 40,
1243     41, 41, 41, 42, 42, 42, 43, 43, 43, 44, 44, 44, 45, 45, 45, 46, 46, 46,
1244     46, 43, 47, 47, 48, 48, 48, 48, 45, 50, 50, 50, 46, 51, 51, 51, 52, 52,
1245     52, 52, 53, 53, 53, 53, 53, 54, 54, 54, 54, 55, 55, 55, 55, 55, 56, 56,
1246     56, 56, 56, 57, 57, 57, 57, 57, 58, 58, 58, 58, 58,
1247 };
1248 static const FX_BYTE g_WeightPow_SHIFTJIS[WEIGHTPOW_ARRAY_SIZE] = {
1249     0, 0, 1, 2, 3, 4, 5, 7, 8, 10, 11, 13, 14, 16, 17, 19, 21, 22, 24, 26, 28,
1250     30, 32, 33, 35, 37, 39, 41, 43, 45, 48, 48, 48, 48, 49, 49, 49, 50, 50, 50, 50,
1251     51, 51, 51, 51, 52, 52, 52, 52, 52, 53, 53, 53, 53, 53, 54, 54, 54, 54, 54, 55, 55,
1252     55, 55, 55, 56, 56, 56, 56, 56 , 56, 57, 57, 57 , 57 , 57, 57, 57, 58, 58, 58, 58, 58,
1253     58, 58, 59, 59, 59, 59, 59, 59, 59, 60, 60, 60, 60, 60, 60, 60, 60,
1254 };
1255 static void _GammaAdjust(FX_LPBYTE pData, int nWid, int nHei, int src_pitch, FX_LPCBYTE gammaTable)
1256 {
1257     int count = nHei * src_pitch;
1258     for(int i = 0; i < count; i++) {
1259         pData[i] = gammaTable[pData[i]];
1260     }
1261 }
1262 static void _ContrastAdjust(FX_LPBYTE pDataIn, FX_LPBYTE pDataOut, int nWid, int nHei, int nSrcRowBytes, int nDstRowBytes)
1263 {
1264     int col, row, temp;
1265     int max = 0, min = 255;
1266     FX_FLOAT rate;
1267     for (row = 0; row < nHei; row ++) {
1268         FX_LPBYTE pRow = pDataIn + row * nSrcRowBytes;
1269         for (col = 0; col < nWid; col++) {
1270             temp = *pRow ++;
1271             if (temp > max) {
1272                 max = temp;
1273             }
1274             if (temp < min) {
1275                 min = temp;
1276             }
1277         }
1278     }
1279     temp = max - min;
1280     if (0 == temp || 255 == temp) {
1281         int rowbytes = FXSYS_abs(nSrcRowBytes) > nDstRowBytes ? nDstRowBytes : FXSYS_abs(nSrcRowBytes);
1282         for (row = 0; row < nHei; row ++) {
1283             FXSYS_memcpy32(pDataOut + row * nDstRowBytes, pDataIn + row * nSrcRowBytes, rowbytes);
1284         }
1285         return;
1286     }
1287     rate = 255.f / temp;
1288     for (row = 0; row < nHei; row ++) {
1289         FX_LPBYTE pSrcRow = pDataIn + row * nSrcRowBytes;
1290         FX_LPBYTE pDstRow = pDataOut + row * nDstRowBytes;
1291         for (col = 0; col < nWid; col ++) {
1292             temp = (int)((*(pSrcRow++) - min) * rate + 0.5);
1293             if (temp > 255)     {
1294                 temp = 255;
1295             } else if (temp < 0) {
1296                 temp = 0;
1297             }
1298             *pDstRow ++ = (FX_BYTE)temp;
1299         }
1300     }
1301 }
1302 CFX_GlyphBitmap* CFX_FaceCache::RenderGlyph(CFX_Font* pFont, FX_DWORD glyph_index, FX_BOOL bFontStyle,
1303         const CFX_AffineMatrix* pMatrix, int dest_width, int anti_alias)
1304 {
1305     if (m_Face == NULL) {
1306         return NULL;
1307     }
1308     FXFT_Matrix  ft_matrix;
1309     ft_matrix.xx = (signed long)(pMatrix->GetA() / 64 * 65536);
1310     ft_matrix.xy = (signed long)(pMatrix->GetC() / 64 * 65536);
1311     ft_matrix.yx = (signed long)(pMatrix->GetB() / 64 * 65536);
1312     ft_matrix.yy = (signed long)(pMatrix->GetD() / 64 * 65536);
1313     FX_BOOL bUseCJKSubFont = FALSE;
1314     const CFX_SubstFont* pSubstFont = pFont->GetSubstFont();
1315     if (pSubstFont) {
1316         bUseCJKSubFont = pSubstFont->m_bSubstOfCJK && bFontStyle;
1317         int skew = 0;
1318         if (bUseCJKSubFont) {
1319             skew = pSubstFont->m_bItlicCJK ? -15 : 0;
1320         } else {
1321             skew = pSubstFont->m_ItalicAngle;
1322         }
1323         if (skew) {
1324             skew = skew <= -ANGLESKEW_ARRAY_SIZE ? -58 : -g_AngleSkew[-skew];
1325             if (pFont->IsVertical()) {
1326                 ft_matrix.yx += ft_matrix.yy * skew / 100;
1327             } else {
1328                 ft_matrix.xy += -ft_matrix.xx * skew / 100;
1329             }
1330         }
1331         if (pSubstFont->m_SubstFlags & FXFONT_SUBST_MM) {
1332             pFont->AdjustMMParams(glyph_index, dest_width, pFont->GetSubstFont()->m_Weight);
1333         }
1334     }
1335     FXFT_Set_Transform(m_Face, &ft_matrix, 0);
1336     int load_flags = (m_Face->face_flags & FT_FACE_FLAG_SFNT) ? FXFT_LOAD_NO_BITMAP : (FXFT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING);
1337     int error = FXFT_Load_Glyph(m_Face, glyph_index, load_flags);
1338     if (error) {
1339         //if an error is returned, try to reload glyphs without hinting.
1340         if (load_flags & FT_LOAD_NO_HINTING || load_flags & FT_LOAD_NO_SCALE) {
1341             return NULL;
1342         }
1343
1344         load_flags |= FT_LOAD_NO_HINTING;
1345         error = FXFT_Load_Glyph(m_Face, glyph_index, load_flags);
1346
1347         if (error) { 
1348             return NULL;
1349         }
1350     }
1351     int weight = 0;
1352     if (bUseCJKSubFont) {
1353         weight = pSubstFont->m_WeightCJK;
1354     } else {
1355         weight = pSubstFont ? pSubstFont->m_Weight : 0;
1356     }
1357     if (pSubstFont && !(pSubstFont->m_SubstFlags & FXFONT_SUBST_MM) && weight > 400) {
1358         int index = (weight - 400) / 10;
1359         if (index >= WEIGHTPOW_ARRAY_SIZE) {
1360             return NULL;
1361         }
1362         int level = 0;
1363         if (pSubstFont->m_Charset == FXFONT_SHIFTJIS_CHARSET) {
1364             level = g_WeightPow_SHIFTJIS[index] * 2 * (FXSYS_abs((int)(ft_matrix.xx)) + FXSYS_abs((int)(ft_matrix.xy))) / 36655;
1365         } else {
1366             level = g_WeightPow_11[index] * (FXSYS_abs((int)(ft_matrix.xx)) + FXSYS_abs((int)(ft_matrix.xy))) / 36655;
1367         }
1368         FXFT_Outline_Embolden(FXFT_Get_Glyph_Outline(m_Face), level);
1369     }
1370     FXFT_Library_SetLcdFilter(CFX_GEModule::Get()->GetFontMgr()->m_FTLibrary, FT_LCD_FILTER_DEFAULT);
1371     error = FXFT_Render_Glyph(m_Face, anti_alias);
1372     if (error) {
1373         return NULL;
1374     }
1375     int bmwidth = FXFT_Get_Bitmap_Width(FXFT_Get_Glyph_Bitmap(m_Face));
1376     int bmheight = FXFT_Get_Bitmap_Rows(FXFT_Get_Glyph_Bitmap(m_Face));
1377     if (bmwidth > 2048 || bmheight > 2048) {
1378         return NULL;
1379     }
1380     int dib_width = bmwidth;
1381     CFX_GlyphBitmap* pGlyphBitmap = FX_NEW CFX_GlyphBitmap;
1382     if (!pGlyphBitmap) {
1383         return NULL;
1384     }
1385     pGlyphBitmap->m_Bitmap.Create(dib_width, bmheight,
1386                                   anti_alias == FXFT_RENDER_MODE_MONO ? FXDIB_1bppMask : FXDIB_8bppMask);
1387     pGlyphBitmap->m_Left = FXFT_Get_Glyph_BitmapLeft(m_Face);
1388     pGlyphBitmap->m_Top = FXFT_Get_Glyph_BitmapTop(m_Face);
1389     int dest_pitch = pGlyphBitmap->m_Bitmap.GetPitch();
1390     int src_pitch = FXFT_Get_Bitmap_Pitch(FXFT_Get_Glyph_Bitmap(m_Face));
1391     FX_BYTE* pDestBuf = pGlyphBitmap->m_Bitmap.GetBuffer();
1392     FX_BYTE* pSrcBuf = (FX_BYTE*)FXFT_Get_Bitmap_Buffer(FXFT_Get_Glyph_Bitmap(m_Face));
1393     if (anti_alias != FXFT_RENDER_MODE_MONO && FXFT_Get_Bitmap_PixelMode(FXFT_Get_Glyph_Bitmap(m_Face)) == FXFT_PIXEL_MODE_MONO) {
1394         int bytes = anti_alias == FXFT_RENDER_MODE_LCD ? 3 : 1;
1395         for(int i = 0; i < bmheight; i++)
1396             for(int n = 0; n < bmwidth; n++) {
1397                 FX_BYTE data = (pSrcBuf[i * src_pitch + n / 8] & (0x80 >> (n % 8))) ? 255 : 0;
1398                 for (int b = 0; b < bytes; b ++) {
1399                     pDestBuf[i * dest_pitch + n * bytes + b] = data;
1400                 }
1401             }
1402     } else {
1403         FXSYS_memset32(pDestBuf, 0, dest_pitch * bmheight);
1404         if (anti_alias == FXFT_RENDER_MODE_MONO && FXFT_Get_Bitmap_PixelMode(FXFT_Get_Glyph_Bitmap(m_Face)) == FXFT_PIXEL_MODE_MONO) {
1405             int rowbytes = FXSYS_abs(src_pitch) > dest_pitch ? dest_pitch : FXSYS_abs(src_pitch);
1406             for (int row = 0; row < bmheight; row ++) {
1407                 FXSYS_memcpy32(pDestBuf + row * dest_pitch, pSrcBuf + row * src_pitch, rowbytes);
1408             }
1409         } else {
1410             _ContrastAdjust(pSrcBuf, pDestBuf, bmwidth, bmheight, src_pitch, dest_pitch);
1411             _GammaAdjust(pDestBuf, bmwidth, bmheight, dest_pitch, CFX_GEModule::Get()->GetTextGammaTable());
1412         }
1413     }
1414     return pGlyphBitmap;
1415 }
1416 FX_BOOL _OutputGlyph(void* dib, int x, int y, CFX_Font* pFont,
1417                      int glyph_index, FX_ARGB argb)
1418 {
1419     CFX_DIBitmap* pDib = (CFX_DIBitmap*)dib;
1420     FXFT_Face face = pFont->GetFace();
1421     int error = FXFT_Load_Glyph(face, glyph_index, FXFT_LOAD_NO_BITMAP);
1422     if (error) {
1423         return FALSE;
1424     }
1425     error = FXFT_Render_Glyph(face, FXFT_RENDER_MODE_NORMAL);
1426     if (error) {
1427         return FALSE;
1428     }
1429     int bmwidth = FXFT_Get_Bitmap_Width(FXFT_Get_Glyph_Bitmap(face));
1430     int bmheight = FXFT_Get_Bitmap_Rows(FXFT_Get_Glyph_Bitmap(face));
1431     int left = FXFT_Get_Glyph_BitmapLeft(face);
1432     int top = FXFT_Get_Glyph_BitmapTop(face);
1433     FX_LPCBYTE src_buf = (FX_LPCBYTE)FXFT_Get_Bitmap_Buffer(FXFT_Get_Glyph_Bitmap(face));
1434     int src_pitch = FXFT_Get_Bitmap_Pitch(FXFT_Get_Glyph_Bitmap(face));
1435     CFX_DIBitmap mask;
1436     mask.Create(bmwidth, bmheight, FXDIB_8bppMask);
1437     FX_LPBYTE dest_buf = mask.GetBuffer();
1438     int dest_pitch = mask.GetPitch();
1439     for (int row = 0; row < bmheight; row ++) {
1440         FX_LPCBYTE src_scan = src_buf + row * src_pitch;
1441         FX_LPBYTE dest_scan = dest_buf + row * dest_pitch;
1442         FXSYS_memcpy32(dest_scan, src_scan, dest_pitch);
1443     }
1444     pDib->CompositeMask(x + left, y - top, bmwidth, bmheight, &mask, argb, 0, 0);
1445     return TRUE;
1446 }
1447 FX_BOOL OutputText(void* dib, int x, int y, CFX_Font* pFont, double font_size,
1448                    CFX_AffineMatrix* pText_matrix, unsigned short const* text, unsigned long argb)
1449 {
1450     if (!pFont) {
1451         return FALSE;
1452     }
1453     FXFT_Face face = pFont->GetFace();
1454     FXFT_Select_Charmap(pFont->m_Face, FXFT_ENCODING_UNICODE);
1455     if (pText_matrix) {
1456         FXFT_Matrix  ft_matrix;
1457         ft_matrix.xx = (signed long)(pText_matrix->a / 64 * 65536);
1458         ft_matrix.xy = (signed long)(pText_matrix->c / 64 * 65536);
1459         ft_matrix.yx = (signed long)(pText_matrix->b / 64 * 65536);
1460         ft_matrix.yy = (signed long)(pText_matrix->d / 64 * 65536);
1461         FXFT_Set_Transform(face, &ft_matrix, 0);
1462     }
1463     FX_FLOAT x_pos = 0;
1464     for (; *text != 0; text ++) {
1465         FX_WCHAR unicode = *text;
1466         int glyph_index = FXFT_Get_Char_Index(pFont->m_Face, unicode);
1467         if (glyph_index <= 0) {
1468             continue;
1469         }
1470         int err = FXFT_Load_Glyph(pFont->m_Face, glyph_index, FXFT_LOAD_NO_SCALE | FXFT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH);
1471         if (err) {
1472             continue;
1473         }
1474         int w = FXFT_Get_Glyph_HoriAdvance(pFont->m_Face);
1475         int em = FXFT_Get_Face_UnitsPerEM(pFont->m_Face);
1476         FX_FLOAT x1, y1;
1477         pText_matrix->Transform(x_pos, 0, x1, y1);
1478         _OutputGlyph(dib, (int)x1 + x, (int) - y1 + y, pFont,
1479                      glyph_index, argb);
1480         x_pos += (FX_FLOAT)w / em;
1481     }
1482     return TRUE;
1483 }
1484 FX_BOOL OutputGlyph(void* dib, int x, int y, CFX_Font* pFont, double font_size,
1485                     CFX_AffineMatrix* pMatrix, unsigned long glyph_index, unsigned long argb)
1486 {
1487     FXFT_Matrix  ft_matrix;
1488     if (pMatrix) {
1489         ft_matrix.xx = (signed long)(pMatrix->a * font_size / 64 * 65536);
1490         ft_matrix.xy = (signed long)(pMatrix->c * font_size / 64 * 65536);
1491         ft_matrix.yx = (signed long)(pMatrix->b * font_size / 64 * 65536);
1492         ft_matrix.yy = (signed long)(pMatrix->d * font_size / 64 * 65536);
1493     } else {
1494         ft_matrix.xx = (signed long)(font_size / 64 * 65536);
1495         ft_matrix.xy = ft_matrix.yx = 0;
1496         ft_matrix.yy = (signed long)(font_size / 64 * 65536);
1497     }
1498     FXFT_Set_Transform(pFont->m_Face, &ft_matrix, 0);
1499     FX_BOOL ret = _OutputGlyph(dib, x, y, pFont,
1500                                glyph_index, argb);
1501     return ret;
1502 }
1503 const CFX_PathData* CFX_FaceCache::LoadGlyphPath(CFX_Font* pFont, FX_DWORD glyph_index, int dest_width)
1504 {
1505     if (m_Face == NULL || glyph_index == (FX_DWORD) - 1) {
1506         return NULL;
1507     }
1508     CFX_PathData* pGlyphPath = NULL;
1509     FX_LPVOID key;
1510     if (pFont->GetSubstFont())
1511         key = (FX_LPVOID)(FX_UINTPTR)(glyph_index + ((pFont->GetSubstFont()->m_Weight / 16) << 15) +
1512                                       ((pFont->GetSubstFont()->m_ItalicAngle / 2) << 21) + ((dest_width / 16) << 25) +
1513                                       (pFont->IsVertical() << 31));
1514     else {
1515         key = (FX_LPVOID)(FX_UINTPTR)glyph_index;
1516     }
1517     if (m_PathMap.Lookup(key, (FX_LPVOID&)pGlyphPath)) {
1518         return pGlyphPath;
1519     }
1520     pGlyphPath = pFont->LoadGlyphPath(glyph_index, dest_width);
1521     m_PathMap.SetAt(key, pGlyphPath);
1522     return pGlyphPath;
1523 }
1524 typedef struct {
1525     FX_BOOL                     m_bCount;
1526     int                         m_PointCount;
1527     FX_PATHPOINT*       m_pPoints;
1528     int                         m_CurX;
1529     int                         m_CurY;
1530     FX_FLOAT            m_CoordUnit;
1531 } OUTLINE_PARAMS;
1532 void _Outline_CheckEmptyContour(OUTLINE_PARAMS* param)
1533 {
1534     if (param->m_PointCount >= 2 && param->m_pPoints[param->m_PointCount - 2].m_Flag == FXPT_MOVETO &&
1535             param->m_pPoints[param->m_PointCount - 2].m_PointX == param->m_pPoints[param->m_PointCount - 1].m_PointX &&
1536             param->m_pPoints[param->m_PointCount - 2].m_PointY == param->m_pPoints[param->m_PointCount - 1].m_PointY) {
1537         param->m_PointCount -= 2;
1538     }
1539     if (param->m_PointCount >= 4 && param->m_pPoints[param->m_PointCount - 4].m_Flag == FXPT_MOVETO &&
1540             param->m_pPoints[param->m_PointCount - 3].m_Flag == FXPT_BEZIERTO &&
1541             param->m_pPoints[param->m_PointCount - 3].m_PointX == param->m_pPoints[param->m_PointCount - 4].m_PointX &&
1542             param->m_pPoints[param->m_PointCount - 3].m_PointY == param->m_pPoints[param->m_PointCount - 4].m_PointY &&
1543             param->m_pPoints[param->m_PointCount - 2].m_PointX == param->m_pPoints[param->m_PointCount - 4].m_PointX &&
1544             param->m_pPoints[param->m_PointCount - 2].m_PointY == param->m_pPoints[param->m_PointCount - 4].m_PointY &&
1545             param->m_pPoints[param->m_PointCount - 1].m_PointX == param->m_pPoints[param->m_PointCount - 4].m_PointX &&
1546             param->m_pPoints[param->m_PointCount - 1].m_PointY == param->m_pPoints[param->m_PointCount - 4].m_PointY) {
1547         param->m_PointCount -= 4;
1548     }
1549 }
1550 extern "C" {
1551     static int _Outline_MoveTo(const FXFT_Vector* to, void* user)
1552     {
1553         OUTLINE_PARAMS* param = (OUTLINE_PARAMS*)user;
1554         if (!param->m_bCount) {
1555             _Outline_CheckEmptyContour(param);
1556             param->m_pPoints[param->m_PointCount].m_PointX = to->x / param->m_CoordUnit;
1557             param->m_pPoints[param->m_PointCount].m_PointY = to->y / param->m_CoordUnit;
1558             param->m_pPoints[param->m_PointCount].m_Flag = FXPT_MOVETO;
1559             param->m_CurX = to->x;
1560             param->m_CurY = to->y;
1561             if (param->m_PointCount) {
1562                 param->m_pPoints[param->m_PointCount - 1].m_Flag |= FXPT_CLOSEFIGURE;
1563             }
1564         }
1565         param->m_PointCount ++;
1566         return 0;
1567     }
1568 };
1569 extern "C" {
1570     static int _Outline_LineTo(const FXFT_Vector* to, void* user)
1571     {
1572         OUTLINE_PARAMS* param = (OUTLINE_PARAMS*)user;
1573         if (!param->m_bCount) {
1574             param->m_pPoints[param->m_PointCount].m_PointX = to->x / param->m_CoordUnit;
1575             param->m_pPoints[param->m_PointCount].m_PointY = to->y / param->m_CoordUnit;
1576             param->m_pPoints[param->m_PointCount].m_Flag = FXPT_LINETO;
1577             param->m_CurX = to->x;
1578             param->m_CurY = to->y;
1579         }
1580         param->m_PointCount ++;
1581         return 0;
1582     }
1583 };
1584 extern "C" {
1585     static int _Outline_ConicTo(const FXFT_Vector* control, const FXFT_Vector* to, void* user)
1586     {
1587         OUTLINE_PARAMS* param = (OUTLINE_PARAMS*)user;
1588         if (!param->m_bCount) {
1589             param->m_pPoints[param->m_PointCount].m_PointX = (param->m_CurX + (control->x - param->m_CurX) * 2 / 3) / param->m_CoordUnit;
1590             param->m_pPoints[param->m_PointCount].m_PointY = (param->m_CurY + (control->y - param->m_CurY) * 2 / 3) / param->m_CoordUnit;
1591             param->m_pPoints[param->m_PointCount].m_Flag = FXPT_BEZIERTO;
1592             param->m_pPoints[param->m_PointCount + 1].m_PointX = (control->x + (to->x - control->x) / 3) / param->m_CoordUnit;
1593             param->m_pPoints[param->m_PointCount + 1].m_PointY = (control->y + (to->y - control->y) / 3) / param->m_CoordUnit;
1594             param->m_pPoints[param->m_PointCount + 1].m_Flag = FXPT_BEZIERTO;
1595             param->m_pPoints[param->m_PointCount + 2].m_PointX = to->x / param->m_CoordUnit;
1596             param->m_pPoints[param->m_PointCount + 2].m_PointY = to->y / param->m_CoordUnit;
1597             param->m_pPoints[param->m_PointCount + 2].m_Flag = FXPT_BEZIERTO;
1598             param->m_CurX = to->x;
1599             param->m_CurY = to->y;
1600         }
1601         param->m_PointCount += 3;
1602         return 0;
1603     }
1604 };
1605 extern "C" {
1606     static int _Outline_CubicTo(const FXFT_Vector* control1, const FXFT_Vector* control2, const FXFT_Vector* to, void* user)
1607     {
1608         OUTLINE_PARAMS* param = (OUTLINE_PARAMS*)user;
1609         if (!param->m_bCount) {
1610             param->m_pPoints[param->m_PointCount].m_PointX = control1->x / param->m_CoordUnit;
1611             param->m_pPoints[param->m_PointCount].m_PointY = control1->y / param->m_CoordUnit;
1612             param->m_pPoints[param->m_PointCount].m_Flag = FXPT_BEZIERTO;
1613             param->m_pPoints[param->m_PointCount + 1].m_PointX = control2->x / param->m_CoordUnit;
1614             param->m_pPoints[param->m_PointCount + 1].m_PointY = control2->y / param->m_CoordUnit;
1615             param->m_pPoints[param->m_PointCount + 1].m_Flag = FXPT_BEZIERTO;
1616             param->m_pPoints[param->m_PointCount + 2].m_PointX = to->x / param->m_CoordUnit;
1617             param->m_pPoints[param->m_PointCount + 2].m_PointY = to->y / param->m_CoordUnit;
1618             param->m_pPoints[param->m_PointCount + 2].m_Flag = FXPT_BEZIERTO;
1619             param->m_CurX = to->x;
1620             param->m_CurY = to->y;
1621         }
1622         param->m_PointCount += 3;
1623         return 0;
1624     }
1625 };
1626 CFX_PathData* CFX_Font::LoadGlyphPath(FX_DWORD glyph_index, int dest_width)
1627 {
1628     if (m_Face == NULL) {
1629         return NULL;
1630     }
1631     FXFT_Set_Pixel_Sizes(m_Face, 0, 64);
1632     FXFT_Matrix  ft_matrix = {65536, 0, 0, 65536};
1633     if (m_pSubstFont) {
1634         if (m_pSubstFont->m_ItalicAngle) {
1635             int skew = m_pSubstFont->m_ItalicAngle;
1636             skew = skew <= -ANGLESKEW_ARRAY_SIZE ? -58 : -g_AngleSkew[-skew];
1637             if (m_bVertical) {
1638                 ft_matrix.yx += ft_matrix.yy * skew / 100;
1639             } else {
1640                 ft_matrix.xy += -ft_matrix.xx * skew / 100;
1641             }
1642         }
1643         if (m_pSubstFont->m_SubstFlags & FXFONT_SUBST_MM) {
1644             AdjustMMParams(glyph_index, dest_width, m_pSubstFont->m_Weight);
1645         }
1646     }
1647     FXFT_Set_Transform(m_Face, &ft_matrix, 0);
1648     int load_flags = (m_Face->face_flags & FT_FACE_FLAG_SFNT) ? FXFT_LOAD_NO_BITMAP : FXFT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING;
1649     int error = FXFT_Load_Glyph(m_Face, glyph_index, load_flags);
1650     if (error) {
1651         return NULL;
1652     }
1653     if (m_pSubstFont && !(m_pSubstFont->m_SubstFlags & FXFONT_SUBST_MM) && m_pSubstFont->m_Weight > 400) {
1654         int index = (m_pSubstFont->m_Weight - 400) / 10;
1655         if (index >= WEIGHTPOW_ARRAY_SIZE)
1656             index = WEIGHTPOW_ARRAY_SIZE - 1;
1657         int level = 0;
1658         if (m_pSubstFont->m_Charset == FXFONT_SHIFTJIS_CHARSET) {
1659             level = g_WeightPow_SHIFTJIS[index] * 2 * 65536 / 36655;
1660         } else {
1661             level = g_WeightPow[index] * 2;
1662         }
1663         FXFT_Outline_Embolden(FXFT_Get_Glyph_Outline(m_Face), level);
1664     }
1665     FXFT_Outline_Funcs funcs;
1666     funcs.move_to = _Outline_MoveTo;
1667     funcs.line_to = _Outline_LineTo;
1668     funcs.conic_to = _Outline_ConicTo;
1669     funcs.cubic_to = _Outline_CubicTo;
1670     funcs.shift = 0;
1671     funcs.delta = 0;
1672     OUTLINE_PARAMS params;
1673     params.m_bCount = TRUE;
1674     params.m_PointCount = 0;
1675     FXFT_Outline_Decompose(FXFT_Get_Glyph_Outline(m_Face), &funcs, &params);
1676     if (params.m_PointCount == 0) {
1677         return NULL;
1678     }
1679     CFX_PathData* pPath = FX_NEW CFX_PathData;
1680     if (!pPath) {
1681         return NULL;
1682     }
1683     pPath->SetPointCount(params.m_PointCount);
1684     params.m_bCount = FALSE;
1685     params.m_PointCount = 0;
1686     params.m_pPoints = pPath->GetPoints();
1687     params.m_CurX = params.m_CurY = 0;
1688     params.m_CoordUnit = 64 * 64.0;
1689     FXFT_Outline_Decompose(FXFT_Get_Glyph_Outline(m_Face), &funcs, &params);
1690     _Outline_CheckEmptyContour(&params);
1691     pPath->TrimPoints(params.m_PointCount);
1692     if (params.m_PointCount) {
1693         pPath->GetPoints()[params.m_PointCount - 1].m_Flag |= FXPT_CLOSEFIGURE;
1694     }
1695     return pPath;
1696 }
1697 void _CFX_UniqueKeyGen::Generate(int count, ...)
1698 {
1699     va_list argList;
1700     va_start(argList, count);
1701     for (int i = 0; i < count; i ++) {
1702         int p = va_arg(argList, int);
1703         ((FX_DWORD*)m_Key)[i] = p;
1704     }
1705     va_end(argList);
1706     m_KeyLen = count * sizeof(FX_DWORD);
1707 }