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