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