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