Revert "Remove FX_Alloc() null checks now that it can't return NULL."
[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 = new CFX_FaceCache(bExternal ? NULL : (FXFT_Face)face);
988     counted_face_cache = new CFX_CountedFaceCache;
989     counted_face_cache->m_nCount = 2;
990     counted_face_cache->m_Obj = face_cache;
991     map.SetAt((FXFT_Face)face, counted_face_cache);
992     return face_cache;
993 }
994 void CFX_FontCache::ReleaseCachedFace(CFX_Font* pFont)
995 {
996     FX_BOOL bExternal = pFont->GetFace() == NULL;
997     void* face = bExternal ? pFont->GetSubstFont()->m_ExtHandle : pFont->GetFace();
998     CFX_FTCacheMap& map =  bExternal ? m_ExtFaceMap : m_FTFaceMap;
999     CFX_CountedFaceCache* counted_face_cache = NULL;
1000     if (!map.Lookup((FXFT_Face)face, counted_face_cache)) {
1001         return;
1002     }
1003     if (counted_face_cache->m_nCount > 1) {
1004         counted_face_cache->m_nCount--;
1005     }
1006 }
1007 void CFX_FontCache::FreeCache(FX_BOOL bRelease)
1008 {
1009     {
1010         FX_POSITION pos;
1011         pos = m_FTFaceMap.GetStartPosition();
1012         while (pos) {
1013             FXFT_Face face;
1014             CFX_CountedFaceCache* cache;
1015             m_FTFaceMap.GetNextAssoc(pos, face, cache);
1016             if (bRelease || cache->m_nCount < 2) {
1017                 delete cache->m_Obj;
1018                 delete cache;
1019                 m_FTFaceMap.RemoveKey(face);
1020             }
1021         }
1022         pos = m_ExtFaceMap.GetStartPosition();
1023         while (pos) {
1024             FXFT_Face face;
1025             CFX_CountedFaceCache* cache;
1026             m_ExtFaceMap.GetNextAssoc(pos, face, cache);
1027             if (bRelease || cache->m_nCount < 2) {
1028                 delete cache->m_Obj;
1029                 delete cache;
1030                 m_ExtFaceMap.RemoveKey(face);
1031             }
1032         }
1033     }
1034 }
1035 CFX_FaceCache::CFX_FaceCache(FXFT_Face face)
1036 {
1037     m_Face = face;
1038     m_pBitmap = NULL;
1039 }
1040 CFX_FaceCache::~CFX_FaceCache()
1041 {
1042     FX_POSITION pos = m_SizeMap.GetStartPosition();
1043     CFX_ByteString Key;
1044     CFX_SizeGlyphCache* pSizeCache = NULL;
1045     while(pos) {
1046         m_SizeMap.GetNextAssoc( pos, Key, (void*&)pSizeCache);
1047         delete pSizeCache;
1048     }
1049     m_SizeMap.RemoveAll();
1050     pos = m_PathMap.GetStartPosition();
1051     FX_LPVOID key1;
1052     CFX_PathData* pPath;
1053     while (pos) {
1054         m_PathMap.GetNextAssoc(pos, key1, (FX_LPVOID&)pPath);
1055         delete pPath;
1056     }
1057     if (m_pBitmap) {
1058         delete m_pBitmap;
1059     }
1060     m_PathMap.RemoveAll();
1061 }
1062 #if _FXM_PLATFORM_  != _FXM_PLATFORM_APPLE_
1063 void CFX_FaceCache::InitPlatform()
1064 {
1065 }
1066 #endif
1067 CFX_GlyphBitmap* CFX_FaceCache::LookUpGlyphBitmap(CFX_Font* pFont, const CFX_AffineMatrix* pMatrix,
1068         CFX_ByteStringC& FaceGlyphsKey, FX_DWORD glyph_index, FX_BOOL bFontStyle,
1069         int dest_width, int anti_alias)
1070 {
1071     CFX_SizeGlyphCache* pSizeCache = NULL;
1072     if (!m_SizeMap.Lookup(FaceGlyphsKey, (void*&)pSizeCache)) {
1073         pSizeCache = new CFX_SizeGlyphCache;
1074         m_SizeMap.SetAt(FaceGlyphsKey, pSizeCache);
1075     }
1076     CFX_GlyphBitmap* pGlyphBitmap = NULL;
1077     if (pSizeCache->m_GlyphMap.Lookup((FX_LPVOID)(FX_UINTPTR)glyph_index, (void*&)pGlyphBitmap)) {
1078         return pGlyphBitmap;
1079     }
1080     pGlyphBitmap = RenderGlyph(pFont, glyph_index, bFontStyle, pMatrix, dest_width, anti_alias);
1081     if (pGlyphBitmap == NULL)   {
1082         return NULL;
1083     }
1084     pSizeCache->m_GlyphMap.SetAt((FX_LPVOID)(FX_UINTPTR)glyph_index, pGlyphBitmap);
1085     return pGlyphBitmap;
1086 }
1087 const CFX_GlyphBitmap* CFX_FaceCache::LoadGlyphBitmap(CFX_Font* pFont, FX_DWORD glyph_index, FX_BOOL bFontStyle, const CFX_AffineMatrix* pMatrix,
1088         int dest_width, int anti_alias, int& text_flags)
1089 {
1090     if (glyph_index == (FX_DWORD) - 1) {
1091         return NULL;
1092     }
1093     _CFX_UniqueKeyGen keygen;
1094 #if _FXM_PLATFORM_  != _FXM_PLATFORM_APPLE_
1095     if (pFont->GetSubstFont())
1096         keygen.Generate(9, (int)(pMatrix->a * 10000), (int)(pMatrix->b * 10000),
1097                         (int)(pMatrix->c * 10000), (int)(pMatrix->d * 10000), dest_width, anti_alias,
1098                         pFont->GetSubstFont()->m_Weight, pFont->GetSubstFont()->m_ItalicAngle, pFont->IsVertical());
1099     else
1100         keygen.Generate(6, (int)(pMatrix->a * 10000), (int)(pMatrix->b * 10000),
1101                         (int)(pMatrix->c * 10000), (int)(pMatrix->d * 10000), dest_width, anti_alias);
1102 #else
1103     if (text_flags & FXTEXT_NO_NATIVETEXT) {
1104         if (pFont->GetSubstFont())
1105             keygen.Generate(9, (int)(pMatrix->a * 10000), (int)(pMatrix->b * 10000),
1106                             (int)(pMatrix->c * 10000), (int)(pMatrix->d * 10000), dest_width, anti_alias,
1107                             pFont->GetSubstFont()->m_Weight, pFont->GetSubstFont()->m_ItalicAngle, pFont->IsVertical());
1108         else
1109             keygen.Generate(6, (int)(pMatrix->a * 10000), (int)(pMatrix->b * 10000),
1110                             (int)(pMatrix->c * 10000), (int)(pMatrix->d * 10000), dest_width, anti_alias);
1111     } else {
1112         if (pFont->GetSubstFont())
1113             keygen.Generate(10, (int)(pMatrix->a * 10000), (int)(pMatrix->b * 10000),
1114                             (int)(pMatrix->c * 10000), (int)(pMatrix->d * 10000), dest_width, anti_alias,
1115                             pFont->GetSubstFont()->m_Weight, pFont->GetSubstFont()->m_ItalicAngle, pFont->IsVertical(), 3);
1116         else
1117             keygen.Generate(7, (int)(pMatrix->a * 10000), (int)(pMatrix->b * 10000),
1118                             (int)(pMatrix->c * 10000), (int)(pMatrix->d * 10000), dest_width, anti_alias, 3);
1119     }
1120 #endif
1121     CFX_ByteStringC FaceGlyphsKey(keygen.m_Key, keygen.m_KeyLen);
1122 #if _FXM_PLATFORM_  != _FXM_PLATFORM_APPLE_
1123     return LookUpGlyphBitmap(pFont, pMatrix, FaceGlyphsKey, glyph_index, bFontStyle, dest_width, anti_alias);
1124 #else
1125     if (text_flags & FXTEXT_NO_NATIVETEXT) {
1126         return LookUpGlyphBitmap(pFont, pMatrix, FaceGlyphsKey, glyph_index, bFontStyle, dest_width, anti_alias);
1127     } else {
1128         CFX_GlyphBitmap* pGlyphBitmap;
1129         CFX_SizeGlyphCache* pSizeCache = NULL;
1130         if (m_SizeMap.Lookup(FaceGlyphsKey, (void*&)pSizeCache)) {
1131             if (pSizeCache->m_GlyphMap.Lookup((FX_LPVOID)(FX_UINTPTR)glyph_index, (void*&)pGlyphBitmap)) {
1132                 return pGlyphBitmap;
1133             }
1134             pGlyphBitmap = RenderGlyph_Nativetext(pFont, glyph_index, pMatrix, dest_width, anti_alias);
1135             if (pGlyphBitmap) {
1136                 pSizeCache->m_GlyphMap.SetAt((FX_LPVOID)(FX_UINTPTR)glyph_index, pGlyphBitmap);
1137                 return pGlyphBitmap;
1138             }
1139         } else {
1140             pGlyphBitmap = RenderGlyph_Nativetext(pFont, glyph_index, pMatrix, dest_width, anti_alias);
1141             if (pGlyphBitmap) {
1142                 pSizeCache = new CFX_SizeGlyphCache;
1143                 m_SizeMap.SetAt(FaceGlyphsKey, pSizeCache);
1144                 pSizeCache->m_GlyphMap.SetAt((FX_LPVOID)(FX_UINTPTR)glyph_index, pGlyphBitmap);
1145                 return pGlyphBitmap;
1146             }
1147         }
1148         if (pFont->GetSubstFont())
1149             keygen.Generate(9, (int)(pMatrix->a * 10000), (int)(pMatrix->b * 10000),
1150                             (int)(pMatrix->c * 10000), (int)(pMatrix->d * 10000), dest_width, anti_alias,
1151                             pFont->GetSubstFont()->m_Weight, pFont->GetSubstFont()->m_ItalicAngle, pFont->IsVertical());
1152         else
1153             keygen.Generate(6, (int)(pMatrix->a * 10000), (int)(pMatrix->b * 10000),
1154                             (int)(pMatrix->c * 10000), (int)(pMatrix->d * 10000), dest_width, anti_alias);
1155         CFX_ByteStringC FaceGlyphsKey(keygen.m_Key, keygen.m_KeyLen);
1156         text_flags |= FXTEXT_NO_NATIVETEXT;
1157         return LookUpGlyphBitmap(pFont, pMatrix, FaceGlyphsKey, glyph_index, bFontStyle, dest_width, anti_alias);
1158     }
1159 #endif
1160 }
1161 CFX_SizeGlyphCache::~CFX_SizeGlyphCache()
1162 {
1163     FX_POSITION pos = m_GlyphMap.GetStartPosition();
1164     FX_LPVOID Key;
1165     CFX_GlyphBitmap* pGlyphBitmap = NULL;
1166     while(pos) {
1167         m_GlyphMap.GetNextAssoc(pos, Key, (void*&)pGlyphBitmap);
1168         delete pGlyphBitmap;
1169     }
1170     m_GlyphMap.RemoveAll();
1171 }
1172 #define CONTRAST_RAMP_STEP      1
1173 void CFX_Font::AdjustMMParams(int glyph_index, int dest_width, int weight)
1174 {
1175     FXFT_MM_Var pMasters = NULL;
1176     FXFT_Get_MM_Var(m_Face, &pMasters);
1177     if (pMasters == NULL) {
1178         return;
1179     }
1180     long coords[2];
1181     if (weight == 0) {
1182         coords[0] = FXFT_Get_MM_Axis_Def(FXFT_Get_MM_Axis(pMasters, 0)) / 65536;
1183     } else {
1184         coords[0] = weight;
1185     }
1186     if (dest_width == 0) {
1187         coords[1] = FXFT_Get_MM_Axis_Def(FXFT_Get_MM_Axis(pMasters, 1)) / 65536;
1188     } else {
1189         int min_param = FXFT_Get_MM_Axis_Min(FXFT_Get_MM_Axis(pMasters, 1)) / 65536;
1190         int max_param = FXFT_Get_MM_Axis_Max(FXFT_Get_MM_Axis(pMasters, 1)) / 65536;
1191         coords[1] = min_param;
1192         int error = FXFT_Set_MM_Design_Coordinates(m_Face, 2, coords);
1193         error = FXFT_Load_Glyph(m_Face, glyph_index, FXFT_LOAD_NO_SCALE | FXFT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH);
1194         int min_width = FXFT_Get_Glyph_HoriAdvance(m_Face) * 1000 / FXFT_Get_Face_UnitsPerEM(m_Face);
1195         coords[1] = max_param;
1196         error = FXFT_Set_MM_Design_Coordinates(m_Face, 2, coords);
1197         error = FXFT_Load_Glyph(m_Face, glyph_index, FXFT_LOAD_NO_SCALE | FXFT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH);
1198         int max_width = FXFT_Get_Glyph_HoriAdvance(m_Face) * 1000 / FXFT_Get_Face_UnitsPerEM(m_Face);
1199         if (max_width == min_width) {
1200             return;
1201         }
1202         int param = min_param + (max_param - min_param) * (dest_width - min_width) / (max_width - min_width);
1203         coords[1] = param;
1204     }
1205     FXFT_Free(m_Face, pMasters);
1206     FXFT_Set_MM_Design_Coordinates(m_Face, 2, coords);
1207 }
1208 static const size_t ANGLESKEW_ARRAY_SIZE = 30;
1209 static const char g_AngleSkew[ANGLESKEW_ARRAY_SIZE] = {
1210     0, 2, 3, 5, 7, 9, 11, 12, 14, 16,
1211     18, 19, 21, 23, 25, 27, 29, 31, 32, 34,
1212     36, 38, 40, 42, 45, 47, 49, 51, 53, 55,
1213 };
1214 static const size_t WEIGHTPOW_ARRAY_SIZE = 100;
1215 static const FX_BYTE g_WeightPow[WEIGHTPOW_ARRAY_SIZE] = {
1216     0, 3, 6, 7, 8, 9, 11, 12, 14, 15, 16, 17, 18, 19, 20,
1217     21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 35, 36, 36,
1218     37, 37, 37, 38, 38, 38, 39, 39, 39, 40, 40, 40, 41, 41, 41, 42, 42, 42,
1219     42, 43, 43, 43, 44, 44, 44, 44, 45, 45, 45, 45, 46, 46, 46, 46, 47, 47,
1220     47, 47, 48, 48, 48, 48, 48, 49, 49, 49, 49, 50, 50, 50, 50, 50, 51, 51,
1221     51, 51, 51, 52, 52, 52, 52, 52, 53, 53, 53, 53, 53,
1222 };
1223 static const FX_BYTE g_WeightPow_11[WEIGHTPOW_ARRAY_SIZE] = {
1224     0, 4, 7, 8, 9, 10, 12, 13, 15, 17, 18, 19, 20, 21, 22,
1225     23, 24, 25, 26, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 39, 39, 40, 40,
1226     41, 41, 41, 42, 42, 42, 43, 43, 43, 44, 44, 44, 45, 45, 45, 46, 46, 46,
1227     46, 43, 47, 47, 48, 48, 48, 48, 45, 50, 50, 50, 46, 51, 51, 51, 52, 52,
1228     52, 52, 53, 53, 53, 53, 53, 54, 54, 54, 54, 55, 55, 55, 55, 55, 56, 56,
1229     56, 56, 56, 57, 57, 57, 57, 57, 58, 58, 58, 58, 58,
1230 };
1231 static const FX_BYTE g_WeightPow_SHIFTJIS[WEIGHTPOW_ARRAY_SIZE] = {
1232     0, 0, 1, 2, 3, 4, 5, 7, 8, 10, 11, 13, 14, 16, 17, 19, 21, 22, 24, 26, 28,
1233     30, 32, 33, 35, 37, 39, 41, 43, 45, 48, 48, 48, 48, 49, 49, 49, 50, 50, 50, 50,
1234     51, 51, 51, 51, 52, 52, 52, 52, 52, 53, 53, 53, 53, 53, 54, 54, 54, 54, 54, 55, 55,
1235     55, 55, 55, 56, 56, 56, 56, 56 , 56, 57, 57, 57 , 57 , 57, 57, 57, 58, 58, 58, 58, 58,
1236     58, 58, 59, 59, 59, 59, 59, 59, 59, 60, 60, 60, 60, 60, 60, 60, 60,
1237 };
1238 static void _GammaAdjust(FX_LPBYTE pData, int nWid, int nHei, int src_pitch, FX_LPCBYTE gammaTable)
1239 {
1240     int count = nHei * src_pitch;
1241     for(int i = 0; i < count; i++) {
1242         pData[i] = gammaTable[pData[i]];
1243     }
1244 }
1245 static void _ContrastAdjust(FX_LPBYTE pDataIn, FX_LPBYTE pDataOut, int nWid, int nHei, int nSrcRowBytes, int nDstRowBytes)
1246 {
1247     int col, row, temp;
1248     int max = 0, min = 255;
1249     FX_FLOAT rate;
1250     for (row = 0; row < nHei; row ++) {
1251         FX_LPBYTE pRow = pDataIn + row * nSrcRowBytes;
1252         for (col = 0; col < nWid; col++) {
1253             temp = *pRow ++;
1254             if (temp > max) {
1255                 max = temp;
1256             }
1257             if (temp < min) {
1258                 min = temp;
1259             }
1260         }
1261     }
1262     temp = max - min;
1263     if (0 == temp || 255 == temp) {
1264         int rowbytes = FXSYS_abs(nSrcRowBytes) > nDstRowBytes ? nDstRowBytes : FXSYS_abs(nSrcRowBytes);
1265         for (row = 0; row < nHei; row ++) {
1266             FXSYS_memcpy32(pDataOut + row * nDstRowBytes, pDataIn + row * nSrcRowBytes, rowbytes);
1267         }
1268         return;
1269     }
1270     rate = 255.f / temp;
1271     for (row = 0; row < nHei; row ++) {
1272         FX_LPBYTE pSrcRow = pDataIn + row * nSrcRowBytes;
1273         FX_LPBYTE pDstRow = pDataOut + row * nDstRowBytes;
1274         for (col = 0; col < nWid; col ++) {
1275             temp = (int)((*(pSrcRow++) - min) * rate + 0.5);
1276             if (temp > 255)     {
1277                 temp = 255;
1278             } else if (temp < 0) {
1279                 temp = 0;
1280             }
1281             *pDstRow ++ = (FX_BYTE)temp;
1282         }
1283     }
1284 }
1285 CFX_GlyphBitmap* CFX_FaceCache::RenderGlyph(CFX_Font* pFont, FX_DWORD glyph_index, FX_BOOL bFontStyle,
1286         const CFX_AffineMatrix* pMatrix, int dest_width, int anti_alias)
1287 {
1288     if (m_Face == NULL) {
1289         return NULL;
1290     }
1291     FXFT_Matrix  ft_matrix;
1292     ft_matrix.xx = (signed long)(pMatrix->GetA() / 64 * 65536);
1293     ft_matrix.xy = (signed long)(pMatrix->GetC() / 64 * 65536);
1294     ft_matrix.yx = (signed long)(pMatrix->GetB() / 64 * 65536);
1295     ft_matrix.yy = (signed long)(pMatrix->GetD() / 64 * 65536);
1296     FX_BOOL bUseCJKSubFont = FALSE;
1297     const CFX_SubstFont* pSubstFont = pFont->GetSubstFont();
1298     if (pSubstFont) {
1299         bUseCJKSubFont = pSubstFont->m_bSubstOfCJK && bFontStyle;
1300         int skew = 0;
1301         if (bUseCJKSubFont) {
1302             skew = pSubstFont->m_bItlicCJK ? -15 : 0;
1303         } else {
1304             skew = pSubstFont->m_ItalicAngle;
1305         }
1306         if (skew) {
1307             skew = skew <= -ANGLESKEW_ARRAY_SIZE ? -58 : -g_AngleSkew[-skew];
1308             if (pFont->IsVertical()) {
1309                 ft_matrix.yx += ft_matrix.yy * skew / 100;
1310             } else {
1311                 ft_matrix.xy += -ft_matrix.xx * skew / 100;
1312             }
1313         }
1314         if (pSubstFont->m_SubstFlags & FXFONT_SUBST_MM) {
1315             pFont->AdjustMMParams(glyph_index, dest_width, pFont->GetSubstFont()->m_Weight);
1316         }
1317     }
1318     FXFT_Set_Transform(m_Face, &ft_matrix, 0);
1319     int load_flags = (m_Face->face_flags & FT_FACE_FLAG_SFNT) ? FXFT_LOAD_NO_BITMAP : (FXFT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING);
1320     int error = FXFT_Load_Glyph(m_Face, glyph_index, load_flags);
1321     if (error) {
1322         //if an error is returned, try to reload glyphs without hinting.
1323         if (load_flags & FT_LOAD_NO_HINTING || load_flags & FT_LOAD_NO_SCALE) {
1324             return NULL;
1325         }
1326
1327         load_flags |= FT_LOAD_NO_HINTING;
1328         error = FXFT_Load_Glyph(m_Face, glyph_index, load_flags);
1329
1330         if (error) { 
1331             return NULL;
1332         }
1333     }
1334     int weight = 0;
1335     if (bUseCJKSubFont) {
1336         weight = pSubstFont->m_WeightCJK;
1337     } else {
1338         weight = pSubstFont ? pSubstFont->m_Weight : 0;
1339     }
1340     if (pSubstFont && !(pSubstFont->m_SubstFlags & FXFONT_SUBST_MM) && weight > 400) {
1341         int index = (weight - 400) / 10;
1342         if (index >= WEIGHTPOW_ARRAY_SIZE) {
1343             return NULL;
1344         }
1345         int level = 0;
1346         if (pSubstFont->m_Charset == FXFONT_SHIFTJIS_CHARSET) {
1347             level = g_WeightPow_SHIFTJIS[index] * 2 * (FXSYS_abs((int)(ft_matrix.xx)) + FXSYS_abs((int)(ft_matrix.xy))) / 36655;
1348         } else {
1349             level = g_WeightPow_11[index] * (FXSYS_abs((int)(ft_matrix.xx)) + FXSYS_abs((int)(ft_matrix.xy))) / 36655;
1350         }
1351         FXFT_Outline_Embolden(FXFT_Get_Glyph_Outline(m_Face), level);
1352     }
1353     FXFT_Library_SetLcdFilter(CFX_GEModule::Get()->GetFontMgr()->m_FTLibrary, FT_LCD_FILTER_DEFAULT);
1354     error = FXFT_Render_Glyph(m_Face, anti_alias);
1355     if (error) {
1356         return NULL;
1357     }
1358     int bmwidth = FXFT_Get_Bitmap_Width(FXFT_Get_Glyph_Bitmap(m_Face));
1359     int bmheight = FXFT_Get_Bitmap_Rows(FXFT_Get_Glyph_Bitmap(m_Face));
1360     if (bmwidth > 2048 || bmheight > 2048) {
1361         return NULL;
1362     }
1363     int dib_width = bmwidth;
1364     CFX_GlyphBitmap* pGlyphBitmap = new CFX_GlyphBitmap;
1365     pGlyphBitmap->m_Bitmap.Create(dib_width, bmheight,
1366                                   anti_alias == FXFT_RENDER_MODE_MONO ? FXDIB_1bppMask : FXDIB_8bppMask);
1367     pGlyphBitmap->m_Left = FXFT_Get_Glyph_BitmapLeft(m_Face);
1368     pGlyphBitmap->m_Top = FXFT_Get_Glyph_BitmapTop(m_Face);
1369     int dest_pitch = pGlyphBitmap->m_Bitmap.GetPitch();
1370     int src_pitch = FXFT_Get_Bitmap_Pitch(FXFT_Get_Glyph_Bitmap(m_Face));
1371     FX_BYTE* pDestBuf = pGlyphBitmap->m_Bitmap.GetBuffer();
1372     FX_BYTE* pSrcBuf = (FX_BYTE*)FXFT_Get_Bitmap_Buffer(FXFT_Get_Glyph_Bitmap(m_Face));
1373     if (anti_alias != FXFT_RENDER_MODE_MONO && FXFT_Get_Bitmap_PixelMode(FXFT_Get_Glyph_Bitmap(m_Face)) == FXFT_PIXEL_MODE_MONO) {
1374         int bytes = anti_alias == FXFT_RENDER_MODE_LCD ? 3 : 1;
1375         for(int i = 0; i < bmheight; i++)
1376             for(int n = 0; n < bmwidth; n++) {
1377                 FX_BYTE data = (pSrcBuf[i * src_pitch + n / 8] & (0x80 >> (n % 8))) ? 255 : 0;
1378                 for (int b = 0; b < bytes; b ++) {
1379                     pDestBuf[i * dest_pitch + n * bytes + b] = data;
1380                 }
1381             }
1382     } else {
1383         FXSYS_memset32(pDestBuf, 0, dest_pitch * bmheight);
1384         if (anti_alias == FXFT_RENDER_MODE_MONO && FXFT_Get_Bitmap_PixelMode(FXFT_Get_Glyph_Bitmap(m_Face)) == FXFT_PIXEL_MODE_MONO) {
1385             int rowbytes = FXSYS_abs(src_pitch) > dest_pitch ? dest_pitch : FXSYS_abs(src_pitch);
1386             for (int row = 0; row < bmheight; row ++) {
1387                 FXSYS_memcpy32(pDestBuf + row * dest_pitch, pSrcBuf + row * src_pitch, rowbytes);
1388             }
1389         } else {
1390             _ContrastAdjust(pSrcBuf, pDestBuf, bmwidth, bmheight, src_pitch, dest_pitch);
1391             _GammaAdjust(pDestBuf, bmwidth, bmheight, dest_pitch, CFX_GEModule::Get()->GetTextGammaTable());
1392         }
1393     }
1394     return pGlyphBitmap;
1395 }
1396 FX_BOOL _OutputGlyph(void* dib, int x, int y, CFX_Font* pFont,
1397                      int glyph_index, FX_ARGB argb)
1398 {
1399     CFX_DIBitmap* pDib = (CFX_DIBitmap*)dib;
1400     FXFT_Face face = pFont->GetFace();
1401     int error = FXFT_Load_Glyph(face, glyph_index, FXFT_LOAD_NO_BITMAP);
1402     if (error) {
1403         return FALSE;
1404     }
1405     error = FXFT_Render_Glyph(face, FXFT_RENDER_MODE_NORMAL);
1406     if (error) {
1407         return FALSE;
1408     }
1409     int bmwidth = FXFT_Get_Bitmap_Width(FXFT_Get_Glyph_Bitmap(face));
1410     int bmheight = FXFT_Get_Bitmap_Rows(FXFT_Get_Glyph_Bitmap(face));
1411     int left = FXFT_Get_Glyph_BitmapLeft(face);
1412     int top = FXFT_Get_Glyph_BitmapTop(face);
1413     FX_LPCBYTE src_buf = (FX_LPCBYTE)FXFT_Get_Bitmap_Buffer(FXFT_Get_Glyph_Bitmap(face));
1414     int src_pitch = FXFT_Get_Bitmap_Pitch(FXFT_Get_Glyph_Bitmap(face));
1415     CFX_DIBitmap mask;
1416     mask.Create(bmwidth, bmheight, FXDIB_8bppMask);
1417     FX_LPBYTE dest_buf = mask.GetBuffer();
1418     int dest_pitch = mask.GetPitch();
1419     for (int row = 0; row < bmheight; row ++) {
1420         FX_LPCBYTE src_scan = src_buf + row * src_pitch;
1421         FX_LPBYTE dest_scan = dest_buf + row * dest_pitch;
1422         FXSYS_memcpy32(dest_scan, src_scan, dest_pitch);
1423     }
1424     pDib->CompositeMask(x + left, y - top, bmwidth, bmheight, &mask, argb, 0, 0);
1425     return TRUE;
1426 }
1427 FX_BOOL OutputText(void* dib, int x, int y, CFX_Font* pFont, double font_size,
1428                    CFX_AffineMatrix* pText_matrix, unsigned short const* text, unsigned long argb)
1429 {
1430     if (!pFont) {
1431         return FALSE;
1432     }
1433     FXFT_Face face = pFont->GetFace();
1434     FXFT_Select_Charmap(pFont->m_Face, FXFT_ENCODING_UNICODE);
1435     if (pText_matrix) {
1436         FXFT_Matrix  ft_matrix;
1437         ft_matrix.xx = (signed long)(pText_matrix->a / 64 * 65536);
1438         ft_matrix.xy = (signed long)(pText_matrix->c / 64 * 65536);
1439         ft_matrix.yx = (signed long)(pText_matrix->b / 64 * 65536);
1440         ft_matrix.yy = (signed long)(pText_matrix->d / 64 * 65536);
1441         FXFT_Set_Transform(face, &ft_matrix, 0);
1442     }
1443     FX_FLOAT x_pos = 0;
1444     for (; *text != 0; text ++) {
1445         FX_WCHAR unicode = *text;
1446         int glyph_index = FXFT_Get_Char_Index(pFont->m_Face, unicode);
1447         if (glyph_index <= 0) {
1448             continue;
1449         }
1450         int err = FXFT_Load_Glyph(pFont->m_Face, glyph_index, FXFT_LOAD_NO_SCALE | FXFT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH);
1451         if (err) {
1452             continue;
1453         }
1454         int w = FXFT_Get_Glyph_HoriAdvance(pFont->m_Face);
1455         int em = FXFT_Get_Face_UnitsPerEM(pFont->m_Face);
1456         FX_FLOAT x1, y1;
1457         pText_matrix->Transform(x_pos, 0, x1, y1);
1458         _OutputGlyph(dib, (int)x1 + x, (int) - y1 + y, pFont,
1459                      glyph_index, argb);
1460         x_pos += (FX_FLOAT)w / em;
1461     }
1462     return TRUE;
1463 }
1464 FX_BOOL OutputGlyph(void* dib, int x, int y, CFX_Font* pFont, double font_size,
1465                     CFX_AffineMatrix* pMatrix, unsigned long glyph_index, unsigned long argb)
1466 {
1467     FXFT_Matrix  ft_matrix;
1468     if (pMatrix) {
1469         ft_matrix.xx = (signed long)(pMatrix->a * font_size / 64 * 65536);
1470         ft_matrix.xy = (signed long)(pMatrix->c * font_size / 64 * 65536);
1471         ft_matrix.yx = (signed long)(pMatrix->b * font_size / 64 * 65536);
1472         ft_matrix.yy = (signed long)(pMatrix->d * font_size / 64 * 65536);
1473     } else {
1474         ft_matrix.xx = (signed long)(font_size / 64 * 65536);
1475         ft_matrix.xy = ft_matrix.yx = 0;
1476         ft_matrix.yy = (signed long)(font_size / 64 * 65536);
1477     }
1478     FXFT_Set_Transform(pFont->m_Face, &ft_matrix, 0);
1479     FX_BOOL ret = _OutputGlyph(dib, x, y, pFont,
1480                                glyph_index, argb);
1481     return ret;
1482 }
1483 const CFX_PathData* CFX_FaceCache::LoadGlyphPath(CFX_Font* pFont, FX_DWORD glyph_index, int dest_width)
1484 {
1485     if (m_Face == NULL || glyph_index == (FX_DWORD) - 1) {
1486         return NULL;
1487     }
1488     CFX_PathData* pGlyphPath = NULL;
1489     FX_LPVOID key;
1490     if (pFont->GetSubstFont())
1491         key = (FX_LPVOID)(FX_UINTPTR)(glyph_index + ((pFont->GetSubstFont()->m_Weight / 16) << 15) +
1492                                       ((pFont->GetSubstFont()->m_ItalicAngle / 2) << 21) + ((dest_width / 16) << 25) +
1493                                       (pFont->IsVertical() << 31));
1494     else {
1495         key = (FX_LPVOID)(FX_UINTPTR)glyph_index;
1496     }
1497     if (m_PathMap.Lookup(key, (FX_LPVOID&)pGlyphPath)) {
1498         return pGlyphPath;
1499     }
1500     pGlyphPath = pFont->LoadGlyphPath(glyph_index, dest_width);
1501     m_PathMap.SetAt(key, pGlyphPath);
1502     return pGlyphPath;
1503 }
1504 typedef struct {
1505     FX_BOOL                     m_bCount;
1506     int                         m_PointCount;
1507     FX_PATHPOINT*       m_pPoints;
1508     int                         m_CurX;
1509     int                         m_CurY;
1510     FX_FLOAT            m_CoordUnit;
1511 } OUTLINE_PARAMS;
1512 void _Outline_CheckEmptyContour(OUTLINE_PARAMS* param)
1513 {
1514     if (param->m_PointCount >= 2 && param->m_pPoints[param->m_PointCount - 2].m_Flag == FXPT_MOVETO &&
1515             param->m_pPoints[param->m_PointCount - 2].m_PointX == param->m_pPoints[param->m_PointCount - 1].m_PointX &&
1516             param->m_pPoints[param->m_PointCount - 2].m_PointY == param->m_pPoints[param->m_PointCount - 1].m_PointY) {
1517         param->m_PointCount -= 2;
1518     }
1519     if (param->m_PointCount >= 4 && param->m_pPoints[param->m_PointCount - 4].m_Flag == FXPT_MOVETO &&
1520             param->m_pPoints[param->m_PointCount - 3].m_Flag == FXPT_BEZIERTO &&
1521             param->m_pPoints[param->m_PointCount - 3].m_PointX == param->m_pPoints[param->m_PointCount - 4].m_PointX &&
1522             param->m_pPoints[param->m_PointCount - 3].m_PointY == param->m_pPoints[param->m_PointCount - 4].m_PointY &&
1523             param->m_pPoints[param->m_PointCount - 2].m_PointX == param->m_pPoints[param->m_PointCount - 4].m_PointX &&
1524             param->m_pPoints[param->m_PointCount - 2].m_PointY == param->m_pPoints[param->m_PointCount - 4].m_PointY &&
1525             param->m_pPoints[param->m_PointCount - 1].m_PointX == param->m_pPoints[param->m_PointCount - 4].m_PointX &&
1526             param->m_pPoints[param->m_PointCount - 1].m_PointY == param->m_pPoints[param->m_PointCount - 4].m_PointY) {
1527         param->m_PointCount -= 4;
1528     }
1529 }
1530 extern "C" {
1531     static int _Outline_MoveTo(const FXFT_Vector* to, void* user)
1532     {
1533         OUTLINE_PARAMS* param = (OUTLINE_PARAMS*)user;
1534         if (!param->m_bCount) {
1535             _Outline_CheckEmptyContour(param);
1536             param->m_pPoints[param->m_PointCount].m_PointX = to->x / param->m_CoordUnit;
1537             param->m_pPoints[param->m_PointCount].m_PointY = to->y / param->m_CoordUnit;
1538             param->m_pPoints[param->m_PointCount].m_Flag = FXPT_MOVETO;
1539             param->m_CurX = to->x;
1540             param->m_CurY = to->y;
1541             if (param->m_PointCount) {
1542                 param->m_pPoints[param->m_PointCount - 1].m_Flag |= FXPT_CLOSEFIGURE;
1543             }
1544         }
1545         param->m_PointCount ++;
1546         return 0;
1547     }
1548 };
1549 extern "C" {
1550     static int _Outline_LineTo(const FXFT_Vector* to, void* user)
1551     {
1552         OUTLINE_PARAMS* param = (OUTLINE_PARAMS*)user;
1553         if (!param->m_bCount) {
1554             param->m_pPoints[param->m_PointCount].m_PointX = to->x / param->m_CoordUnit;
1555             param->m_pPoints[param->m_PointCount].m_PointY = to->y / param->m_CoordUnit;
1556             param->m_pPoints[param->m_PointCount].m_Flag = FXPT_LINETO;
1557             param->m_CurX = to->x;
1558             param->m_CurY = to->y;
1559         }
1560         param->m_PointCount ++;
1561         return 0;
1562     }
1563 };
1564 extern "C" {
1565     static int _Outline_ConicTo(const FXFT_Vector* control, const FXFT_Vector* to, void* user)
1566     {
1567         OUTLINE_PARAMS* param = (OUTLINE_PARAMS*)user;
1568         if (!param->m_bCount) {
1569             param->m_pPoints[param->m_PointCount].m_PointX = (param->m_CurX + (control->x - param->m_CurX) * 2 / 3) / param->m_CoordUnit;
1570             param->m_pPoints[param->m_PointCount].m_PointY = (param->m_CurY + (control->y - param->m_CurY) * 2 / 3) / param->m_CoordUnit;
1571             param->m_pPoints[param->m_PointCount].m_Flag = FXPT_BEZIERTO;
1572             param->m_pPoints[param->m_PointCount + 1].m_PointX = (control->x + (to->x - control->x) / 3) / param->m_CoordUnit;
1573             param->m_pPoints[param->m_PointCount + 1].m_PointY = (control->y + (to->y - control->y) / 3) / param->m_CoordUnit;
1574             param->m_pPoints[param->m_PointCount + 1].m_Flag = FXPT_BEZIERTO;
1575             param->m_pPoints[param->m_PointCount + 2].m_PointX = to->x / param->m_CoordUnit;
1576             param->m_pPoints[param->m_PointCount + 2].m_PointY = to->y / param->m_CoordUnit;
1577             param->m_pPoints[param->m_PointCount + 2].m_Flag = FXPT_BEZIERTO;
1578             param->m_CurX = to->x;
1579             param->m_CurY = to->y;
1580         }
1581         param->m_PointCount += 3;
1582         return 0;
1583     }
1584 };
1585 extern "C" {
1586     static int _Outline_CubicTo(const FXFT_Vector* control1, const FXFT_Vector* control2, const FXFT_Vector* to, void* user)
1587     {
1588         OUTLINE_PARAMS* param = (OUTLINE_PARAMS*)user;
1589         if (!param->m_bCount) {
1590             param->m_pPoints[param->m_PointCount].m_PointX = control1->x / param->m_CoordUnit;
1591             param->m_pPoints[param->m_PointCount].m_PointY = control1->y / param->m_CoordUnit;
1592             param->m_pPoints[param->m_PointCount].m_Flag = FXPT_BEZIERTO;
1593             param->m_pPoints[param->m_PointCount + 1].m_PointX = control2->x / param->m_CoordUnit;
1594             param->m_pPoints[param->m_PointCount + 1].m_PointY = control2->y / param->m_CoordUnit;
1595             param->m_pPoints[param->m_PointCount + 1].m_Flag = FXPT_BEZIERTO;
1596             param->m_pPoints[param->m_PointCount + 2].m_PointX = to->x / param->m_CoordUnit;
1597             param->m_pPoints[param->m_PointCount + 2].m_PointY = to->y / param->m_CoordUnit;
1598             param->m_pPoints[param->m_PointCount + 2].m_Flag = FXPT_BEZIERTO;
1599             param->m_CurX = to->x;
1600             param->m_CurY = to->y;
1601         }
1602         param->m_PointCount += 3;
1603         return 0;
1604     }
1605 };
1606 CFX_PathData* CFX_Font::LoadGlyphPath(FX_DWORD glyph_index, int dest_width)
1607 {
1608     if (m_Face == NULL) {
1609         return NULL;
1610     }
1611     FXFT_Set_Pixel_Sizes(m_Face, 0, 64);
1612     FXFT_Matrix  ft_matrix = {65536, 0, 0, 65536};
1613     if (m_pSubstFont) {
1614         if (m_pSubstFont->m_ItalicAngle) {
1615             int skew = m_pSubstFont->m_ItalicAngle;
1616             skew = skew <= -ANGLESKEW_ARRAY_SIZE ? -58 : -g_AngleSkew[-skew];
1617             if (m_bVertical) {
1618                 ft_matrix.yx += ft_matrix.yy * skew / 100;
1619             } else {
1620                 ft_matrix.xy += -ft_matrix.xx * skew / 100;
1621             }
1622         }
1623         if (m_pSubstFont->m_SubstFlags & FXFONT_SUBST_MM) {
1624             AdjustMMParams(glyph_index, dest_width, m_pSubstFont->m_Weight);
1625         }
1626     }
1627     FXFT_Set_Transform(m_Face, &ft_matrix, 0);
1628     int load_flags = (m_Face->face_flags & FT_FACE_FLAG_SFNT) ? FXFT_LOAD_NO_BITMAP : FXFT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING;
1629     int error = FXFT_Load_Glyph(m_Face, glyph_index, load_flags);
1630     if (error) {
1631         return NULL;
1632     }
1633     if (m_pSubstFont && !(m_pSubstFont->m_SubstFlags & FXFONT_SUBST_MM) && m_pSubstFont->m_Weight > 400) {
1634         int index = (m_pSubstFont->m_Weight - 400) / 10;
1635         if (index >= WEIGHTPOW_ARRAY_SIZE)
1636             index = WEIGHTPOW_ARRAY_SIZE - 1;
1637         int level = 0;
1638         if (m_pSubstFont->m_Charset == FXFONT_SHIFTJIS_CHARSET) {
1639             level = g_WeightPow_SHIFTJIS[index] * 2 * 65536 / 36655;
1640         } else {
1641             level = g_WeightPow[index] * 2;
1642         }
1643         FXFT_Outline_Embolden(FXFT_Get_Glyph_Outline(m_Face), level);
1644     }
1645     FXFT_Outline_Funcs funcs;
1646     funcs.move_to = _Outline_MoveTo;
1647     funcs.line_to = _Outline_LineTo;
1648     funcs.conic_to = _Outline_ConicTo;
1649     funcs.cubic_to = _Outline_CubicTo;
1650     funcs.shift = 0;
1651     funcs.delta = 0;
1652     OUTLINE_PARAMS params;
1653     params.m_bCount = TRUE;
1654     params.m_PointCount = 0;
1655     FXFT_Outline_Decompose(FXFT_Get_Glyph_Outline(m_Face), &funcs, &params);
1656     if (params.m_PointCount == 0) {
1657         return NULL;
1658     }
1659     CFX_PathData* pPath = new CFX_PathData;
1660     pPath->SetPointCount(params.m_PointCount);
1661     params.m_bCount = FALSE;
1662     params.m_PointCount = 0;
1663     params.m_pPoints = pPath->GetPoints();
1664     params.m_CurX = params.m_CurY = 0;
1665     params.m_CoordUnit = 64 * 64.0;
1666     FXFT_Outline_Decompose(FXFT_Get_Glyph_Outline(m_Face), &funcs, &params);
1667     _Outline_CheckEmptyContour(&params);
1668     pPath->TrimPoints(params.m_PointCount);
1669     if (params.m_PointCount) {
1670         pPath->GetPoints()[params.m_PointCount - 1].m_Flag |= FXPT_CLOSEFIGURE;
1671     }
1672     return pPath;
1673 }
1674 void _CFX_UniqueKeyGen::Generate(int count, ...)
1675 {
1676     va_list argList;
1677     va_start(argList, count);
1678     for (int i = 0; i < count; i ++) {
1679         int p = va_arg(argList, int);
1680         ((FX_DWORD*)m_Key)[i] = p;
1681     }
1682     va_end(argList);
1683     m_KeyLen = count * sizeof(FX_DWORD);
1684 }