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