1 // Copyright 2014 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
7 #include "../../../include/fxge/fx_ge.h"
8 #include "../../../include/fxge/fx_freetype.h"
9 #include "../../../include/fxcodec/fx_codec.h"
12 #undef FX_GAMMA_INVERSE
13 #define FX_GAMMA(value) (value)
14 #define FX_GAMMA_INVERSE(value) (value)
18 void ResetTransform(FT_Face face) {
24 FXFT_Set_Transform(face, &matrix, 0);
27 // Sets the given transform on the font, and resets it to the identity when it
29 class ScopedFontTransform
32 ScopedFontTransform(FT_Face face, FXFT_Matrix* matrix) : m_Face(face) {
33 FXFT_Set_Transform(m_Face, matrix, 0);
36 ~ScopedFontTransform() {
37 ResetTransform(m_Face);
46 FX_RECT FXGE_GetGlyphsBBox(FXTEXT_GLYPHPOS* pGlyphAndPos, int nChars, int anti_alias, FX_FLOAT retinaScaleX, FX_FLOAT retinaScaleY)
48 FX_RECT rect(0, 0, 0, 0);
49 FX_BOOL bStarted = FALSE;
50 for (int iChar = 0; iChar < nChars; iChar ++) {
51 FXTEXT_GLYPHPOS& glyph = pGlyphAndPos[iChar];
52 const CFX_GlyphBitmap* pGlyph = glyph.m_pGlyph;
56 int char_left = glyph.m_OriginX + pGlyph->m_Left;
57 int char_width = (int)(pGlyph->m_Bitmap.GetWidth() / retinaScaleX);
58 if (anti_alias == FXFT_RENDER_MODE_LCD) {
61 int char_right = char_left + char_width;
62 int char_top = glyph.m_OriginY - pGlyph->m_Top;
63 int char_bottom = char_top + (int)(pGlyph->m_Bitmap.GetHeight() / retinaScaleY);
65 rect.left = char_left;
66 rect.right = char_right;
68 rect.bottom = char_bottom;
71 if (rect.left > char_left) {
72 rect.left = char_left;
74 if (rect.right < char_right) {
75 rect.right = char_right;
77 if (rect.top > char_top) {
80 if (rect.bottom < char_bottom) {
81 rect.bottom = char_bottom;
87 static void _AdjustGlyphSpace(FXTEXT_GLYPHPOS* pGlyphAndPos, int nChars)
90 FX_BOOL bVertical = FALSE;
91 if (pGlyphAndPos[nChars - 1].m_OriginX == pGlyphAndPos[0].m_OriginX) {
93 } else if (pGlyphAndPos[nChars - 1].m_OriginY != pGlyphAndPos[0].m_OriginY) {
97 int* next_origin = bVertical ? &pGlyphAndPos[i].m_OriginY : &pGlyphAndPos[i].m_OriginX;
98 FX_FLOAT next_origin_f = bVertical ? pGlyphAndPos[i].m_fOriginY : pGlyphAndPos[i].m_fOriginX;
99 for (i --; i > 0; i --) {
100 int* this_origin = bVertical ? &pGlyphAndPos[i].m_OriginY : &pGlyphAndPos[i].m_OriginX;
101 FX_FLOAT this_origin_f = bVertical ? pGlyphAndPos[i].m_fOriginY : pGlyphAndPos[i].m_fOriginX;
102 int space = (*next_origin) - (*this_origin);
103 FX_FLOAT space_f = next_origin_f - this_origin_f;
104 FX_FLOAT error = (FX_FLOAT)(FXSYS_fabs(space_f) - FXSYS_fabs((FX_FLOAT)(space)));
106 *this_origin += space > 0 ? -1 : 1;
108 next_origin = this_origin;
109 next_origin_f = this_origin_f;
112 static const uint8_t g_TextGammaAdjust[256] = {
113 0, 2, 3, 4, 6, 7, 8, 10, 11, 12, 13, 15, 16, 17, 18, 19,
114 21, 22, 23, 24, 25, 26, 27, 29, 30, 31, 32, 33, 34, 35, 36, 38,
115 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 51, 52, 53, 54, 55,
116 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 71, 72,
117 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88,
118 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104,
119 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120,
120 121, 122, 123, 124, 125, 126, 127, 128, 129, 129, 130, 131, 132, 133, 134, 135,
121 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151,
122 152, 153, 154, 155, 156, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166,
123 167, 168, 169, 170, 171, 172, 173, 174, 174, 175, 176, 177, 178, 179, 180, 181,
124 182, 183, 184, 185, 186, 187, 188, 189, 190, 190, 191, 192, 193, 194, 195, 196,
125 197, 198, 199, 200, 201, 202, 203, 204, 204, 205, 206, 207, 208, 209, 210, 211,
126 212, 213, 214, 215, 216, 217, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226,
127 227, 228, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 239, 240,
128 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 250, 251, 252, 253, 254, 255,
130 #define ADJUST_ALPHA(background, foreground, src_alpha, text_flags, a) \
131 src_alpha = g_TextGammaAdjust[(uint8_t)src_alpha];
132 void _Color2Argb(FX_ARGB& argb, FX_DWORD color, int alpha_flag, void* pIccTransform)
134 if (pIccTransform == NULL && !FXGETFLAG_COLORTYPE(alpha_flag)) {
138 if (!CFX_GEModule::Get()->GetCodecModule() || !CFX_GEModule::Get()->GetCodecModule()->GetIccModule()) {
139 pIccTransform = NULL;
143 ICodec_IccModule* pIccModule = CFX_GEModule::Get()->GetCodecModule()->GetIccModule();
144 color = FXGETFLAG_COLORTYPE(alpha_flag) ? FXCMYK_TODIB(color) : FXARGB_TODIB(color);
145 pIccModule->TranslateScanline(pIccTransform, bgra, (const uint8_t*)&color, 1);
146 bgra[3] = FXGETFLAG_COLORTYPE(alpha_flag) ?
147 (alpha_flag >> 24) ? FXGETFLAG_ALPHA_FILL(alpha_flag) : FXGETFLAG_ALPHA_STROKE(alpha_flag) :
149 argb = FXARGB_MAKE(bgra[3], bgra[2], bgra[1], bgra[0]);
152 AdobeCMYK_to_sRGB1(FXSYS_GetCValue(color), FXSYS_GetMValue(color),
153 FXSYS_GetYValue(color), FXSYS_GetKValue(color),
154 bgra[2], bgra[1], bgra[0]);
155 bgra[3] = (alpha_flag >> 24) ? FXGETFLAG_ALPHA_FILL(alpha_flag) : FXGETFLAG_ALPHA_STROKE(alpha_flag);
156 argb = FXARGB_MAKE(bgra[3], bgra[2], bgra[1], bgra[0]);
158 FX_BOOL CFX_RenderDevice::DrawNormalText(int nChars, const FXTEXT_CHARPOS* pCharPos,
159 CFX_Font* pFont, CFX_FontCache* pCache,
160 FX_FLOAT font_size, const CFX_AffineMatrix* pText2Device,
161 FX_DWORD fill_color, FX_DWORD text_flags,
162 int alpha_flag, void* pIccTransform)
164 int nativetext_flags = text_flags;
165 if (m_DeviceClass != FXDC_DISPLAY) {
166 if (!(text_flags & FXTEXT_PRINTGRAPHICTEXT)) {
167 #if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
168 if (!(text_flags & FXFONT_CIDFONT) && pFont->GetPsName().Find(CFX_WideString::FromLocal("+ZJHL")) == -1)
169 #ifdef FOXIT_CHROME_BUILD
170 if (pFont->GetPsName() != CFX_WideString::FromLocal("CNAAJI+cmex10"))
173 if (m_pDeviceDriver->DrawDeviceText(nChars, pCharPos, pFont, pCache, pText2Device, font_size, fill_color, alpha_flag, pIccTransform)) {
177 int alpha = FXGETFLAG_COLORTYPE(alpha_flag) ? FXGETFLAG_ALPHA_FILL(alpha_flag) : FXARGB_A(fill_color);
181 } else if (!(text_flags & FXTEXT_NO_NATIVETEXT)) {
182 #if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
183 if (!(text_flags & FXFONT_CIDFONT))
184 #ifdef FOXIT_CHROME_BUILD
185 if (pFont->GetPsName() != CFX_WideString::FromLocal("CNAAJI+cmex10"))
188 if (m_pDeviceDriver->DrawDeviceText(nChars, pCharPos, pFont, pCache, pText2Device, font_size, fill_color, alpha_flag, pIccTransform)) {
192 CFX_AffineMatrix char2device, deviceCtm, text2Device;
194 char2device = *pText2Device;
195 text2Device = *pText2Device;
197 char2device.Scale(font_size, -font_size);
198 if (FXSYS_fabs(char2device.a) + FXSYS_fabs(char2device.b) > 50 * 1.0f ||
199 ((m_DeviceClass == FXDC_PRINTER && !m_pDeviceDriver->IsPSPrintDriver())
200 && !(text_flags & FXTEXT_PRINTIMAGETEXT))) {
201 if (pFont->GetFace() != NULL || (pFont->GetSubstFont()->m_SubstFlags & FXFONT_SUBST_GLYPHPATH)) {
202 int nPathFlags = (text_flags & FXTEXT_NOSMOOTH) == 0 ? 0 : FXFILL_NOPATHSMOOTH;
203 return DrawTextPath(nChars, pCharPos, pFont, pCache, font_size, pText2Device, NULL, NULL, fill_color, 0, NULL, nPathFlags, alpha_flag, pIccTransform);
206 int anti_alias = FXFT_RENDER_MODE_MONO;
207 FX_BOOL bNormal = FALSE;
208 if ((text_flags & FXTEXT_NOSMOOTH) == 0) {
209 if (m_DeviceClass == FXDC_DISPLAY && m_bpp > 1) {
211 if (pFont->GetFace() == NULL && !(pFont->GetSubstFont()->m_SubstFlags & FXFONT_SUBST_CLEARTYPE)) {
214 bClearType = text_flags & FXTEXT_CLEARTYPE;
216 if ((m_RenderCaps & (FXRC_ALPHA_OUTPUT | FXRC_CMYK_OUTPUT))) {
217 anti_alias = FXFT_RENDER_MODE_LCD;
219 } else if (m_bpp < 16) {
220 anti_alias = FXFT_RENDER_MODE_NORMAL;
222 if (bClearType == FALSE) {
223 anti_alias = FXFT_RENDER_MODE_LCD;
226 anti_alias = FXFT_RENDER_MODE_LCD;
231 if (pCache == NULL) {
232 pCache = CFX_GEModule::Get()->GetFontCache();
234 CFX_FaceCache* pFaceCache = pCache->GetCachedFace(pFont);
235 FX_FONTCACHE_DEFINE(pCache, pFont);
236 FXTEXT_GLYPHPOS* pGlyphAndPos = FX_Alloc(FXTEXT_GLYPHPOS, nChars);
238 deviceCtm = char2device;
239 CFX_AffineMatrix matrixCTM = GetCTM();
240 FX_FLOAT scale_x = FXSYS_fabs(matrixCTM.a);
241 FX_FLOAT scale_y = FXSYS_fabs(matrixCTM.d);
242 deviceCtm.Concat(scale_x, 0, 0, scale_y, 0, 0);
243 text2Device.Concat(scale_x, 0, 0, scale_y, 0, 0);
244 for (iChar = 0; iChar < nChars; iChar ++) {
245 FXTEXT_GLYPHPOS& glyph = pGlyphAndPos[iChar];
246 const FXTEXT_CHARPOS& charpos = pCharPos[iChar];
247 glyph.m_fOriginX = charpos.m_OriginX;
248 glyph.m_fOriginY = charpos.m_OriginY;
249 text2Device.Transform(glyph.m_fOriginX, glyph.m_fOriginY);
250 if (anti_alias < FXFT_RENDER_MODE_LCD) {
251 glyph.m_OriginX = FXSYS_round(glyph.m_fOriginX);
253 glyph.m_OriginX = (int)FXSYS_floor(glyph.m_fOriginX);
255 glyph.m_OriginY = FXSYS_round(glyph.m_fOriginY);
256 if (charpos.m_bGlyphAdjust) {
257 CFX_AffineMatrix new_matrix(charpos.m_AdjustMatrix[0], charpos.m_AdjustMatrix[1],
258 charpos.m_AdjustMatrix[2], charpos.m_AdjustMatrix[3], 0, 0);
259 new_matrix.Concat(deviceCtm);
260 glyph.m_pGlyph = pFaceCache->LoadGlyphBitmap(pFont, charpos.m_GlyphIndex, charpos.m_bFontStyle, &new_matrix,
261 charpos.m_FontCharWidth, anti_alias, nativetext_flags);
263 glyph.m_pGlyph = pFaceCache->LoadGlyphBitmap(pFont, charpos.m_GlyphIndex, charpos.m_bFontStyle, &deviceCtm,
264 charpos.m_FontCharWidth, anti_alias, nativetext_flags);
266 if (anti_alias < FXFT_RENDER_MODE_LCD && nChars > 1) {
267 _AdjustGlyphSpace(pGlyphAndPos, nChars);
269 FX_RECT bmp_rect1 = FXGE_GetGlyphsBBox(pGlyphAndPos, nChars, anti_alias);
270 if (scale_x > 1 && scale_y > 1) {
276 FX_RECT bmp_rect(FXSYS_round((FX_FLOAT)(bmp_rect1.left) / scale_x), FXSYS_round((FX_FLOAT)(bmp_rect1.top) / scale_y),
277 FXSYS_round((FX_FLOAT)bmp_rect1.right / scale_x), FXSYS_round((FX_FLOAT)bmp_rect1.bottom / scale_y));
278 bmp_rect.Intersect(m_ClipBox);
279 if (bmp_rect.IsEmpty()) {
280 FX_Free(pGlyphAndPos);
283 int pixel_width = FXSYS_round(bmp_rect.Width() * scale_x);
284 int pixel_height = FXSYS_round(bmp_rect.Height() * scale_y);
285 int pixel_left = FXSYS_round(bmp_rect.left * scale_x);
286 int pixel_top = FXSYS_round(bmp_rect.top * scale_y);
287 if (anti_alias == FXFT_RENDER_MODE_MONO) {
289 if (!bitmap.Create(pixel_width, pixel_height, FXDIB_1bppMask)) {
290 FX_Free(pGlyphAndPos);
294 for (iChar = 0; iChar < nChars; iChar ++) {
295 FXTEXT_GLYPHPOS& glyph = pGlyphAndPos[iChar];
296 if (glyph.m_pGlyph == NULL) {
299 const CFX_DIBitmap* pGlyph = &glyph.m_pGlyph->m_Bitmap;
300 bitmap.TransferBitmap(glyph.m_OriginX + glyph.m_pGlyph->m_Left - pixel_left,
301 glyph.m_OriginY - glyph.m_pGlyph->m_Top - pixel_top,
302 pGlyph->GetWidth(), pGlyph->GetHeight(), pGlyph, 0, 0);
304 FX_Free(pGlyphAndPos);
305 return SetBitMask(&bitmap, bmp_rect.left, bmp_rect.top, fill_color);
309 if (!bitmap.Create(pixel_width, pixel_height, FXDIB_8bppMask)) {
310 FX_Free(pGlyphAndPos);
314 if (!CreateCompatibleBitmap(&bitmap, pixel_width, pixel_height)) {
315 FX_Free(pGlyphAndPos);
319 if (!bitmap.HasAlpha() && !bitmap.IsAlphaMask()) {
320 bitmap.Clear(0xFFFFFFFF);
321 if (!GetDIBits(&bitmap, bmp_rect.left, bmp_rect.top)) {
322 FX_Free(pGlyphAndPos);
327 if (bitmap.m_pAlphaMask) {
328 bitmap.m_pAlphaMask->Clear(0);
331 int dest_width = pixel_width;
332 uint8_t* dest_buf = bitmap.GetBuffer();
333 int dest_pitch = bitmap.GetPitch();
334 int Bpp = bitmap.GetBPP() / 8;
336 if (anti_alias == FXFT_RENDER_MODE_LCD) {
337 _Color2Argb(fill_color, fill_color, alpha_flag | (1 << 24), pIccTransform);
338 ArgbDecode(fill_color, a, r, g, b);
343 for (iChar = 0; iChar < nChars; iChar ++) {
344 FXTEXT_GLYPHPOS& glyph = pGlyphAndPos[iChar];
345 if (glyph.m_pGlyph == NULL) {
348 const CFX_DIBitmap* pGlyph = &glyph.m_pGlyph->m_Bitmap;
349 int left = glyph.m_OriginX + glyph.m_pGlyph->m_Left - pixel_left;
350 int top = glyph.m_OriginY - glyph.m_pGlyph->m_Top - pixel_top;
351 int ncols = pGlyph->GetWidth();
352 int nrows = pGlyph->GetHeight();
353 if (anti_alias == FXFT_RENDER_MODE_NORMAL) {
354 if (!bitmap.CompositeMask(left, top, ncols, nrows, pGlyph, fill_color,
355 0, 0, FXDIB_BLEND_NORMAL, NULL, FALSE, alpha_flag, pIccTransform)) {
356 FX_Free(pGlyphAndPos);
361 FX_BOOL bBGRStripe = text_flags & FXTEXT_BGR_STRIPE;
363 int x_subpixel = (int)(glyph.m_fOriginX * 3) % 3;
364 uint8_t* src_buf = pGlyph->GetBuffer();
365 int src_pitch = pGlyph->GetPitch();
366 int start_col = left;
370 int end_col = left + ncols;
371 if (end_col > dest_width) {
372 end_col = dest_width;
374 if (start_col >= end_col) {
377 if (bitmap.GetFormat() == FXDIB_Argb) {
378 for (int row = 0; row < nrows; row ++) {
379 int dest_row = row + top;
380 if (dest_row < 0 || dest_row >= bitmap.GetHeight()) {
383 uint8_t* src_scan = src_buf + row * src_pitch + (start_col - left) * 3;
384 uint8_t* dest_scan = dest_buf + dest_row * dest_pitch + (start_col << 2);
386 if (x_subpixel == 0) {
387 for (int col = start_col; col < end_col; col ++) {
388 int src_alpha = src_scan[2];
389 src_alpha = src_alpha * a / 255;
390 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
391 src_alpha = src_scan[1];
392 src_alpha = src_alpha * a / 255;
393 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
394 src_alpha = src_scan[0];
395 src_alpha = src_alpha * a / 255;
396 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
401 } else if (x_subpixel == 1) {
402 int src_alpha = src_scan[1];
403 ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
404 src_alpha = src_alpha * a / 255;
405 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
406 src_alpha = src_scan[0];
407 ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
408 src_alpha = src_alpha * a / 255;
409 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
410 if (start_col > left) {
411 src_alpha = src_scan[-1];
412 ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
413 src_alpha = src_alpha * a / 255;
414 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
419 for (int col = start_col + 1; col < end_col - 1; col ++) {
420 int src_alpha = src_scan[1];
421 ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
422 src_alpha = src_alpha * a / 255;
423 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
424 src_alpha = src_scan[0];
425 ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
426 src_alpha = src_alpha * a / 255;
427 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
428 src_alpha = src_scan[-1];
429 ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
430 src_alpha = src_alpha * a / 255;
431 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
437 int src_alpha = src_scan[0];
438 ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
439 src_alpha = src_alpha * a / 255;
440 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
441 if (start_col > left) {
442 src_alpha = src_scan[-1];
443 ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
444 src_alpha = src_alpha * a / 255;
445 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
446 src_alpha = src_scan[-2];
447 ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
448 src_alpha = src_alpha * a / 255;
449 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
454 for (int col = start_col + 1; col < end_col - 1; col ++) {
455 int src_alpha = src_scan[0];
456 ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
457 src_alpha = src_alpha * a / 255;
458 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
459 src_alpha = src_scan[-1];
460 ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
461 src_alpha = src_alpha * a / 255;
462 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
463 src_alpha = src_scan[-2];
464 ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
465 src_alpha = src_alpha * a / 255;
466 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
473 if (x_subpixel == 0) {
474 for (int col = start_col; col < end_col; col ++) {
476 int src_alpha1 = (src_scan[0] + src_scan[1] + src_scan[2]) / 3;
477 ADJUST_ALPHA(dest_scan[2], r, src_alpha1, nativetext_flags, a);
478 src_alpha1 = src_alpha1 * a / 255;
479 uint8_t back_alpha = dest_scan[3];
480 if (back_alpha == 0) {
481 FXARGB_SETDIB(dest_scan, FXARGB_MAKE(src_alpha1, r, g, b));
486 if (src_alpha1 == 0) {
491 uint8_t dest_alpha = back_alpha + src_alpha1 - back_alpha * src_alpha1 / 255;
492 dest_scan[3] = dest_alpha;
493 int alpha_ratio = src_alpha1 * 255 / dest_alpha;
494 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, alpha_ratio));
495 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, alpha_ratio));
496 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, alpha_ratio));
501 int src_alpha = src_scan[0];
502 ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
503 src_alpha = src_alpha * a / 255;
504 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
505 src_alpha = src_scan[1];
506 ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
507 src_alpha = src_alpha * a / 255;
508 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
509 src_alpha = src_scan[2];
510 ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
511 src_alpha = src_alpha * a / 255;
512 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
517 } else if (x_subpixel == 1) {
519 int src_alpha1 = start_col > left ? ((src_scan[-1] + src_scan[0] + src_scan[1]) / 3) : ((src_scan[0] + src_scan[1]) / 3);
520 ADJUST_ALPHA(dest_scan[2], r, src_alpha1, nativetext_flags, a);
521 src_alpha1 = src_alpha1 * a / 255;
522 if (src_alpha1 == 0) {
526 uint8_t back_alpha = dest_scan[3];
527 if (back_alpha == 0) {
528 FXARGB_SETDIB(dest_scan, FXARGB_MAKE(src_alpha1, r, g, b));
530 uint8_t dest_alpha = back_alpha + src_alpha1 - back_alpha * src_alpha1 / 255;
531 dest_scan[3] = dest_alpha;
532 int alpha_ratio = src_alpha1 * 255 / dest_alpha;
533 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, alpha_ratio));
534 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, alpha_ratio));
535 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, alpha_ratio));
541 if (start_col > left) {
542 int src_alpha = src_scan[-1];
543 ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
544 src_alpha = src_alpha * a / 255;
545 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
547 int src_alpha = src_scan[0];
548 ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
549 src_alpha = src_alpha * a / 255;
550 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
551 src_alpha = src_scan[1];
552 ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
553 src_alpha = src_alpha * a / 255;
554 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
559 for (int col = start_col + 1; col < end_col; col ++) {
561 int src_alpha1 = (src_scan[-1] + src_scan[0] + src_scan[1]) / 3;
562 ADJUST_ALPHA(dest_scan[2], r, src_alpha1, nativetext_flags, a);
563 src_alpha1 = src_alpha1 * a / 255;
564 uint8_t back_alpha = dest_scan[3];
565 if (back_alpha == 0) {
566 FXARGB_SETDIB(dest_scan, FXARGB_MAKE(src_alpha1, r, g, b));
571 if (src_alpha1 == 0) {
576 uint8_t dest_alpha = back_alpha + src_alpha1 - back_alpha * src_alpha1 / 255;
577 dest_scan[3] = dest_alpha;
578 int alpha_ratio = src_alpha1 * 255 / dest_alpha;
579 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, alpha_ratio));
580 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, alpha_ratio));
581 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, alpha_ratio));
586 int src_alpha = src_scan[-1];
587 ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
588 src_alpha = src_alpha * a / 255;
589 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
590 src_alpha = src_scan[0];
591 ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
592 src_alpha = src_alpha * a / 255;
593 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
594 src_alpha = src_scan[1];
595 ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
596 src_alpha = src_alpha * a / 255;
597 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
604 int src_alpha1 = start_col > left ? ((src_scan[-2] + src_scan[-1] + src_scan[0]) / 3) : ((src_scan[0]) / 3);
605 ADJUST_ALPHA(dest_scan[2], r, src_alpha1, nativetext_flags, a);
606 src_alpha1 = src_alpha1 * a / 255;
607 if (src_alpha1 == 0) {
611 uint8_t back_alpha = dest_scan[3];
612 if (back_alpha == 0) {
613 FXARGB_SETDIB(dest_scan, FXARGB_MAKE(src_alpha1, r, g, b));
615 uint8_t dest_alpha = back_alpha + src_alpha1 - back_alpha * src_alpha1 / 255;
616 dest_scan[3] = dest_alpha;
617 int alpha_ratio = src_alpha1 * 255 / dest_alpha;
618 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, alpha_ratio));
619 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, alpha_ratio));
620 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, alpha_ratio));
626 if (start_col > left) {
627 int src_alpha = src_scan[-2];
628 ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
629 src_alpha = src_alpha * a / 255;
630 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
631 src_alpha = src_scan[-1];
632 ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
633 src_alpha = src_alpha * a / 255;
634 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
636 int src_alpha = src_scan[0];
637 ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
638 src_alpha = src_alpha * a / 255;
639 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
644 for (int col = start_col + 1; col < end_col; col ++) {
646 int src_alpha1 = (src_scan[-2] + src_scan[-1] + src_scan[0]) / 3;
647 ADJUST_ALPHA(dest_scan[2], r, src_alpha1, nativetext_flags, a);
648 src_alpha1 = src_alpha1 * a / 255;
649 uint8_t back_alpha = dest_scan[3];
650 if (back_alpha == 0) {
651 FXARGB_SETDIB(dest_scan, FXARGB_MAKE(src_alpha1, r, g, b));
656 if (src_alpha1 == 0) {
661 uint8_t dest_alpha = back_alpha + src_alpha1 - back_alpha * src_alpha1 / 255;
662 dest_scan[3] = dest_alpha;
663 int alpha_ratio = src_alpha1 * 255 / dest_alpha;
664 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, alpha_ratio));
665 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, alpha_ratio));
666 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, alpha_ratio));
671 int src_alpha = src_scan[-2];
672 ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
673 src_alpha = src_alpha * a / 255;
674 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
675 src_alpha = src_scan[-1];
676 ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
677 src_alpha = src_alpha * a / 255;
678 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
679 src_alpha = src_scan[0];
680 ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
681 src_alpha = src_alpha * a / 255;
682 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
691 for (int row = 0; row < nrows; row ++) {
692 int dest_row = row + top;
693 if (dest_row < 0 || dest_row >= bitmap.GetHeight()) {
696 uint8_t* src_scan = src_buf + row * src_pitch + (start_col - left) * 3;
697 uint8_t* dest_scan = dest_buf + dest_row * dest_pitch + start_col * Bpp;
699 if (x_subpixel == 0) {
700 for (int col = start_col; col < end_col; col ++) {
701 int src_alpha = src_scan[2];
702 ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
703 src_alpha = src_alpha * a / 255;
704 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
705 src_alpha = src_scan[1];
706 ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
707 src_alpha = src_alpha * a / 255;
708 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
709 src_alpha = src_scan[0];
710 ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
711 src_alpha = src_alpha * a / 255;
712 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
716 } else if (x_subpixel == 1) {
717 int src_alpha = src_scan[1];
718 ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
719 src_alpha = src_alpha * a / 255;
720 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
721 src_alpha = src_scan[0];
722 ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
723 src_alpha = src_alpha * a / 255;
724 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
725 if (start_col > left) {
726 src_alpha = src_scan[-1];
727 ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
728 src_alpha = src_alpha * a / 255;
729 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
733 for (int col = start_col + 1; col < end_col - 1; col ++) {
734 int src_alpha = src_scan[1];
735 ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
736 src_alpha = src_alpha * a / 255;
737 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
738 src_alpha = src_scan[0];
739 ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
740 src_alpha = src_alpha * a / 255;
741 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
742 src_alpha = src_scan[-1];
743 ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
744 src_alpha = src_alpha * a / 255;
745 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
750 int src_alpha = src_scan[0];
751 ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
752 src_alpha = src_alpha * a / 255;
753 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
754 if (start_col > left) {
755 src_alpha = src_scan[-1];
756 ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
757 src_alpha = src_alpha * a / 255;
758 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
759 src_alpha = src_scan[-2];
760 ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
761 src_alpha = src_alpha * a / 255;
762 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
766 for (int col = start_col + 1; col < end_col - 1; col ++) {
767 int src_alpha = src_scan[0];
768 ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
769 src_alpha = src_alpha * a / 255;
770 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
771 src_alpha = src_scan[-1];
772 ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
773 src_alpha = src_alpha * a / 255;
774 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
775 src_alpha = src_scan[-2];
776 ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
777 src_alpha = src_alpha * a / 255;
778 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
784 if (x_subpixel == 0) {
785 for (int col = start_col; col < end_col; col ++) {
787 int src_alpha1 = (src_scan[0] + src_scan[1] + src_scan[2]) / 3;
788 ADJUST_ALPHA(dest_scan[2], r, src_alpha1, nativetext_flags, a);
789 src_alpha1 = src_alpha1 * a / 255;
790 if (src_alpha1 == 0) {
795 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha1));
796 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha1));
797 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha1));
802 int src_alpha = src_scan[0];
803 ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
804 src_alpha = src_alpha * a / 255;
805 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
806 src_alpha = src_scan[1];
807 ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
808 src_alpha = src_alpha * a / 255;
809 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
810 src_alpha = src_scan[2];
811 ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
812 src_alpha = src_alpha * a / 255;
813 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
817 } else if (x_subpixel == 1) {
819 int src_alpha1 = start_col > left ? (src_scan[0] + src_scan[1] + src_scan[-1]) / 3 : (src_scan[0] + src_scan[1]) / 3;
820 ADJUST_ALPHA(dest_scan[2], r, src_alpha1, nativetext_flags, a);
821 src_alpha1 = src_alpha1 * a / 255;
822 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha1));
823 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha1));
824 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha1));
828 if (start_col > left) {
829 int src_alpha = src_scan[-1];
830 ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
831 src_alpha = src_alpha * a / 255;
832 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
834 int src_alpha = src_scan[0];
835 ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
836 src_alpha = src_alpha * a / 255;
837 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
838 src_alpha = src_scan[1];
839 ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
840 src_alpha = src_alpha * a / 255;
841 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
845 for (int col = start_col + 1; col < end_col; col ++) {
847 int src_alpha1 = (src_scan[0] + src_scan[1] + src_scan[-1]) / 3;
848 ADJUST_ALPHA(dest_scan[2], r, src_alpha1, nativetext_flags, a);
849 src_alpha1 = src_alpha1 * a / 255;
850 if (src_alpha1 == 0) {
855 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha1));
856 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha1));
857 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha1));
862 int src_alpha = src_scan[-1];
863 ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
864 src_alpha = src_alpha * a / 255;
865 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
866 src_alpha = src_scan[0];
867 ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
868 src_alpha = src_alpha * a / 255;
869 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
870 src_alpha = src_scan[1];
871 ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
872 src_alpha = src_alpha * a / 255;
873 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
879 int src_alpha1 = start_col > left ? (src_scan[0] + src_scan[-2] + src_scan[-1]) / 3 : src_scan[0] / 3;
880 ADJUST_ALPHA(dest_scan[2], r, src_alpha1, nativetext_flags, a);
881 src_alpha1 = src_alpha1 * a / 255;
882 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha1));
883 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha1));
884 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha1));
888 if (start_col > left) {
889 int src_alpha = src_scan[-2];
890 ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
891 src_alpha = src_alpha * a / 255;
892 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
893 src_alpha = src_scan[-1];
894 ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
895 src_alpha = src_alpha * a / 255;
896 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
898 int src_alpha = src_scan[0];
899 ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
900 src_alpha = src_alpha * a / 255;
901 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
905 for (int col = start_col + 1; col < end_col; col ++) {
907 int src_alpha1 = ((int)(src_scan[0]) + (int)(src_scan[-2]) + (int)(src_scan[-1])) / 3;
908 ADJUST_ALPHA(dest_scan[2], r, src_alpha1, nativetext_flags, a);
909 src_alpha1 = src_alpha1 * a / 255;
910 if (src_alpha1 == 0) {
915 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha1));
916 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha1));
917 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha1));
922 int src_alpha = src_scan[-2];
923 ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
924 src_alpha = src_alpha * a / 255;
925 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
926 src_alpha = src_scan[-1];
927 ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
928 src_alpha = src_alpha * a / 255;
929 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
930 src_alpha = src_scan[0];
931 ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
932 src_alpha = src_alpha * a / 255;
933 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
942 if (bitmap.IsAlphaMask()) {
943 SetBitMask(&bitmap, bmp_rect.left, bmp_rect.top, fill_color, alpha_flag, pIccTransform);
945 SetDIBits(&bitmap, bmp_rect.left, bmp_rect.top);
947 FX_Free(pGlyphAndPos);
950 FX_BOOL CFX_RenderDevice::DrawTextPath(int nChars, const FXTEXT_CHARPOS* pCharPos,
951 CFX_Font* pFont, CFX_FontCache* pCache,
952 FX_FLOAT font_size, const CFX_AffineMatrix* pText2User,
953 const CFX_AffineMatrix* pUser2Device, const CFX_GraphStateData* pGraphState,
954 FX_DWORD fill_color, FX_ARGB stroke_color, CFX_PathData* pClippingPath, int nFlag,
955 int alpha_flag, void* pIccTransform, int blend_type)
957 if (pCache == NULL) {
958 pCache = CFX_GEModule::Get()->GetFontCache();
960 CFX_FaceCache* pFaceCache = pCache->GetCachedFace(pFont);
961 FX_FONTCACHE_DEFINE(pCache, pFont);
962 for (int iChar = 0; iChar < nChars; iChar ++) {
963 const FXTEXT_CHARPOS& charpos = pCharPos[iChar];
964 CFX_AffineMatrix matrix;
965 if (charpos.m_bGlyphAdjust)
966 matrix.Set(charpos.m_AdjustMatrix[0], charpos.m_AdjustMatrix[1],
967 charpos.m_AdjustMatrix[2], charpos.m_AdjustMatrix[3], 0, 0);
968 matrix.Concat(font_size, 0, 0, font_size, charpos.m_OriginX, charpos.m_OriginY);
969 const CFX_PathData* pPath = pFaceCache->LoadGlyphPath(pFont, charpos.m_GlyphIndex, charpos.m_FontCharWidth);
973 matrix.Concat(*pText2User);
974 CFX_PathData TransformedPath(*pPath);
975 TransformedPath.Transform(&matrix);
976 FX_BOOL bHasAlpha = FXGETFLAG_COLORTYPE(alpha_flag) ?
977 (FXGETFLAG_ALPHA_FILL(alpha_flag) || FXGETFLAG_ALPHA_STROKE(alpha_flag)) :
978 (fill_color || stroke_color);
980 int fill_mode = nFlag;
981 if (FXGETFLAG_COLORTYPE(alpha_flag)) {
982 if (FXGETFLAG_ALPHA_FILL(alpha_flag)) {
983 fill_mode |= FXFILL_WINDING;
987 fill_mode |= FXFILL_WINDING;
990 fill_mode |= FX_FILL_TEXT_MODE;
991 if (!DrawPath(&TransformedPath, pUser2Device, pGraphState, fill_color, stroke_color, fill_mode, alpha_flag, pIccTransform, blend_type)) {
996 pClippingPath->Append(&TransformedPath, pUser2Device);
1001 CFX_FontCache::~CFX_FontCache()
1005 CFX_FaceCache* CFX_FontCache::GetCachedFace(CFX_Font* pFont)
1007 FX_BOOL bExternal = pFont->GetFace() == NULL;
1008 void* face = bExternal ? pFont->GetSubstFont()->m_ExtHandle : pFont->GetFace();
1009 CFX_FTCacheMap& map = bExternal ? m_ExtFaceMap : m_FTFaceMap;
1010 CFX_CountedFaceCache* counted_face_cache = NULL;
1011 if (map.Lookup((FXFT_Face)face, counted_face_cache)) {
1012 counted_face_cache->m_nCount++;
1013 return counted_face_cache->m_Obj;
1015 CFX_FaceCache* face_cache = new CFX_FaceCache(bExternal ? NULL : (FXFT_Face)face);
1016 counted_face_cache = new CFX_CountedFaceCache;
1017 counted_face_cache->m_nCount = 2;
1018 counted_face_cache->m_Obj = face_cache;
1019 map.SetAt((FXFT_Face)face, counted_face_cache);
1022 void CFX_FontCache::ReleaseCachedFace(CFX_Font* pFont)
1024 FX_BOOL bExternal = pFont->GetFace() == NULL;
1025 void* face = bExternal ? pFont->GetSubstFont()->m_ExtHandle : pFont->GetFace();
1026 CFX_FTCacheMap& map = bExternal ? m_ExtFaceMap : m_FTFaceMap;
1027 CFX_CountedFaceCache* counted_face_cache = NULL;
1028 if (!map.Lookup((FXFT_Face)face, counted_face_cache)) {
1031 if (counted_face_cache->m_nCount > 1) {
1032 counted_face_cache->m_nCount--;
1035 void CFX_FontCache::FreeCache(FX_BOOL bRelease)
1039 pos = m_FTFaceMap.GetStartPosition();
1042 CFX_CountedFaceCache* cache;
1043 m_FTFaceMap.GetNextAssoc(pos, face, cache);
1044 if (bRelease || cache->m_nCount < 2) {
1045 delete cache->m_Obj;
1047 m_FTFaceMap.RemoveKey(face);
1050 pos = m_ExtFaceMap.GetStartPosition();
1053 CFX_CountedFaceCache* cache;
1054 m_ExtFaceMap.GetNextAssoc(pos, face, cache);
1055 if (bRelease || cache->m_nCount < 2) {
1056 delete cache->m_Obj;
1058 m_ExtFaceMap.RemoveKey(face);
1063 CFX_FaceCache::CFX_FaceCache(FXFT_Face face)
1068 CFX_FaceCache::~CFX_FaceCache()
1070 FX_POSITION pos = m_SizeMap.GetStartPosition();
1072 CFX_SizeGlyphCache* pSizeCache = NULL;
1074 m_SizeMap.GetNextAssoc( pos, Key, (void*&)pSizeCache);
1077 m_SizeMap.RemoveAll();
1078 pos = m_PathMap.GetStartPosition();
1080 CFX_PathData* pPath;
1082 m_PathMap.GetNextAssoc(pos, key1, (void*&)pPath);
1088 m_PathMap.RemoveAll();
1090 #if _FXM_PLATFORM_ != _FXM_PLATFORM_APPLE_
1091 void CFX_FaceCache::InitPlatform()
1095 CFX_GlyphBitmap* CFX_FaceCache::LookUpGlyphBitmap(CFX_Font* pFont, const CFX_AffineMatrix* pMatrix,
1096 CFX_ByteStringC& FaceGlyphsKey, FX_DWORD glyph_index, FX_BOOL bFontStyle,
1097 int dest_width, int anti_alias)
1099 CFX_SizeGlyphCache* pSizeCache = NULL;
1100 if (!m_SizeMap.Lookup(FaceGlyphsKey, (void*&)pSizeCache)) {
1101 pSizeCache = new CFX_SizeGlyphCache;
1102 m_SizeMap.SetAt(FaceGlyphsKey, pSizeCache);
1104 CFX_GlyphBitmap* pGlyphBitmap = NULL;
1105 if (pSizeCache->m_GlyphMap.Lookup((void*)(uintptr_t)glyph_index, (void*&)pGlyphBitmap)) {
1106 return pGlyphBitmap;
1108 pGlyphBitmap = RenderGlyph(pFont, glyph_index, bFontStyle, pMatrix, dest_width, anti_alias);
1109 if (pGlyphBitmap == NULL) {
1112 pSizeCache->m_GlyphMap.SetAt((void*)(uintptr_t)glyph_index, pGlyphBitmap);
1113 return pGlyphBitmap;
1115 const CFX_GlyphBitmap* CFX_FaceCache::LoadGlyphBitmap(CFX_Font* pFont, FX_DWORD glyph_index, FX_BOOL bFontStyle, const CFX_AffineMatrix* pMatrix,
1116 int dest_width, int anti_alias, int& text_flags)
1118 if (glyph_index == (FX_DWORD) - 1) {
1121 _CFX_UniqueKeyGen keygen;
1122 #if _FXM_PLATFORM_ != _FXM_PLATFORM_APPLE_
1123 if (pFont->GetSubstFont())
1124 keygen.Generate(9, (int)(pMatrix->a * 10000), (int)(pMatrix->b * 10000),
1125 (int)(pMatrix->c * 10000), (int)(pMatrix->d * 10000), dest_width, anti_alias,
1126 pFont->GetSubstFont()->m_Weight, pFont->GetSubstFont()->m_ItalicAngle, pFont->IsVertical());
1128 keygen.Generate(6, (int)(pMatrix->a * 10000), (int)(pMatrix->b * 10000),
1129 (int)(pMatrix->c * 10000), (int)(pMatrix->d * 10000), dest_width, anti_alias);
1131 if (text_flags & FXTEXT_NO_NATIVETEXT) {
1132 if (pFont->GetSubstFont())
1133 keygen.Generate(9, (int)(pMatrix->a * 10000), (int)(pMatrix->b * 10000),
1134 (int)(pMatrix->c * 10000), (int)(pMatrix->d * 10000), dest_width, anti_alias,
1135 pFont->GetSubstFont()->m_Weight, pFont->GetSubstFont()->m_ItalicAngle, pFont->IsVertical());
1137 keygen.Generate(6, (int)(pMatrix->a * 10000), (int)(pMatrix->b * 10000),
1138 (int)(pMatrix->c * 10000), (int)(pMatrix->d * 10000), dest_width, anti_alias);
1140 if (pFont->GetSubstFont())
1141 keygen.Generate(10, (int)(pMatrix->a * 10000), (int)(pMatrix->b * 10000),
1142 (int)(pMatrix->c * 10000), (int)(pMatrix->d * 10000), dest_width, anti_alias,
1143 pFont->GetSubstFont()->m_Weight, pFont->GetSubstFont()->m_ItalicAngle, pFont->IsVertical(), 3);
1145 keygen.Generate(7, (int)(pMatrix->a * 10000), (int)(pMatrix->b * 10000),
1146 (int)(pMatrix->c * 10000), (int)(pMatrix->d * 10000), dest_width, anti_alias, 3);
1149 CFX_ByteStringC FaceGlyphsKey(keygen.m_Key, keygen.m_KeyLen);
1150 #if _FXM_PLATFORM_ != _FXM_PLATFORM_APPLE_
1151 return LookUpGlyphBitmap(pFont, pMatrix, FaceGlyphsKey, glyph_index, bFontStyle, dest_width, anti_alias);
1153 if (text_flags & FXTEXT_NO_NATIVETEXT) {
1154 return LookUpGlyphBitmap(pFont, pMatrix, FaceGlyphsKey, glyph_index, bFontStyle, dest_width, anti_alias);
1156 CFX_GlyphBitmap* pGlyphBitmap;
1157 CFX_SizeGlyphCache* pSizeCache = NULL;
1158 if (m_SizeMap.Lookup(FaceGlyphsKey, (void*&)pSizeCache)) {
1159 if (pSizeCache->m_GlyphMap.Lookup((void*)(uintptr_t)glyph_index, (void*&)pGlyphBitmap)) {
1160 return pGlyphBitmap;
1162 pGlyphBitmap = RenderGlyph_Nativetext(pFont, glyph_index, pMatrix, dest_width, anti_alias);
1164 pSizeCache->m_GlyphMap.SetAt((void*)(uintptr_t)glyph_index, pGlyphBitmap);
1165 return pGlyphBitmap;
1168 pGlyphBitmap = RenderGlyph_Nativetext(pFont, glyph_index, pMatrix, dest_width, anti_alias);
1170 pSizeCache = new CFX_SizeGlyphCache;
1171 m_SizeMap.SetAt(FaceGlyphsKey, pSizeCache);
1172 pSizeCache->m_GlyphMap.SetAt((void*)(uintptr_t)glyph_index, pGlyphBitmap);
1173 return pGlyphBitmap;
1176 if (pFont->GetSubstFont())
1177 keygen.Generate(9, (int)(pMatrix->a * 10000), (int)(pMatrix->b * 10000),
1178 (int)(pMatrix->c * 10000), (int)(pMatrix->d * 10000), dest_width, anti_alias,
1179 pFont->GetSubstFont()->m_Weight, pFont->GetSubstFont()->m_ItalicAngle, pFont->IsVertical());
1181 keygen.Generate(6, (int)(pMatrix->a * 10000), (int)(pMatrix->b * 10000),
1182 (int)(pMatrix->c * 10000), (int)(pMatrix->d * 10000), dest_width, anti_alias);
1183 CFX_ByteStringC FaceGlyphsKey(keygen.m_Key, keygen.m_KeyLen);
1184 text_flags |= FXTEXT_NO_NATIVETEXT;
1185 return LookUpGlyphBitmap(pFont, pMatrix, FaceGlyphsKey, glyph_index, bFontStyle, dest_width, anti_alias);
1189 CFX_SizeGlyphCache::~CFX_SizeGlyphCache()
1191 FX_POSITION pos = m_GlyphMap.GetStartPosition();
1193 CFX_GlyphBitmap* pGlyphBitmap = NULL;
1195 m_GlyphMap.GetNextAssoc(pos, Key, (void*&)pGlyphBitmap);
1196 delete pGlyphBitmap;
1198 m_GlyphMap.RemoveAll();
1200 #define CONTRAST_RAMP_STEP 1
1201 void CFX_Font::AdjustMMParams(int glyph_index, int dest_width, int weight)
1203 FXFT_MM_Var pMasters = NULL;
1204 FXFT_Get_MM_Var(m_Face, &pMasters);
1205 if (pMasters == NULL) {
1210 coords[0] = FXFT_Get_MM_Axis_Def(FXFT_Get_MM_Axis(pMasters, 0)) / 65536;
1214 if (dest_width == 0) {
1215 coords[1] = FXFT_Get_MM_Axis_Def(FXFT_Get_MM_Axis(pMasters, 1)) / 65536;
1217 int min_param = FXFT_Get_MM_Axis_Min(FXFT_Get_MM_Axis(pMasters, 1)) / 65536;
1218 int max_param = FXFT_Get_MM_Axis_Max(FXFT_Get_MM_Axis(pMasters, 1)) / 65536;
1219 coords[1] = min_param;
1220 int error = FXFT_Set_MM_Design_Coordinates(m_Face, 2, coords);
1221 error = FXFT_Load_Glyph(m_Face, glyph_index, FXFT_LOAD_NO_SCALE | FXFT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH);
1222 int min_width = FXFT_Get_Glyph_HoriAdvance(m_Face) * 1000 / FXFT_Get_Face_UnitsPerEM(m_Face);
1223 coords[1] = max_param;
1224 error = FXFT_Set_MM_Design_Coordinates(m_Face, 2, coords);
1225 error = FXFT_Load_Glyph(m_Face, glyph_index, FXFT_LOAD_NO_SCALE | FXFT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH);
1226 int max_width = FXFT_Get_Glyph_HoriAdvance(m_Face) * 1000 / FXFT_Get_Face_UnitsPerEM(m_Face);
1227 if (max_width == min_width) {
1230 int param = min_param + (max_param - min_param) * (dest_width - min_width) / (max_width - min_width);
1233 FXFT_Free(m_Face, pMasters);
1234 FXFT_Set_MM_Design_Coordinates(m_Face, 2, coords);
1236 static const size_t ANGLESKEW_ARRAY_SIZE = 30;
1237 static const char g_AngleSkew[ANGLESKEW_ARRAY_SIZE] = {
1238 0, 2, 3, 5, 7, 9, 11, 12, 14, 16,
1239 18, 19, 21, 23, 25, 27, 29, 31, 32, 34,
1240 36, 38, 40, 42, 45, 47, 49, 51, 53, 55,
1242 static const size_t WEIGHTPOW_ARRAY_SIZE = 100;
1243 static const uint8_t g_WeightPow[WEIGHTPOW_ARRAY_SIZE] = {
1244 0, 3, 6, 7, 8, 9, 11, 12, 14, 15, 16, 17, 18, 19, 20,
1245 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 35, 36, 36,
1246 37, 37, 37, 38, 38, 38, 39, 39, 39, 40, 40, 40, 41, 41, 41, 42, 42, 42,
1247 42, 43, 43, 43, 44, 44, 44, 44, 45, 45, 45, 45, 46, 46, 46, 46, 47, 47,
1248 47, 47, 48, 48, 48, 48, 48, 49, 49, 49, 49, 50, 50, 50, 50, 50, 51, 51,
1249 51, 51, 51, 52, 52, 52, 52, 52, 53, 53, 53, 53, 53,
1251 static const uint8_t g_WeightPow_11[WEIGHTPOW_ARRAY_SIZE] = {
1252 0, 4, 7, 8, 9, 10, 12, 13, 15, 17, 18, 19, 20, 21, 22,
1253 23, 24, 25, 26, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 39, 39, 40, 40,
1254 41, 41, 41, 42, 42, 42, 43, 43, 43, 44, 44, 44, 45, 45, 45, 46, 46, 46,
1255 46, 43, 47, 47, 48, 48, 48, 48, 45, 50, 50, 50, 46, 51, 51, 51, 52, 52,
1256 52, 52, 53, 53, 53, 53, 53, 54, 54, 54, 54, 55, 55, 55, 55, 55, 56, 56,
1257 56, 56, 56, 57, 57, 57, 57, 57, 58, 58, 58, 58, 58,
1259 static const uint8_t g_WeightPow_SHIFTJIS[WEIGHTPOW_ARRAY_SIZE] = {
1260 0, 0, 1, 2, 3, 4, 5, 7, 8, 10, 11, 13, 14, 16, 17, 19, 21, 22, 24, 26, 28,
1261 30, 32, 33, 35, 37, 39, 41, 43, 45, 48, 48, 48, 48, 49, 49, 49, 50, 50, 50, 50,
1262 51, 51, 51, 51, 52, 52, 52, 52, 52, 53, 53, 53, 53, 53, 54, 54, 54, 54, 54, 55, 55,
1263 55, 55, 55, 56, 56, 56, 56, 56 , 56, 57, 57, 57 , 57 , 57, 57, 57, 58, 58, 58, 58, 58,
1264 58, 58, 59, 59, 59, 59, 59, 59, 59, 60, 60, 60, 60, 60, 60, 60, 60,
1266 static void _GammaAdjust(uint8_t* pData, int nWid, int nHei, int src_pitch, const uint8_t* gammaTable)
1268 int count = nHei * src_pitch;
1269 for(int i = 0; i < count; i++) {
1270 pData[i] = gammaTable[pData[i]];
1273 static void _ContrastAdjust(uint8_t* pDataIn, uint8_t* pDataOut, int nWid, int nHei, int nSrcRowBytes, int nDstRowBytes)
1276 int max = 0, min = 255;
1278 for (row = 0; row < nHei; row ++) {
1279 uint8_t* pRow = pDataIn + row * nSrcRowBytes;
1280 for (col = 0; col < nWid; col++) {
1291 if (0 == temp || 255 == temp) {
1292 int rowbytes = FXSYS_abs(nSrcRowBytes) > nDstRowBytes ? nDstRowBytes : FXSYS_abs(nSrcRowBytes);
1293 for (row = 0; row < nHei; row ++) {
1294 FXSYS_memcpy(pDataOut + row * nDstRowBytes, pDataIn + row * nSrcRowBytes, rowbytes);
1298 rate = 255.f / temp;
1299 for (row = 0; row < nHei; row ++) {
1300 uint8_t* pSrcRow = pDataIn + row * nSrcRowBytes;
1301 uint8_t* pDstRow = pDataOut + row * nDstRowBytes;
1302 for (col = 0; col < nWid; col ++) {
1303 temp = (int)((*(pSrcRow++) - min) * rate + 0.5);
1306 } else if (temp < 0) {
1309 *pDstRow ++ = (uint8_t)temp;
1313 CFX_GlyphBitmap* CFX_FaceCache::RenderGlyph(CFX_Font* pFont, FX_DWORD glyph_index, FX_BOOL bFontStyle,
1314 const CFX_AffineMatrix* pMatrix, int dest_width, int anti_alias)
1316 if (m_Face == NULL) {
1319 FXFT_Matrix ft_matrix;
1320 ft_matrix.xx = (signed long)(pMatrix->GetA() / 64 * 65536);
1321 ft_matrix.xy = (signed long)(pMatrix->GetC() / 64 * 65536);
1322 ft_matrix.yx = (signed long)(pMatrix->GetB() / 64 * 65536);
1323 ft_matrix.yy = (signed long)(pMatrix->GetD() / 64 * 65536);
1324 FX_BOOL bUseCJKSubFont = FALSE;
1325 const CFX_SubstFont* pSubstFont = pFont->GetSubstFont();
1327 bUseCJKSubFont = pSubstFont->m_bSubstOfCJK && bFontStyle;
1329 if (bUseCJKSubFont) {
1330 skew = pSubstFont->m_bItlicCJK ? -15 : 0;
1332 skew = pSubstFont->m_ItalicAngle;
1335 skew = skew <= -ANGLESKEW_ARRAY_SIZE ? -58 : -g_AngleSkew[-skew];
1336 if (pFont->IsVertical()) {
1337 ft_matrix.yx += ft_matrix.yy * skew / 100;
1339 ft_matrix.xy += -ft_matrix.xx * skew / 100;
1342 if (pSubstFont->m_SubstFlags & FXFONT_SUBST_MM) {
1343 pFont->AdjustMMParams(glyph_index, dest_width, pFont->GetSubstFont()->m_Weight);
1346 ScopedFontTransform scoped_transform(m_Face, &ft_matrix);
1347 int load_flags = (m_Face->face_flags & FT_FACE_FLAG_SFNT) ? FXFT_LOAD_NO_BITMAP : (FXFT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING);
1348 int error = FXFT_Load_Glyph(m_Face, glyph_index, load_flags);
1350 //if an error is returned, try to reload glyphs without hinting.
1351 if (load_flags & FT_LOAD_NO_HINTING || load_flags & FT_LOAD_NO_SCALE) {
1355 load_flags |= FT_LOAD_NO_HINTING;
1356 error = FXFT_Load_Glyph(m_Face, glyph_index, load_flags);
1363 if (bUseCJKSubFont) {
1364 weight = pSubstFont->m_WeightCJK;
1366 weight = pSubstFont ? pSubstFont->m_Weight : 0;
1368 if (pSubstFont && !(pSubstFont->m_SubstFlags & FXFONT_SUBST_MM) && weight > 400) {
1369 int index = (weight - 400) / 10;
1370 if (index >= WEIGHTPOW_ARRAY_SIZE) {
1374 if (pSubstFont->m_Charset == FXFONT_SHIFTJIS_CHARSET) {
1375 level = g_WeightPow_SHIFTJIS[index] * 2 * (FXSYS_abs((int)(ft_matrix.xx)) + FXSYS_abs((int)(ft_matrix.xy))) / 36655;
1377 level = g_WeightPow_11[index] * (FXSYS_abs((int)(ft_matrix.xx)) + FXSYS_abs((int)(ft_matrix.xy))) / 36655;
1379 FXFT_Outline_Embolden(FXFT_Get_Glyph_Outline(m_Face), level);
1381 FXFT_Library_SetLcdFilter(CFX_GEModule::Get()->GetFontMgr()->m_FTLibrary, FT_LCD_FILTER_DEFAULT);
1382 error = FXFT_Render_Glyph(m_Face, anti_alias);
1386 int bmwidth = FXFT_Get_Bitmap_Width(FXFT_Get_Glyph_Bitmap(m_Face));
1387 int bmheight = FXFT_Get_Bitmap_Rows(FXFT_Get_Glyph_Bitmap(m_Face));
1388 if (bmwidth > 2048 || bmheight > 2048) {
1391 int dib_width = bmwidth;
1392 CFX_GlyphBitmap* pGlyphBitmap = new CFX_GlyphBitmap;
1393 pGlyphBitmap->m_Bitmap.Create(dib_width, bmheight,
1394 anti_alias == FXFT_RENDER_MODE_MONO ? FXDIB_1bppMask : FXDIB_8bppMask);
1395 pGlyphBitmap->m_Left = FXFT_Get_Glyph_BitmapLeft(m_Face);
1396 pGlyphBitmap->m_Top = FXFT_Get_Glyph_BitmapTop(m_Face);
1397 int dest_pitch = pGlyphBitmap->m_Bitmap.GetPitch();
1398 int src_pitch = FXFT_Get_Bitmap_Pitch(FXFT_Get_Glyph_Bitmap(m_Face));
1399 uint8_t* pDestBuf = pGlyphBitmap->m_Bitmap.GetBuffer();
1400 uint8_t* pSrcBuf = (uint8_t*)FXFT_Get_Bitmap_Buffer(FXFT_Get_Glyph_Bitmap(m_Face));
1401 if (anti_alias != FXFT_RENDER_MODE_MONO && FXFT_Get_Bitmap_PixelMode(FXFT_Get_Glyph_Bitmap(m_Face)) == FXFT_PIXEL_MODE_MONO) {
1402 int bytes = anti_alias == FXFT_RENDER_MODE_LCD ? 3 : 1;
1403 for(int i = 0; i < bmheight; i++)
1404 for(int n = 0; n < bmwidth; n++) {
1405 uint8_t data = (pSrcBuf[i * src_pitch + n / 8] & (0x80 >> (n % 8))) ? 255 : 0;
1406 for (int b = 0; b < bytes; b ++) {
1407 pDestBuf[i * dest_pitch + n * bytes + b] = data;
1411 FXSYS_memset(pDestBuf, 0, dest_pitch * bmheight);
1412 if (anti_alias == FXFT_RENDER_MODE_MONO && FXFT_Get_Bitmap_PixelMode(FXFT_Get_Glyph_Bitmap(m_Face)) == FXFT_PIXEL_MODE_MONO) {
1413 int rowbytes = FXSYS_abs(src_pitch) > dest_pitch ? dest_pitch : FXSYS_abs(src_pitch);
1414 for (int row = 0; row < bmheight; row ++) {
1415 FXSYS_memcpy(pDestBuf + row * dest_pitch, pSrcBuf + row * src_pitch, rowbytes);
1418 _ContrastAdjust(pSrcBuf, pDestBuf, bmwidth, bmheight, src_pitch, dest_pitch);
1419 _GammaAdjust(pDestBuf, bmwidth, bmheight, dest_pitch, CFX_GEModule::Get()->GetTextGammaTable());
1422 return pGlyphBitmap;
1424 FX_BOOL _OutputGlyph(void* dib, int x, int y, CFX_Font* pFont,
1425 int glyph_index, FX_ARGB argb)
1427 CFX_DIBitmap* pDib = (CFX_DIBitmap*)dib;
1428 FXFT_Face face = pFont->GetFace();
1429 int error = FXFT_Load_Glyph(face, glyph_index, FXFT_LOAD_NO_BITMAP);
1433 error = FXFT_Render_Glyph(face, FXFT_RENDER_MODE_NORMAL);
1437 int bmwidth = FXFT_Get_Bitmap_Width(FXFT_Get_Glyph_Bitmap(face));
1438 int bmheight = FXFT_Get_Bitmap_Rows(FXFT_Get_Glyph_Bitmap(face));
1439 int left = FXFT_Get_Glyph_BitmapLeft(face);
1440 int top = FXFT_Get_Glyph_BitmapTop(face);
1441 const uint8_t* src_buf = (const uint8_t*)FXFT_Get_Bitmap_Buffer(FXFT_Get_Glyph_Bitmap(face));
1442 int src_pitch = FXFT_Get_Bitmap_Pitch(FXFT_Get_Glyph_Bitmap(face));
1444 mask.Create(bmwidth, bmheight, FXDIB_8bppMask);
1445 uint8_t* dest_buf = mask.GetBuffer();
1446 int dest_pitch = mask.GetPitch();
1447 for (int row = 0; row < bmheight; row ++) {
1448 const uint8_t* src_scan = src_buf + row * src_pitch;
1449 uint8_t* dest_scan = dest_buf + row * dest_pitch;
1450 FXSYS_memcpy(dest_scan, src_scan, dest_pitch);
1452 pDib->CompositeMask(x + left, y - top, bmwidth, bmheight, &mask, argb, 0, 0);
1455 FX_BOOL OutputText(void* dib, int x, int y, CFX_Font* pFont, double font_size,
1456 CFX_AffineMatrix* pText_matrix, unsigned short const* text, unsigned long argb)
1461 FXFT_Face face = pFont->GetFace();
1462 FXFT_Select_Charmap(pFont->m_Face, FXFT_ENCODING_UNICODE);
1464 FXFT_Matrix ft_matrix;
1465 ft_matrix.xx = (signed long)(pText_matrix->a / 64 * 65536);
1466 ft_matrix.xy = (signed long)(pText_matrix->c / 64 * 65536);
1467 ft_matrix.yx = (signed long)(pText_matrix->b / 64 * 65536);
1468 ft_matrix.yy = (signed long)(pText_matrix->d / 64 * 65536);
1469 FXFT_Set_Transform(face, &ft_matrix, 0);
1472 for (; *text != 0; text ++) {
1473 FX_WCHAR unicode = *text;
1474 int glyph_index = FXFT_Get_Char_Index(pFont->m_Face, unicode);
1475 if (glyph_index <= 0) {
1478 int err = FXFT_Load_Glyph(pFont->m_Face, glyph_index, FXFT_LOAD_NO_SCALE | FXFT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH);
1482 int w = FXFT_Get_Glyph_HoriAdvance(pFont->m_Face);
1483 int em = FXFT_Get_Face_UnitsPerEM(pFont->m_Face);
1485 pText_matrix->Transform(x_pos, 0, x1, y1);
1486 _OutputGlyph(dib, (int)x1 + x, (int) - y1 + y, pFont,
1488 x_pos += (FX_FLOAT)w / em;
1491 ResetTransform(face);
1494 FX_BOOL OutputGlyph(void* dib, int x, int y, CFX_Font* pFont, double font_size,
1495 CFX_AffineMatrix* pMatrix, unsigned long glyph_index, unsigned long argb)
1497 FXFT_Matrix ft_matrix;
1499 ft_matrix.xx = (signed long)(pMatrix->a * font_size / 64 * 65536);
1500 ft_matrix.xy = (signed long)(pMatrix->c * font_size / 64 * 65536);
1501 ft_matrix.yx = (signed long)(pMatrix->b * font_size / 64 * 65536);
1502 ft_matrix.yy = (signed long)(pMatrix->d * font_size / 64 * 65536);
1504 ft_matrix.xx = (signed long)(font_size / 64 * 65536);
1505 ft_matrix.xy = ft_matrix.yx = 0;
1506 ft_matrix.yy = (signed long)(font_size / 64 * 65536);
1508 ScopedFontTransform scoped_transform(pFont->m_Face, &ft_matrix);
1509 FX_BOOL ret = _OutputGlyph(dib, x, y, pFont,
1513 const CFX_PathData* CFX_FaceCache::LoadGlyphPath(CFX_Font* pFont, FX_DWORD glyph_index, int dest_width)
1515 if (m_Face == NULL || glyph_index == (FX_DWORD) - 1) {
1518 CFX_PathData* pGlyphPath = NULL;
1520 if (pFont->GetSubstFont())
1521 key = (void*)(uintptr_t)(glyph_index + ((pFont->GetSubstFont()->m_Weight / 16) << 15) +
1522 ((pFont->GetSubstFont()->m_ItalicAngle / 2) << 21) + ((dest_width / 16) << 25) +
1523 (pFont->IsVertical() << 31));
1525 key = (void*)(uintptr_t)glyph_index;
1527 if (m_PathMap.Lookup(key, (void*&)pGlyphPath)) {
1530 pGlyphPath = pFont->LoadGlyphPath(glyph_index, dest_width);
1531 m_PathMap.SetAt(key, pGlyphPath);
1537 FX_PATHPOINT* m_pPoints;
1540 FX_FLOAT m_CoordUnit;
1542 void _Outline_CheckEmptyContour(OUTLINE_PARAMS* param)
1544 if (param->m_PointCount >= 2 && param->m_pPoints[param->m_PointCount - 2].m_Flag == FXPT_MOVETO &&
1545 param->m_pPoints[param->m_PointCount - 2].m_PointX == param->m_pPoints[param->m_PointCount - 1].m_PointX &&
1546 param->m_pPoints[param->m_PointCount - 2].m_PointY == param->m_pPoints[param->m_PointCount - 1].m_PointY) {
1547 param->m_PointCount -= 2;
1549 if (param->m_PointCount >= 4 && param->m_pPoints[param->m_PointCount - 4].m_Flag == FXPT_MOVETO &&
1550 param->m_pPoints[param->m_PointCount - 3].m_Flag == FXPT_BEZIERTO &&
1551 param->m_pPoints[param->m_PointCount - 3].m_PointX == param->m_pPoints[param->m_PointCount - 4].m_PointX &&
1552 param->m_pPoints[param->m_PointCount - 3].m_PointY == param->m_pPoints[param->m_PointCount - 4].m_PointY &&
1553 param->m_pPoints[param->m_PointCount - 2].m_PointX == param->m_pPoints[param->m_PointCount - 4].m_PointX &&
1554 param->m_pPoints[param->m_PointCount - 2].m_PointY == param->m_pPoints[param->m_PointCount - 4].m_PointY &&
1555 param->m_pPoints[param->m_PointCount - 1].m_PointX == param->m_pPoints[param->m_PointCount - 4].m_PointX &&
1556 param->m_pPoints[param->m_PointCount - 1].m_PointY == param->m_pPoints[param->m_PointCount - 4].m_PointY) {
1557 param->m_PointCount -= 4;
1561 static int _Outline_MoveTo(const FXFT_Vector* to, void* user)
1563 OUTLINE_PARAMS* param = (OUTLINE_PARAMS*)user;
1564 if (!param->m_bCount) {
1565 _Outline_CheckEmptyContour(param);
1566 param->m_pPoints[param->m_PointCount].m_PointX = to->x / param->m_CoordUnit;
1567 param->m_pPoints[param->m_PointCount].m_PointY = to->y / param->m_CoordUnit;
1568 param->m_pPoints[param->m_PointCount].m_Flag = FXPT_MOVETO;
1569 param->m_CurX = to->x;
1570 param->m_CurY = to->y;
1571 if (param->m_PointCount) {
1572 param->m_pPoints[param->m_PointCount - 1].m_Flag |= FXPT_CLOSEFIGURE;
1575 param->m_PointCount ++;
1580 static int _Outline_LineTo(const FXFT_Vector* to, void* user)
1582 OUTLINE_PARAMS* param = (OUTLINE_PARAMS*)user;
1583 if (!param->m_bCount) {
1584 param->m_pPoints[param->m_PointCount].m_PointX = to->x / param->m_CoordUnit;
1585 param->m_pPoints[param->m_PointCount].m_PointY = to->y / param->m_CoordUnit;
1586 param->m_pPoints[param->m_PointCount].m_Flag = FXPT_LINETO;
1587 param->m_CurX = to->x;
1588 param->m_CurY = to->y;
1590 param->m_PointCount ++;
1595 static int _Outline_ConicTo(const FXFT_Vector* control, const FXFT_Vector* to, void* user)
1597 OUTLINE_PARAMS* param = (OUTLINE_PARAMS*)user;
1598 if (!param->m_bCount) {
1599 param->m_pPoints[param->m_PointCount].m_PointX = (param->m_CurX + (control->x - param->m_CurX) * 2 / 3) / param->m_CoordUnit;
1600 param->m_pPoints[param->m_PointCount].m_PointY = (param->m_CurY + (control->y - param->m_CurY) * 2 / 3) / param->m_CoordUnit;
1601 param->m_pPoints[param->m_PointCount].m_Flag = FXPT_BEZIERTO;
1602 param->m_pPoints[param->m_PointCount + 1].m_PointX = (control->x + (to->x - control->x) / 3) / param->m_CoordUnit;
1603 param->m_pPoints[param->m_PointCount + 1].m_PointY = (control->y + (to->y - control->y) / 3) / param->m_CoordUnit;
1604 param->m_pPoints[param->m_PointCount + 1].m_Flag = FXPT_BEZIERTO;
1605 param->m_pPoints[param->m_PointCount + 2].m_PointX = to->x / param->m_CoordUnit;
1606 param->m_pPoints[param->m_PointCount + 2].m_PointY = to->y / param->m_CoordUnit;
1607 param->m_pPoints[param->m_PointCount + 2].m_Flag = FXPT_BEZIERTO;
1608 param->m_CurX = to->x;
1609 param->m_CurY = to->y;
1611 param->m_PointCount += 3;
1616 static int _Outline_CubicTo(const FXFT_Vector* control1, const FXFT_Vector* control2, const FXFT_Vector* to, void* user)
1618 OUTLINE_PARAMS* param = (OUTLINE_PARAMS*)user;
1619 if (!param->m_bCount) {
1620 param->m_pPoints[param->m_PointCount].m_PointX = control1->x / param->m_CoordUnit;
1621 param->m_pPoints[param->m_PointCount].m_PointY = control1->y / param->m_CoordUnit;
1622 param->m_pPoints[param->m_PointCount].m_Flag = FXPT_BEZIERTO;
1623 param->m_pPoints[param->m_PointCount + 1].m_PointX = control2->x / param->m_CoordUnit;
1624 param->m_pPoints[param->m_PointCount + 1].m_PointY = control2->y / param->m_CoordUnit;
1625 param->m_pPoints[param->m_PointCount + 1].m_Flag = FXPT_BEZIERTO;
1626 param->m_pPoints[param->m_PointCount + 2].m_PointX = to->x / param->m_CoordUnit;
1627 param->m_pPoints[param->m_PointCount + 2].m_PointY = to->y / param->m_CoordUnit;
1628 param->m_pPoints[param->m_PointCount + 2].m_Flag = FXPT_BEZIERTO;
1629 param->m_CurX = to->x;
1630 param->m_CurY = to->y;
1632 param->m_PointCount += 3;
1636 CFX_PathData* CFX_Font::LoadGlyphPath(FX_DWORD glyph_index, int dest_width)
1638 if (m_Face == NULL) {
1641 FXFT_Set_Pixel_Sizes(m_Face, 0, 64);
1642 FXFT_Matrix ft_matrix = {65536, 0, 0, 65536};
1644 if (m_pSubstFont->m_ItalicAngle) {
1645 int skew = m_pSubstFont->m_ItalicAngle;
1646 skew = skew <= -ANGLESKEW_ARRAY_SIZE ? -58 : -g_AngleSkew[-skew];
1648 ft_matrix.yx += ft_matrix.yy * skew / 100;
1650 ft_matrix.xy += -ft_matrix.xx * skew / 100;
1653 if (m_pSubstFont->m_SubstFlags & FXFONT_SUBST_MM) {
1654 AdjustMMParams(glyph_index, dest_width, m_pSubstFont->m_Weight);
1657 ScopedFontTransform scoped_transform(m_Face, &ft_matrix);
1658 int load_flags = FXFT_LOAD_NO_BITMAP;
1659 if (!(m_Face->face_flags & FT_FACE_FLAG_SFNT) || !FT_IS_TRICKY(m_Face)) {
1660 load_flags |= FT_LOAD_NO_HINTING;
1662 int error = FXFT_Load_Glyph(m_Face, glyph_index, load_flags);
1666 if (m_pSubstFont && !(m_pSubstFont->m_SubstFlags & FXFONT_SUBST_MM) && m_pSubstFont->m_Weight > 400) {
1667 int index = (m_pSubstFont->m_Weight - 400) / 10;
1668 if (index >= WEIGHTPOW_ARRAY_SIZE)
1669 index = WEIGHTPOW_ARRAY_SIZE - 1;
1671 if (m_pSubstFont->m_Charset == FXFONT_SHIFTJIS_CHARSET) {
1672 level = g_WeightPow_SHIFTJIS[index] * 2 * 65536 / 36655;
1674 level = g_WeightPow[index] * 2;
1676 FXFT_Outline_Embolden(FXFT_Get_Glyph_Outline(m_Face), level);
1678 FXFT_Outline_Funcs funcs;
1679 funcs.move_to = _Outline_MoveTo;
1680 funcs.line_to = _Outline_LineTo;
1681 funcs.conic_to = _Outline_ConicTo;
1682 funcs.cubic_to = _Outline_CubicTo;
1685 OUTLINE_PARAMS params;
1686 params.m_bCount = TRUE;
1687 params.m_PointCount = 0;
1688 FXFT_Outline_Decompose(FXFT_Get_Glyph_Outline(m_Face), &funcs, ¶ms);
1689 if (params.m_PointCount == 0) {
1692 CFX_PathData* pPath = new CFX_PathData;
1693 pPath->SetPointCount(params.m_PointCount);
1694 params.m_bCount = FALSE;
1695 params.m_PointCount = 0;
1696 params.m_pPoints = pPath->GetPoints();
1697 params.m_CurX = params.m_CurY = 0;
1698 params.m_CoordUnit = 64 * 64.0;
1699 FXFT_Outline_Decompose(FXFT_Get_Glyph_Outline(m_Face), &funcs, ¶ms);
1700 _Outline_CheckEmptyContour(¶ms);
1701 pPath->TrimPoints(params.m_PointCount);
1702 if (params.m_PointCount) {
1703 pPath->GetPoints()[params.m_PointCount - 1].m_Flag |= FXPT_CLOSEFIGURE;
1707 void _CFX_UniqueKeyGen::Generate(int count, ...)
1710 va_start(argList, count);
1711 for (int i = 0; i < count; i ++) {
1712 int p = va_arg(argList, int);
1713 ((FX_DWORD*)m_Key)[i] = p;
1716 m_KeyLen = count * sizeof(FX_DWORD);