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