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