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