Revert "Fix else-after-returns throughout pdfium."
[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
1006 CFX_FaceCache* CFX_FontCache::GetCachedFace(CFX_Font* pFont)
1007 {
1008     FXFT_Face internal_face = pFont->GetFace();
1009     const FX_BOOL bExternal = internal_face == nullptr;
1010     FXFT_Face face = bExternal ?
1011         (FXFT_Face)pFont->GetSubstFont()->m_ExtHandle : internal_face;
1012     CFX_FTCacheMap& map = bExternal ? m_ExtFaceMap : m_FTFaceMap;
1013     auto it = map.find(face);
1014     if (it != map.end()) {
1015         CFX_CountedFaceCache* counted_face_cache = it->second;
1016         counted_face_cache->m_nCount++;
1017         return counted_face_cache->m_Obj;
1018     }
1019
1020     CFX_FaceCache* face_cache = new CFX_FaceCache(bExternal ? nullptr : face);
1021     CFX_CountedFaceCache* counted_face_cache = new CFX_CountedFaceCache;
1022     counted_face_cache->m_nCount = 2;
1023     counted_face_cache->m_Obj = face_cache;
1024     map[face] = counted_face_cache;
1025     return face_cache;
1026 }
1027
1028 void CFX_FontCache::ReleaseCachedFace(CFX_Font* pFont)
1029 {
1030     FXFT_Face internal_face = pFont->GetFace();
1031     const FX_BOOL bExternal = internal_face == nullptr;
1032     FXFT_Face face = bExternal ?
1033         (FXFT_Face)pFont->GetSubstFont()->m_ExtHandle : internal_face;
1034     CFX_FTCacheMap& map =  bExternal ? m_ExtFaceMap : m_FTFaceMap;
1035
1036     auto it = map.find(face);
1037     if (it == map.end())
1038         return;
1039
1040     CFX_CountedFaceCache* counted_face_cache = it->second;
1041     if (counted_face_cache->m_nCount > 1) {
1042         counted_face_cache->m_nCount--;
1043     }
1044 }
1045
1046 void CFX_FontCache::FreeCache(FX_BOOL bRelease)
1047 {
1048     for (auto it = m_FTFaceMap.begin(); it != m_FTFaceMap.end();) {
1049         auto curr_it = it++;
1050         CFX_CountedFaceCache* cache = curr_it->second;
1051         if (bRelease || cache->m_nCount < 2) {
1052             delete cache->m_Obj;
1053             delete cache;
1054             m_FTFaceMap.erase(curr_it);
1055         }
1056     }
1057
1058     for (auto it = m_ExtFaceMap.begin(); it != m_ExtFaceMap.end();) {
1059         auto curr_it = it++;
1060         CFX_CountedFaceCache* cache = curr_it->second;
1061         if (bRelease || cache->m_nCount < 2) {
1062             delete cache->m_Obj;
1063             delete cache;
1064             m_ExtFaceMap.erase(curr_it);
1065         }
1066     }
1067 }
1068
1069 CFX_FaceCache::CFX_FaceCache(FXFT_Face face)
1070 {
1071     m_Face = face;
1072 }
1073 CFX_FaceCache::~CFX_FaceCache()
1074 {
1075     FX_POSITION pos = m_SizeMap.GetStartPosition();
1076     CFX_ByteString Key;
1077     CFX_SizeGlyphCache* pSizeCache = NULL;
1078     while(pos) {
1079         m_SizeMap.GetNextAssoc( pos, Key, (void*&)pSizeCache);
1080         delete pSizeCache;
1081     }
1082     m_SizeMap.RemoveAll();
1083     pos = m_PathMap.GetStartPosition();
1084     void* key1;
1085     CFX_PathData* pPath;
1086     while (pos) {
1087         m_PathMap.GetNextAssoc(pos, key1, (void*&)pPath);
1088         delete pPath;
1089     }
1090     m_PathMap.RemoveAll();
1091 }
1092 #if _FXM_PLATFORM_  != _FXM_PLATFORM_APPLE_
1093 void CFX_FaceCache::InitPlatform()
1094 {
1095 }
1096 #endif
1097 CFX_GlyphBitmap* CFX_FaceCache::LookUpGlyphBitmap(CFX_Font* pFont, const CFX_AffineMatrix* pMatrix,
1098         CFX_ByteStringC& FaceGlyphsKey, FX_DWORD glyph_index, FX_BOOL bFontStyle,
1099         int dest_width, int anti_alias)
1100 {
1101     CFX_SizeGlyphCache* pSizeCache = NULL;
1102     if (!m_SizeMap.Lookup(FaceGlyphsKey, (void*&)pSizeCache)) {
1103         pSizeCache = new CFX_SizeGlyphCache;
1104         m_SizeMap.SetAt(FaceGlyphsKey, pSizeCache);
1105     }
1106     CFX_GlyphBitmap* pGlyphBitmap = NULL;
1107     if (pSizeCache->m_GlyphMap.Lookup((void*)(uintptr_t)glyph_index, (void*&)pGlyphBitmap)) {
1108         return pGlyphBitmap;
1109     }
1110     pGlyphBitmap = RenderGlyph(pFont, glyph_index, bFontStyle, pMatrix, dest_width, anti_alias);
1111     if (pGlyphBitmap == NULL)   {
1112         return NULL;
1113     }
1114     pSizeCache->m_GlyphMap.SetAt((void*)(uintptr_t)glyph_index, pGlyphBitmap);
1115     return pGlyphBitmap;
1116 }
1117 const CFX_GlyphBitmap* CFX_FaceCache::LoadGlyphBitmap(CFX_Font* pFont, FX_DWORD glyph_index, FX_BOOL bFontStyle, const CFX_AffineMatrix* pMatrix,
1118         int dest_width, int anti_alias, int& text_flags)
1119 {
1120     if (glyph_index == (FX_DWORD) - 1) {
1121         return NULL;
1122     }
1123     _CFX_UniqueKeyGen keygen;
1124 #if _FXM_PLATFORM_  != _FXM_PLATFORM_APPLE_
1125     if (pFont->GetSubstFont())
1126         keygen.Generate(9, (int)(pMatrix->a * 10000), (int)(pMatrix->b * 10000),
1127                         (int)(pMatrix->c * 10000), (int)(pMatrix->d * 10000), dest_width, anti_alias,
1128                         pFont->GetSubstFont()->m_Weight, pFont->GetSubstFont()->m_ItalicAngle, pFont->IsVertical());
1129     else
1130         keygen.Generate(6, (int)(pMatrix->a * 10000), (int)(pMatrix->b * 10000),
1131                         (int)(pMatrix->c * 10000), (int)(pMatrix->d * 10000), dest_width, anti_alias);
1132 #else
1133     if (text_flags & FXTEXT_NO_NATIVETEXT) {
1134         if (pFont->GetSubstFont())
1135             keygen.Generate(9, (int)(pMatrix->a * 10000), (int)(pMatrix->b * 10000),
1136                             (int)(pMatrix->c * 10000), (int)(pMatrix->d * 10000), dest_width, anti_alias,
1137                             pFont->GetSubstFont()->m_Weight, pFont->GetSubstFont()->m_ItalicAngle, pFont->IsVertical());
1138         else
1139             keygen.Generate(6, (int)(pMatrix->a * 10000), (int)(pMatrix->b * 10000),
1140                             (int)(pMatrix->c * 10000), (int)(pMatrix->d * 10000), dest_width, anti_alias);
1141     } else {
1142         if (pFont->GetSubstFont())
1143             keygen.Generate(10, (int)(pMatrix->a * 10000), (int)(pMatrix->b * 10000),
1144                             (int)(pMatrix->c * 10000), (int)(pMatrix->d * 10000), dest_width, anti_alias,
1145                             pFont->GetSubstFont()->m_Weight, pFont->GetSubstFont()->m_ItalicAngle, pFont->IsVertical(), 3);
1146         else
1147             keygen.Generate(7, (int)(pMatrix->a * 10000), (int)(pMatrix->b * 10000),
1148                             (int)(pMatrix->c * 10000), (int)(pMatrix->d * 10000), dest_width, anti_alias, 3);
1149     }
1150 #endif
1151     CFX_ByteStringC FaceGlyphsKey(keygen.m_Key, keygen.m_KeyLen);
1152 #if _FXM_PLATFORM_  != _FXM_PLATFORM_APPLE_
1153     return LookUpGlyphBitmap(pFont, pMatrix, FaceGlyphsKey, glyph_index, bFontStyle, dest_width, anti_alias);
1154 #else
1155     if (text_flags & FXTEXT_NO_NATIVETEXT) {
1156         return LookUpGlyphBitmap(pFont, pMatrix, FaceGlyphsKey, glyph_index, bFontStyle, dest_width, anti_alias);
1157     } else {
1158         CFX_GlyphBitmap* pGlyphBitmap;
1159         CFX_SizeGlyphCache* pSizeCache = NULL;
1160         if (m_SizeMap.Lookup(FaceGlyphsKey, (void*&)pSizeCache)) {
1161             if (pSizeCache->m_GlyphMap.Lookup((void*)(uintptr_t)glyph_index, (void*&)pGlyphBitmap)) {
1162                 return pGlyphBitmap;
1163             }
1164             pGlyphBitmap = RenderGlyph_Nativetext(pFont, glyph_index, pMatrix, dest_width, anti_alias);
1165             if (pGlyphBitmap) {
1166                 pSizeCache->m_GlyphMap.SetAt((void*)(uintptr_t)glyph_index, pGlyphBitmap);
1167                 return pGlyphBitmap;
1168             }
1169         } else {
1170             pGlyphBitmap = RenderGlyph_Nativetext(pFont, glyph_index, pMatrix, dest_width, anti_alias);
1171             if (pGlyphBitmap) {
1172                 pSizeCache = new CFX_SizeGlyphCache;
1173                 m_SizeMap.SetAt(FaceGlyphsKey, pSizeCache);
1174                 pSizeCache->m_GlyphMap.SetAt((void*)(uintptr_t)glyph_index, pGlyphBitmap);
1175                 return pGlyphBitmap;
1176             }
1177         }
1178         if (pFont->GetSubstFont())
1179             keygen.Generate(9, (int)(pMatrix->a * 10000), (int)(pMatrix->b * 10000),
1180                             (int)(pMatrix->c * 10000), (int)(pMatrix->d * 10000), dest_width, anti_alias,
1181                             pFont->GetSubstFont()->m_Weight, pFont->GetSubstFont()->m_ItalicAngle, pFont->IsVertical());
1182         else
1183             keygen.Generate(6, (int)(pMatrix->a * 10000), (int)(pMatrix->b * 10000),
1184                             (int)(pMatrix->c * 10000), (int)(pMatrix->d * 10000), dest_width, anti_alias);
1185         CFX_ByteStringC FaceGlyphsKey(keygen.m_Key, keygen.m_KeyLen);
1186         text_flags |= FXTEXT_NO_NATIVETEXT;
1187         return LookUpGlyphBitmap(pFont, pMatrix, FaceGlyphsKey, glyph_index, bFontStyle, dest_width, anti_alias);
1188     }
1189 #endif
1190 }
1191 CFX_SizeGlyphCache::~CFX_SizeGlyphCache()
1192 {
1193     FX_POSITION pos = m_GlyphMap.GetStartPosition();
1194     void* Key;
1195     CFX_GlyphBitmap* pGlyphBitmap = NULL;
1196     while(pos) {
1197         m_GlyphMap.GetNextAssoc(pos, Key, (void*&)pGlyphBitmap);
1198         delete pGlyphBitmap;
1199     }
1200     m_GlyphMap.RemoveAll();
1201 }
1202 #define CONTRAST_RAMP_STEP      1
1203 void CFX_Font::AdjustMMParams(int glyph_index, int dest_width, int weight)
1204 {
1205     FXFT_MM_Var pMasters = NULL;
1206     FXFT_Get_MM_Var(m_Face, &pMasters);
1207     if (pMasters == NULL) {
1208         return;
1209     }
1210     long coords[2];
1211     if (weight == 0) {
1212         coords[0] = FXFT_Get_MM_Axis_Def(FXFT_Get_MM_Axis(pMasters, 0)) / 65536;
1213     } else {
1214         coords[0] = weight;
1215     }
1216     if (dest_width == 0) {
1217         coords[1] = FXFT_Get_MM_Axis_Def(FXFT_Get_MM_Axis(pMasters, 1)) / 65536;
1218     } else {
1219         int min_param = FXFT_Get_MM_Axis_Min(FXFT_Get_MM_Axis(pMasters, 1)) / 65536;
1220         int max_param = FXFT_Get_MM_Axis_Max(FXFT_Get_MM_Axis(pMasters, 1)) / 65536;
1221         coords[1] = min_param;
1222         int 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 min_width = FXFT_Get_Glyph_HoriAdvance(m_Face) * 1000 / FXFT_Get_Face_UnitsPerEM(m_Face);
1225         coords[1] = max_param;
1226         error = FXFT_Set_MM_Design_Coordinates(m_Face, 2, coords);
1227         error = FXFT_Load_Glyph(m_Face, glyph_index, FXFT_LOAD_NO_SCALE | FXFT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH);
1228         int max_width = FXFT_Get_Glyph_HoriAdvance(m_Face) * 1000 / FXFT_Get_Face_UnitsPerEM(m_Face);
1229         if (max_width == min_width) {
1230             return;
1231         }
1232         int param = min_param + (max_param - min_param) * (dest_width - min_width) / (max_width - min_width);
1233         coords[1] = param;
1234     }
1235     FXFT_Free(m_Face, pMasters);
1236     FXFT_Set_MM_Design_Coordinates(m_Face, 2, coords);
1237 }
1238 static const size_t ANGLESKEW_ARRAY_SIZE = 30;
1239 static const char g_AngleSkew[ANGLESKEW_ARRAY_SIZE] = {
1240     0, 2, 3, 5, 7, 9, 11, 12, 14, 16,
1241     18, 19, 21, 23, 25, 27, 29, 31, 32, 34,
1242     36, 38, 40, 42, 45, 47, 49, 51, 53, 55,
1243 };
1244 static const size_t WEIGHTPOW_ARRAY_SIZE = 100;
1245 static const uint8_t g_WeightPow[WEIGHTPOW_ARRAY_SIZE] = {
1246     0, 3, 6, 7, 8, 9, 11, 12, 14, 15, 16, 17, 18, 19, 20,
1247     21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 35, 36, 36,
1248     37, 37, 37, 38, 38, 38, 39, 39, 39, 40, 40, 40, 41, 41, 41, 42, 42, 42,
1249     42, 43, 43, 43, 44, 44, 44, 44, 45, 45, 45, 45, 46, 46, 46, 46, 47, 47,
1250     47, 47, 48, 48, 48, 48, 48, 49, 49, 49, 49, 50, 50, 50, 50, 50, 51, 51,
1251     51, 51, 51, 52, 52, 52, 52, 52, 53, 53, 53, 53, 53,
1252 };
1253 static const uint8_t g_WeightPow_11[WEIGHTPOW_ARRAY_SIZE] = {
1254     0, 4, 7, 8, 9, 10, 12, 13, 15, 17, 18, 19, 20, 21, 22,
1255     23, 24, 25, 26, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 39, 39, 40, 40,
1256     41, 41, 41, 42, 42, 42, 43, 43, 43, 44, 44, 44, 45, 45, 45, 46, 46, 46,
1257     46, 43, 47, 47, 48, 48, 48, 48, 45, 50, 50, 50, 46, 51, 51, 51, 52, 52,
1258     52, 52, 53, 53, 53, 53, 53, 54, 54, 54, 54, 55, 55, 55, 55, 55, 56, 56,
1259     56, 56, 56, 57, 57, 57, 57, 57, 58, 58, 58, 58, 58,
1260 };
1261 static const uint8_t g_WeightPow_SHIFTJIS[WEIGHTPOW_ARRAY_SIZE] = {
1262     0, 0, 1, 2, 3, 4, 5, 7, 8, 10, 11, 13, 14, 16, 17, 19, 21, 22, 24, 26, 28,
1263     30, 32, 33, 35, 37, 39, 41, 43, 45, 48, 48, 48, 48, 49, 49, 49, 50, 50, 50, 50,
1264     51, 51, 51, 51, 52, 52, 52, 52, 52, 53, 53, 53, 53, 53, 54, 54, 54, 54, 54, 55, 55,
1265     55, 55, 55, 56, 56, 56, 56, 56 , 56, 57, 57, 57 , 57 , 57, 57, 57, 58, 58, 58, 58, 58,
1266     58, 58, 59, 59, 59, 59, 59, 59, 59, 60, 60, 60, 60, 60, 60, 60, 60,
1267 };
1268 static void _GammaAdjust(uint8_t* pData, int nWid, int nHei, int src_pitch, const uint8_t* gammaTable)
1269 {
1270     int count = nHei * src_pitch;
1271     for(int i = 0; i < count; i++) {
1272         pData[i] = gammaTable[pData[i]];
1273     }
1274 }
1275 static void _ContrastAdjust(uint8_t* pDataIn, uint8_t* pDataOut, int nWid, int nHei, int nSrcRowBytes, int nDstRowBytes)
1276 {
1277     int col, row, temp;
1278     int max = 0, min = 255;
1279     FX_FLOAT rate;
1280     for (row = 0; row < nHei; row ++) {
1281         uint8_t* pRow = pDataIn + row * nSrcRowBytes;
1282         for (col = 0; col < nWid; col++) {
1283             temp = *pRow ++;
1284             if (temp > max) {
1285                 max = temp;
1286             }
1287             if (temp < min) {
1288                 min = temp;
1289             }
1290         }
1291     }
1292     temp = max - min;
1293     if (0 == temp || 255 == temp) {
1294         int rowbytes = FXSYS_abs(nSrcRowBytes) > nDstRowBytes ? nDstRowBytes : FXSYS_abs(nSrcRowBytes);
1295         for (row = 0; row < nHei; row ++) {
1296             FXSYS_memcpy(pDataOut + row * nDstRowBytes, pDataIn + row * nSrcRowBytes, rowbytes);
1297         }
1298         return;
1299     }
1300     rate = 255.f / temp;
1301     for (row = 0; row < nHei; row ++) {
1302         uint8_t* pSrcRow = pDataIn + row * nSrcRowBytes;
1303         uint8_t* pDstRow = pDataOut + row * nDstRowBytes;
1304         for (col = 0; col < nWid; col ++) {
1305             temp = (int)((*(pSrcRow++) - min) * rate + 0.5);
1306             if (temp > 255)     {
1307                 temp = 255;
1308             } else if (temp < 0) {
1309                 temp = 0;
1310             }
1311             *pDstRow ++ = (uint8_t)temp;
1312         }
1313     }
1314 }
1315 CFX_GlyphBitmap* CFX_FaceCache::RenderGlyph(CFX_Font* pFont, FX_DWORD glyph_index, FX_BOOL bFontStyle,
1316         const CFX_AffineMatrix* pMatrix, int dest_width, int anti_alias)
1317 {
1318     if (m_Face == NULL) {
1319         return NULL;
1320     }
1321     FXFT_Matrix  ft_matrix;
1322     ft_matrix.xx = (signed long)(pMatrix->GetA() / 64 * 65536);
1323     ft_matrix.xy = (signed long)(pMatrix->GetC() / 64 * 65536);
1324     ft_matrix.yx = (signed long)(pMatrix->GetB() / 64 * 65536);
1325     ft_matrix.yy = (signed long)(pMatrix->GetD() / 64 * 65536);
1326     FX_BOOL bUseCJKSubFont = FALSE;
1327     const CFX_SubstFont* pSubstFont = pFont->GetSubstFont();
1328     if (pSubstFont) {
1329         bUseCJKSubFont = pSubstFont->m_bSubstOfCJK && bFontStyle;
1330         int skew = 0;
1331         if (bUseCJKSubFont) {
1332             skew = pSubstFont->m_bItlicCJK ? -15 : 0;
1333         } else {
1334             skew = pSubstFont->m_ItalicAngle;
1335         }
1336         if (skew) {
1337             skew = skew <= -ANGLESKEW_ARRAY_SIZE ? -58 : -g_AngleSkew[-skew];
1338             if (pFont->IsVertical()) {
1339                 ft_matrix.yx += ft_matrix.yy * skew / 100;
1340             } else {
1341                 ft_matrix.xy += -ft_matrix.xx * skew / 100;
1342             }
1343         }
1344         if (pSubstFont->m_SubstFlags & FXFONT_SUBST_MM) {
1345             pFont->AdjustMMParams(glyph_index, dest_width, pFont->GetSubstFont()->m_Weight);
1346         }
1347     }
1348     ScopedFontTransform scoped_transform(m_Face, &ft_matrix);
1349     int load_flags = (m_Face->face_flags & FT_FACE_FLAG_SFNT) ? FXFT_LOAD_NO_BITMAP : (FXFT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING);
1350     int error = FXFT_Load_Glyph(m_Face, glyph_index, load_flags);
1351     if (error) {
1352         //if an error is returned, try to reload glyphs without hinting.
1353         if (load_flags & FT_LOAD_NO_HINTING || load_flags & FT_LOAD_NO_SCALE) {
1354             return NULL;
1355         }
1356
1357         load_flags |= FT_LOAD_NO_HINTING;
1358         error = FXFT_Load_Glyph(m_Face, glyph_index, load_flags);
1359
1360         if (error) {
1361             return NULL;
1362         }
1363     }
1364     int weight = 0;
1365     if (bUseCJKSubFont) {
1366         weight = pSubstFont->m_WeightCJK;
1367     } else {
1368         weight = pSubstFont ? pSubstFont->m_Weight : 0;
1369     }
1370     if (pSubstFont && !(pSubstFont->m_SubstFlags & FXFONT_SUBST_MM) && weight > 400) {
1371         int index = (weight - 400) / 10;
1372         if (index >= WEIGHTPOW_ARRAY_SIZE) {
1373             return NULL;
1374         }
1375         int level = 0;
1376         if (pSubstFont->m_Charset == FXFONT_SHIFTJIS_CHARSET) {
1377             level = g_WeightPow_SHIFTJIS[index] * 2 * (FXSYS_abs((int)(ft_matrix.xx)) + FXSYS_abs((int)(ft_matrix.xy))) / 36655;
1378         } else {
1379             level = g_WeightPow_11[index] * (FXSYS_abs((int)(ft_matrix.xx)) + FXSYS_abs((int)(ft_matrix.xy))) / 36655;
1380         }
1381         FXFT_Outline_Embolden(FXFT_Get_Glyph_Outline(m_Face), level);
1382     }
1383     FXFT_Library_SetLcdFilter(CFX_GEModule::Get()->GetFontMgr()->m_FTLibrary, FT_LCD_FILTER_DEFAULT);
1384     error = FXFT_Render_Glyph(m_Face, anti_alias);
1385     if (error) {
1386         return NULL;
1387     }
1388     int bmwidth = FXFT_Get_Bitmap_Width(FXFT_Get_Glyph_Bitmap(m_Face));
1389     int bmheight = FXFT_Get_Bitmap_Rows(FXFT_Get_Glyph_Bitmap(m_Face));
1390     if (bmwidth > 2048 || bmheight > 2048) {
1391         return NULL;
1392     }
1393     int dib_width = bmwidth;
1394     CFX_GlyphBitmap* pGlyphBitmap = new CFX_GlyphBitmap;
1395     pGlyphBitmap->m_Bitmap.Create(dib_width, bmheight,
1396                                   anti_alias == FXFT_RENDER_MODE_MONO ? FXDIB_1bppMask : FXDIB_8bppMask);
1397     pGlyphBitmap->m_Left = FXFT_Get_Glyph_BitmapLeft(m_Face);
1398     pGlyphBitmap->m_Top = FXFT_Get_Glyph_BitmapTop(m_Face);
1399     int dest_pitch = pGlyphBitmap->m_Bitmap.GetPitch();
1400     int src_pitch = FXFT_Get_Bitmap_Pitch(FXFT_Get_Glyph_Bitmap(m_Face));
1401     uint8_t* pDestBuf = pGlyphBitmap->m_Bitmap.GetBuffer();
1402     uint8_t* pSrcBuf = (uint8_t*)FXFT_Get_Bitmap_Buffer(FXFT_Get_Glyph_Bitmap(m_Face));
1403     if (anti_alias != FXFT_RENDER_MODE_MONO && FXFT_Get_Bitmap_PixelMode(FXFT_Get_Glyph_Bitmap(m_Face)) == FXFT_PIXEL_MODE_MONO) {
1404         int bytes = anti_alias == FXFT_RENDER_MODE_LCD ? 3 : 1;
1405         for(int i = 0; i < bmheight; i++)
1406             for(int n = 0; n < bmwidth; n++) {
1407                 uint8_t data = (pSrcBuf[i * src_pitch + n / 8] & (0x80 >> (n % 8))) ? 255 : 0;
1408                 for (int b = 0; b < bytes; b ++) {
1409                     pDestBuf[i * dest_pitch + n * bytes + b] = data;
1410                 }
1411             }
1412     } else {
1413         FXSYS_memset(pDestBuf, 0, dest_pitch * bmheight);
1414         if (anti_alias == FXFT_RENDER_MODE_MONO && FXFT_Get_Bitmap_PixelMode(FXFT_Get_Glyph_Bitmap(m_Face)) == FXFT_PIXEL_MODE_MONO) {
1415             int rowbytes = FXSYS_abs(src_pitch) > dest_pitch ? dest_pitch : FXSYS_abs(src_pitch);
1416             for (int row = 0; row < bmheight; row ++) {
1417                 FXSYS_memcpy(pDestBuf + row * dest_pitch, pSrcBuf + row * src_pitch, rowbytes);
1418             }
1419         } else {
1420             _ContrastAdjust(pSrcBuf, pDestBuf, bmwidth, bmheight, src_pitch, dest_pitch);
1421             _GammaAdjust(pDestBuf, bmwidth, bmheight, dest_pitch, CFX_GEModule::Get()->GetTextGammaTable());
1422         }
1423     }
1424     return pGlyphBitmap;
1425 }
1426 FX_BOOL _OutputGlyph(void* dib, int x, int y, CFX_Font* pFont,
1427                      int glyph_index, FX_ARGB argb)
1428 {
1429     CFX_DIBitmap* pDib = (CFX_DIBitmap*)dib;
1430     FXFT_Face face = pFont->GetFace();
1431     int error = FXFT_Load_Glyph(face, glyph_index, FXFT_LOAD_NO_BITMAP);
1432     if (error) {
1433         return FALSE;
1434     }
1435     error = FXFT_Render_Glyph(face, FXFT_RENDER_MODE_NORMAL);
1436     if (error) {
1437         return FALSE;
1438     }
1439     int bmwidth = FXFT_Get_Bitmap_Width(FXFT_Get_Glyph_Bitmap(face));
1440     int bmheight = FXFT_Get_Bitmap_Rows(FXFT_Get_Glyph_Bitmap(face));
1441     int left = FXFT_Get_Glyph_BitmapLeft(face);
1442     int top = FXFT_Get_Glyph_BitmapTop(face);
1443     const uint8_t* src_buf = (const uint8_t*)FXFT_Get_Bitmap_Buffer(FXFT_Get_Glyph_Bitmap(face));
1444     int src_pitch = FXFT_Get_Bitmap_Pitch(FXFT_Get_Glyph_Bitmap(face));
1445     CFX_DIBitmap mask;
1446     mask.Create(bmwidth, bmheight, FXDIB_8bppMask);
1447     uint8_t* dest_buf = mask.GetBuffer();
1448     int dest_pitch = mask.GetPitch();
1449     for (int row = 0; row < bmheight; row ++) {
1450         const uint8_t* src_scan = src_buf + row * src_pitch;
1451         uint8_t* dest_scan = dest_buf + row * dest_pitch;
1452         FXSYS_memcpy(dest_scan, src_scan, dest_pitch);
1453     }
1454     pDib->CompositeMask(x + left, y - top, bmwidth, bmheight, &mask, argb, 0, 0);
1455     return TRUE;
1456 }
1457 FX_BOOL OutputText(void* dib, int x, int y, CFX_Font* pFont, double font_size,
1458                    CFX_AffineMatrix* pText_matrix, unsigned short const* text, unsigned long argb)
1459 {
1460     if (!pFont) {
1461         return FALSE;
1462     }
1463     FXFT_Face face = pFont->GetFace();
1464     FXFT_Select_Charmap(pFont->m_Face, FXFT_ENCODING_UNICODE);
1465     if (pText_matrix) {
1466         FXFT_Matrix  ft_matrix;
1467         ft_matrix.xx = (signed long)(pText_matrix->a / 64 * 65536);
1468         ft_matrix.xy = (signed long)(pText_matrix->c / 64 * 65536);
1469         ft_matrix.yx = (signed long)(pText_matrix->b / 64 * 65536);
1470         ft_matrix.yy = (signed long)(pText_matrix->d / 64 * 65536);
1471         FXFT_Set_Transform(face, &ft_matrix, 0);
1472     }
1473     FX_FLOAT x_pos = 0;
1474     for (; *text != 0; text ++) {
1475         FX_WCHAR unicode = *text;
1476         int glyph_index = FXFT_Get_Char_Index(pFont->m_Face, unicode);
1477         if (glyph_index <= 0) {
1478             continue;
1479         }
1480         int err = FXFT_Load_Glyph(pFont->m_Face, glyph_index, FXFT_LOAD_NO_SCALE | FXFT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH);
1481         if (err) {
1482             continue;
1483         }
1484         int w = FXFT_Get_Glyph_HoriAdvance(pFont->m_Face);
1485         int em = FXFT_Get_Face_UnitsPerEM(pFont->m_Face);
1486         FX_FLOAT x1, y1;
1487         pText_matrix->Transform(x_pos, 0, x1, y1);
1488         _OutputGlyph(dib, (int)x1 + x, (int) - y1 + y, pFont,
1489                      glyph_index, argb);
1490         x_pos += (FX_FLOAT)w / em;
1491     }
1492     if (pText_matrix)
1493         ResetTransform(face);
1494     return TRUE;
1495 }
1496 FX_BOOL OutputGlyph(void* dib, int x, int y, CFX_Font* pFont, double font_size,
1497                     CFX_AffineMatrix* pMatrix, unsigned long glyph_index, unsigned long argb)
1498 {
1499     FXFT_Matrix  ft_matrix;
1500     if (pMatrix) {
1501         ft_matrix.xx = (signed long)(pMatrix->a * font_size / 64 * 65536);
1502         ft_matrix.xy = (signed long)(pMatrix->c * font_size / 64 * 65536);
1503         ft_matrix.yx = (signed long)(pMatrix->b * font_size / 64 * 65536);
1504         ft_matrix.yy = (signed long)(pMatrix->d * font_size / 64 * 65536);
1505     } else {
1506         ft_matrix.xx = (signed long)(font_size / 64 * 65536);
1507         ft_matrix.xy = ft_matrix.yx = 0;
1508         ft_matrix.yy = (signed long)(font_size / 64 * 65536);
1509     }
1510     ScopedFontTransform scoped_transform(pFont->m_Face, &ft_matrix);
1511     FX_BOOL ret = _OutputGlyph(dib, x, y, pFont,
1512                                glyph_index, argb);
1513     return ret;
1514 }
1515 const CFX_PathData* CFX_FaceCache::LoadGlyphPath(CFX_Font* pFont, FX_DWORD glyph_index, int dest_width)
1516 {
1517     if (m_Face == NULL || glyph_index == (FX_DWORD) - 1) {
1518         return NULL;
1519     }
1520     CFX_PathData* pGlyphPath = NULL;
1521     void* key;
1522     if (pFont->GetSubstFont())
1523         key = (void*)(uintptr_t)(glyph_index + ((pFont->GetSubstFont()->m_Weight / 16) << 15) +
1524                                       ((pFont->GetSubstFont()->m_ItalicAngle / 2) << 21) + ((dest_width / 16) << 25) +
1525                                       (pFont->IsVertical() << 31));
1526     else {
1527         key = (void*)(uintptr_t)glyph_index;
1528     }
1529     if (m_PathMap.Lookup(key, (void*&)pGlyphPath)) {
1530         return pGlyphPath;
1531     }
1532     pGlyphPath = pFont->LoadGlyphPath(glyph_index, dest_width);
1533     m_PathMap.SetAt(key, pGlyphPath);
1534     return pGlyphPath;
1535 }
1536 typedef struct {
1537     FX_BOOL                     m_bCount;
1538     int                         m_PointCount;
1539     FX_PATHPOINT*       m_pPoints;
1540     int                         m_CurX;
1541     int                         m_CurY;
1542     FX_FLOAT            m_CoordUnit;
1543 } OUTLINE_PARAMS;
1544 void _Outline_CheckEmptyContour(OUTLINE_PARAMS* param)
1545 {
1546     if (param->m_PointCount >= 2 && param->m_pPoints[param->m_PointCount - 2].m_Flag == FXPT_MOVETO &&
1547             param->m_pPoints[param->m_PointCount - 2].m_PointX == param->m_pPoints[param->m_PointCount - 1].m_PointX &&
1548             param->m_pPoints[param->m_PointCount - 2].m_PointY == param->m_pPoints[param->m_PointCount - 1].m_PointY) {
1549         param->m_PointCount -= 2;
1550     }
1551     if (param->m_PointCount >= 4 && param->m_pPoints[param->m_PointCount - 4].m_Flag == FXPT_MOVETO &&
1552             param->m_pPoints[param->m_PointCount - 3].m_Flag == FXPT_BEZIERTO &&
1553             param->m_pPoints[param->m_PointCount - 3].m_PointX == param->m_pPoints[param->m_PointCount - 4].m_PointX &&
1554             param->m_pPoints[param->m_PointCount - 3].m_PointY == param->m_pPoints[param->m_PointCount - 4].m_PointY &&
1555             param->m_pPoints[param->m_PointCount - 2].m_PointX == param->m_pPoints[param->m_PointCount - 4].m_PointX &&
1556             param->m_pPoints[param->m_PointCount - 2].m_PointY == param->m_pPoints[param->m_PointCount - 4].m_PointY &&
1557             param->m_pPoints[param->m_PointCount - 1].m_PointX == param->m_pPoints[param->m_PointCount - 4].m_PointX &&
1558             param->m_pPoints[param->m_PointCount - 1].m_PointY == param->m_pPoints[param->m_PointCount - 4].m_PointY) {
1559         param->m_PointCount -= 4;
1560     }
1561 }
1562 extern "C" {
1563     static int _Outline_MoveTo(const FXFT_Vector* to, void* user)
1564     {
1565         OUTLINE_PARAMS* param = (OUTLINE_PARAMS*)user;
1566         if (!param->m_bCount) {
1567             _Outline_CheckEmptyContour(param);
1568             param->m_pPoints[param->m_PointCount].m_PointX = to->x / param->m_CoordUnit;
1569             param->m_pPoints[param->m_PointCount].m_PointY = to->y / param->m_CoordUnit;
1570             param->m_pPoints[param->m_PointCount].m_Flag = FXPT_MOVETO;
1571             param->m_CurX = to->x;
1572             param->m_CurY = to->y;
1573             if (param->m_PointCount) {
1574                 param->m_pPoints[param->m_PointCount - 1].m_Flag |= FXPT_CLOSEFIGURE;
1575             }
1576         }
1577         param->m_PointCount ++;
1578         return 0;
1579     }
1580 };
1581 extern "C" {
1582     static int _Outline_LineTo(const FXFT_Vector* to, void* user)
1583     {
1584         OUTLINE_PARAMS* param = (OUTLINE_PARAMS*)user;
1585         if (!param->m_bCount) {
1586             param->m_pPoints[param->m_PointCount].m_PointX = to->x / param->m_CoordUnit;
1587             param->m_pPoints[param->m_PointCount].m_PointY = to->y / param->m_CoordUnit;
1588             param->m_pPoints[param->m_PointCount].m_Flag = FXPT_LINETO;
1589             param->m_CurX = to->x;
1590             param->m_CurY = to->y;
1591         }
1592         param->m_PointCount ++;
1593         return 0;
1594     }
1595 };
1596 extern "C" {
1597     static int _Outline_ConicTo(const FXFT_Vector* control, const FXFT_Vector* to, void* user)
1598     {
1599         OUTLINE_PARAMS* param = (OUTLINE_PARAMS*)user;
1600         if (!param->m_bCount) {
1601             param->m_pPoints[param->m_PointCount].m_PointX = (param->m_CurX + (control->x - param->m_CurX) * 2 / 3) / param->m_CoordUnit;
1602             param->m_pPoints[param->m_PointCount].m_PointY = (param->m_CurY + (control->y - param->m_CurY) * 2 / 3) / param->m_CoordUnit;
1603             param->m_pPoints[param->m_PointCount].m_Flag = FXPT_BEZIERTO;
1604             param->m_pPoints[param->m_PointCount + 1].m_PointX = (control->x + (to->x - control->x) / 3) / param->m_CoordUnit;
1605             param->m_pPoints[param->m_PointCount + 1].m_PointY = (control->y + (to->y - control->y) / 3) / param->m_CoordUnit;
1606             param->m_pPoints[param->m_PointCount + 1].m_Flag = FXPT_BEZIERTO;
1607             param->m_pPoints[param->m_PointCount + 2].m_PointX = to->x / param->m_CoordUnit;
1608             param->m_pPoints[param->m_PointCount + 2].m_PointY = to->y / param->m_CoordUnit;
1609             param->m_pPoints[param->m_PointCount + 2].m_Flag = FXPT_BEZIERTO;
1610             param->m_CurX = to->x;
1611             param->m_CurY = to->y;
1612         }
1613         param->m_PointCount += 3;
1614         return 0;
1615     }
1616 };
1617 extern "C" {
1618     static int _Outline_CubicTo(const FXFT_Vector* control1, const FXFT_Vector* control2, const FXFT_Vector* to, void* user)
1619     {
1620         OUTLINE_PARAMS* param = (OUTLINE_PARAMS*)user;
1621         if (!param->m_bCount) {
1622             param->m_pPoints[param->m_PointCount].m_PointX = control1->x / param->m_CoordUnit;
1623             param->m_pPoints[param->m_PointCount].m_PointY = control1->y / param->m_CoordUnit;
1624             param->m_pPoints[param->m_PointCount].m_Flag = FXPT_BEZIERTO;
1625             param->m_pPoints[param->m_PointCount + 1].m_PointX = control2->x / param->m_CoordUnit;
1626             param->m_pPoints[param->m_PointCount + 1].m_PointY = control2->y / param->m_CoordUnit;
1627             param->m_pPoints[param->m_PointCount + 1].m_Flag = FXPT_BEZIERTO;
1628             param->m_pPoints[param->m_PointCount + 2].m_PointX = to->x / param->m_CoordUnit;
1629             param->m_pPoints[param->m_PointCount + 2].m_PointY = to->y / param->m_CoordUnit;
1630             param->m_pPoints[param->m_PointCount + 2].m_Flag = FXPT_BEZIERTO;
1631             param->m_CurX = to->x;
1632             param->m_CurY = to->y;
1633         }
1634         param->m_PointCount += 3;
1635         return 0;
1636     }
1637 };
1638 CFX_PathData* CFX_Font::LoadGlyphPath(FX_DWORD glyph_index, int dest_width)
1639 {
1640     if (m_Face == NULL) {
1641         return NULL;
1642     }
1643     FXFT_Set_Pixel_Sizes(m_Face, 0, 64);
1644     FXFT_Matrix  ft_matrix = {65536, 0, 0, 65536};
1645     if (m_pSubstFont) {
1646         if (m_pSubstFont->m_ItalicAngle) {
1647             int skew = m_pSubstFont->m_ItalicAngle;
1648             skew = skew <= -ANGLESKEW_ARRAY_SIZE ? -58 : -g_AngleSkew[-skew];
1649             if (m_bVertical) {
1650                 ft_matrix.yx += ft_matrix.yy * skew / 100;
1651             } else {
1652                 ft_matrix.xy += -ft_matrix.xx * skew / 100;
1653             }
1654         }
1655         if (m_pSubstFont->m_SubstFlags & FXFONT_SUBST_MM) {
1656             AdjustMMParams(glyph_index, dest_width, m_pSubstFont->m_Weight);
1657         }
1658     }
1659     ScopedFontTransform scoped_transform(m_Face, &ft_matrix);
1660     int load_flags = FXFT_LOAD_NO_BITMAP;
1661     if (!(m_Face->face_flags & FT_FACE_FLAG_SFNT) || !FT_IS_TRICKY(m_Face)) {
1662         load_flags |= FT_LOAD_NO_HINTING;
1663     }
1664     int error = FXFT_Load_Glyph(m_Face, glyph_index, load_flags);
1665     if (error) {
1666         return NULL;
1667     }
1668     if (m_pSubstFont && !(m_pSubstFont->m_SubstFlags & FXFONT_SUBST_MM) && m_pSubstFont->m_Weight > 400) {
1669         int index = (m_pSubstFont->m_Weight - 400) / 10;
1670         if (index >= WEIGHTPOW_ARRAY_SIZE)
1671             index = WEIGHTPOW_ARRAY_SIZE - 1;
1672         int level = 0;
1673         if (m_pSubstFont->m_Charset == FXFONT_SHIFTJIS_CHARSET) {
1674             level = g_WeightPow_SHIFTJIS[index] * 2 * 65536 / 36655;
1675         } else {
1676             level = g_WeightPow[index] * 2;
1677         }
1678         FXFT_Outline_Embolden(FXFT_Get_Glyph_Outline(m_Face), level);
1679     }
1680     FXFT_Outline_Funcs funcs;
1681     funcs.move_to = _Outline_MoveTo;
1682     funcs.line_to = _Outline_LineTo;
1683     funcs.conic_to = _Outline_ConicTo;
1684     funcs.cubic_to = _Outline_CubicTo;
1685     funcs.shift = 0;
1686     funcs.delta = 0;
1687     OUTLINE_PARAMS params;
1688     params.m_bCount = TRUE;
1689     params.m_PointCount = 0;
1690     FXFT_Outline_Decompose(FXFT_Get_Glyph_Outline(m_Face), &funcs, &params);
1691     if (params.m_PointCount == 0) {
1692         return NULL;
1693     }
1694     CFX_PathData* pPath = new CFX_PathData;
1695     pPath->SetPointCount(params.m_PointCount);
1696     params.m_bCount = FALSE;
1697     params.m_PointCount = 0;
1698     params.m_pPoints = pPath->GetPoints();
1699     params.m_CurX = params.m_CurY = 0;
1700     params.m_CoordUnit = 64 * 64.0;
1701     FXFT_Outline_Decompose(FXFT_Get_Glyph_Outline(m_Face), &funcs, &params);
1702     _Outline_CheckEmptyContour(&params);
1703     pPath->TrimPoints(params.m_PointCount);
1704     if (params.m_PointCount) {
1705         pPath->GetPoints()[params.m_PointCount - 1].m_Flag |= FXPT_CLOSEFIGURE;
1706     }
1707     return pPath;
1708 }
1709 void _CFX_UniqueKeyGen::Generate(int count, ...)
1710 {
1711     va_list argList;
1712     va_start(argList, count);
1713     for (int i = 0; i < count; i ++) {
1714         int p = va_arg(argList, int);
1715         ((FX_DWORD*)m_Key)[i] = p;
1716     }
1717     va_end(argList);
1718     m_KeyLen = count * sizeof(FX_DWORD);
1719 }