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