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