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