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