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