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