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