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