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)
15 FX_RECT FXGE_GetGlyphsBBox(FXTEXT_GLYPHPOS* pGlyphAndPos, int nChars, int anti_alias, FX_FLOAT retinaScaleX, FX_FLOAT retinaScaleY)
17 FX_RECT rect(0, 0, 0, 0);
18 FX_BOOL bStarted = FALSE;
19 for (int iChar = 0; iChar < nChars; iChar ++) {
20 FXTEXT_GLYPHPOS& glyph = pGlyphAndPos[iChar];
21 const CFX_GlyphBitmap* pGlyph = glyph.m_pGlyph;
25 int char_left = glyph.m_OriginX + pGlyph->m_Left;
26 int char_width = (int)(pGlyph->m_Bitmap.GetWidth() / retinaScaleX);
27 if (anti_alias == FXFT_RENDER_MODE_LCD) {
30 int char_right = char_left + char_width;
31 int char_top = glyph.m_OriginY - pGlyph->m_Top;
32 int char_bottom = char_top + (int)(pGlyph->m_Bitmap.GetHeight() / retinaScaleY);
34 rect.left = char_left;
35 rect.right = char_right;
37 rect.bottom = char_bottom;
40 if (rect.left > char_left) {
41 rect.left = char_left;
43 if (rect.right < char_right) {
44 rect.right = char_right;
46 if (rect.top > char_top) {
49 if (rect.bottom < char_bottom) {
50 rect.bottom = char_bottom;
56 static void _AdjustGlyphSpace(FXTEXT_GLYPHPOS* pGlyphAndPos, int nChars)
59 FX_BOOL bVertical = FALSE;
60 if (pGlyphAndPos[nChars - 1].m_OriginX == pGlyphAndPos[0].m_OriginX) {
62 } else if (pGlyphAndPos[nChars - 1].m_OriginY != pGlyphAndPos[0].m_OriginY) {
66 int* next_origin = bVertical ? &pGlyphAndPos[i].m_OriginY : &pGlyphAndPos[i].m_OriginX;
67 FX_FLOAT next_origin_f = bVertical ? pGlyphAndPos[i].m_fOriginY : pGlyphAndPos[i].m_fOriginX;
68 for (i --; i > 0; i --) {
69 int* this_origin = bVertical ? &pGlyphAndPos[i].m_OriginY : &pGlyphAndPos[i].m_OriginX;
70 FX_FLOAT this_origin_f = bVertical ? pGlyphAndPos[i].m_fOriginY : pGlyphAndPos[i].m_fOriginX;
71 int space = (*next_origin) - (*this_origin);
72 FX_FLOAT space_f = next_origin_f - this_origin_f;
73 FX_FLOAT error = (FX_FLOAT)(FXSYS_fabs(space_f) - FXSYS_fabs((FX_FLOAT)(space)));
75 *this_origin += space > 0 ? -1 : 1;
77 next_origin = this_origin;
78 next_origin_f = this_origin_f;
81 static const FX_BYTE g_TextGammaAdjust[256] = {
82 0, 2, 3, 4, 6, 7, 8, 10, 11, 12, 13, 15, 16, 17, 18, 19,
83 21, 22, 23, 24, 25, 26, 27, 29, 30, 31, 32, 33, 34, 35, 36, 38,
84 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 51, 52, 53, 54, 55,
85 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 71, 72,
86 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88,
87 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104,
88 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120,
89 121, 122, 123, 124, 125, 126, 127, 128, 129, 129, 130, 131, 132, 133, 134, 135,
90 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151,
91 152, 153, 154, 155, 156, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166,
92 167, 168, 169, 170, 171, 172, 173, 174, 174, 175, 176, 177, 178, 179, 180, 181,
93 182, 183, 184, 185, 186, 187, 188, 189, 190, 190, 191, 192, 193, 194, 195, 196,
94 197, 198, 199, 200, 201, 202, 203, 204, 204, 205, 206, 207, 208, 209, 210, 211,
95 212, 213, 214, 215, 216, 217, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226,
96 227, 228, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 239, 240,
97 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 250, 251, 252, 253, 254, 255,
99 #define ADJUST_ALPHA(background, foreground, src_alpha, text_flags, a) \
100 src_alpha = g_TextGammaAdjust[(FX_BYTE)src_alpha];
101 void _Color2Argb(FX_ARGB& argb, FX_DWORD color, int alpha_flag, void* pIccTransform)
103 if (pIccTransform == NULL && !FXGETFLAG_COLORTYPE(alpha_flag)) {
107 if (!CFX_GEModule::Get()->GetCodecModule() || !CFX_GEModule::Get()->GetCodecModule()->GetIccModule()) {
108 pIccTransform = NULL;
112 ICodec_IccModule* pIccModule = CFX_GEModule::Get()->GetCodecModule()->GetIccModule();
113 color = FXGETFLAG_COLORTYPE(alpha_flag) ? FXCMYK_TODIB(color) : FXARGB_TODIB(color);
114 pIccModule->TranslateScanline(pIccTransform, bgra, (FX_LPCBYTE)&color, 1);
115 bgra[3] = FXGETFLAG_COLORTYPE(alpha_flag) ?
116 (alpha_flag >> 24) ? FXGETFLAG_ALPHA_FILL(alpha_flag) : FXGETFLAG_ALPHA_STROKE(alpha_flag) :
118 argb = FXARGB_MAKE(bgra[3], bgra[2], bgra[1], bgra[0]);
121 AdobeCMYK_to_sRGB1(FXSYS_GetCValue(color), FXSYS_GetMValue(color),
122 FXSYS_GetYValue(color), FXSYS_GetKValue(color),
123 bgra[2], bgra[1], bgra[0]);
124 bgra[3] = (alpha_flag >> 24) ? FXGETFLAG_ALPHA_FILL(alpha_flag) : FXGETFLAG_ALPHA_STROKE(alpha_flag);
125 argb = FXARGB_MAKE(bgra[3], bgra[2], bgra[1], bgra[0]);
127 FX_BOOL CFX_RenderDevice::DrawNormalText(int nChars, const FXTEXT_CHARPOS* pCharPos,
128 CFX_Font* pFont, CFX_FontCache* pCache,
129 FX_FLOAT font_size, const CFX_AffineMatrix* pText2Device,
130 FX_DWORD fill_color, FX_DWORD text_flags,
131 int alpha_flag, void* pIccTransform)
133 int nativetext_flags = text_flags;
134 if (m_DeviceClass != FXDC_DISPLAY) {
135 if (!(text_flags & FXTEXT_PRINTGRAPHICTEXT)) {
136 #if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
137 if (!(text_flags & FXFONT_CIDFONT) && pFont->GetPsName().Find(CFX_WideString::FromLocal("+ZJHL")) == -1)
138 #ifdef FOXIT_CHROME_BUILD
139 if (pFont->GetPsName() != CFX_WideString::FromLocal("CNAAJI+cmex10"))
142 if (m_pDeviceDriver->DrawDeviceText(nChars, pCharPos, pFont, pCache, pText2Device, font_size, fill_color, alpha_flag, pIccTransform)) {
146 int alpha = FXGETFLAG_COLORTYPE(alpha_flag) ? FXGETFLAG_ALPHA_FILL(alpha_flag) : FXARGB_A(fill_color);
150 } else if (!(text_flags & FXTEXT_NO_NATIVETEXT)) {
151 #if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
152 if (!(text_flags & FXFONT_CIDFONT))
153 #ifdef FOXIT_CHROME_BUILD
154 if (pFont->GetPsName() != CFX_WideString::FromLocal("CNAAJI+cmex10"))
157 if (m_pDeviceDriver->DrawDeviceText(nChars, pCharPos, pFont, pCache, pText2Device, font_size, fill_color, alpha_flag, pIccTransform)) {
161 CFX_AffineMatrix char2device, deviceCtm, text2Device;
163 char2device = *pText2Device;
164 text2Device = *pText2Device;
166 char2device.Scale(font_size, -font_size);
167 if (FXSYS_fabs(char2device.a) + FXSYS_fabs(char2device.b) > 50 * 1.0f ||
168 ((m_DeviceClass == FXDC_PRINTER && !m_pDeviceDriver->IsPSPrintDriver())
169 && !(text_flags & FXTEXT_PRINTIMAGETEXT))) {
170 if (pFont->GetFace() != NULL || (pFont->GetSubstFont()->m_SubstFlags & FXFONT_SUBST_GLYPHPATH)) {
171 int nPathFlags = (text_flags & FXTEXT_NOSMOOTH) == 0 ? 0 : FXFILL_NOPATHSMOOTH;
172 return DrawTextPath(nChars, pCharPos, pFont, pCache, font_size, pText2Device, NULL, NULL, fill_color, 0, NULL, nPathFlags, alpha_flag, pIccTransform);
175 int anti_alias = FXFT_RENDER_MODE_MONO;
176 FX_BOOL bNormal = FALSE;
177 if ((text_flags & FXTEXT_NOSMOOTH) == 0) {
178 if (m_DeviceClass == FXDC_DISPLAY && m_bpp > 1) {
180 if (pFont->GetFace() == NULL && !(pFont->GetSubstFont()->m_SubstFlags & FXFONT_SUBST_CLEARTYPE)) {
183 bClearType = text_flags & FXTEXT_CLEARTYPE;
185 if ((m_RenderCaps & (FXRC_ALPHA_OUTPUT | FXRC_CMYK_OUTPUT))) {
186 anti_alias = FXFT_RENDER_MODE_LCD;
188 } else if (m_bpp < 16) {
189 anti_alias = FXFT_RENDER_MODE_NORMAL;
191 if (bClearType == FALSE) {
192 anti_alias = FXFT_RENDER_MODE_LCD;
195 anti_alias = FXFT_RENDER_MODE_LCD;
200 if (pCache == NULL) {
201 pCache = CFX_GEModule::Get()->GetFontCache();
203 CFX_FaceCache* pFaceCache = pCache->GetCachedFace(pFont);
204 FX_FONTCACHE_DEFINE(pCache, pFont);
205 FXTEXT_GLYPHPOS* pGlyphAndPos = FX_Alloc(FXTEXT_GLYPHPOS, nChars);
210 deviceCtm = char2device;
211 CFX_AffineMatrix matrixCTM = GetCTM();
212 FX_FLOAT scale_x = FXSYS_fabs(matrixCTM.a);
213 FX_FLOAT scale_y = FXSYS_fabs(matrixCTM.d);
214 deviceCtm.Concat(scale_x, 0, 0, scale_y, 0, 0);
215 text2Device.Concat(scale_x, 0, 0, scale_y, 0, 0);
216 for (iChar = 0; iChar < nChars; iChar ++) {
217 FXTEXT_GLYPHPOS& glyph = pGlyphAndPos[iChar];
218 const FXTEXT_CHARPOS& charpos = pCharPos[iChar];
219 glyph.m_fOriginX = charpos.m_OriginX;
220 glyph.m_fOriginY = charpos.m_OriginY;
221 text2Device.Transform(glyph.m_fOriginX, glyph.m_fOriginY);
222 if (anti_alias < FXFT_RENDER_MODE_LCD) {
223 glyph.m_OriginX = FXSYS_round(glyph.m_fOriginX);
225 glyph.m_OriginX = (int)FXSYS_floor(glyph.m_fOriginX);
227 glyph.m_OriginY = FXSYS_round(glyph.m_fOriginY);
228 if (charpos.m_bGlyphAdjust) {
229 CFX_AffineMatrix new_matrix(charpos.m_AdjustMatrix[0], charpos.m_AdjustMatrix[1],
230 charpos.m_AdjustMatrix[2], charpos.m_AdjustMatrix[3], 0, 0);
231 new_matrix.Concat(deviceCtm);
232 glyph.m_pGlyph = pFaceCache->LoadGlyphBitmap(pFont, charpos.m_GlyphIndex, charpos.m_bFontStyle, &new_matrix,
233 charpos.m_FontCharWidth, anti_alias, nativetext_flags);
235 glyph.m_pGlyph = pFaceCache->LoadGlyphBitmap(pFont, charpos.m_GlyphIndex, charpos.m_bFontStyle, &deviceCtm,
236 charpos.m_FontCharWidth, anti_alias, nativetext_flags);
238 if (anti_alias < FXFT_RENDER_MODE_LCD && nChars > 1) {
239 _AdjustGlyphSpace(pGlyphAndPos, nChars);
241 FX_RECT bmp_rect1 = FXGE_GetGlyphsBBox(pGlyphAndPos, nChars, anti_alias);
242 if (scale_x > 1 && scale_y > 1) {
248 FX_RECT bmp_rect(FXSYS_round((FX_FLOAT)(bmp_rect1.left) / scale_x), FXSYS_round((FX_FLOAT)(bmp_rect1.top) / scale_y),
249 FXSYS_round((FX_FLOAT)bmp_rect1.right / scale_x), FXSYS_round((FX_FLOAT)bmp_rect1.bottom / scale_y));
250 bmp_rect.Intersect(m_ClipBox);
251 if (bmp_rect.IsEmpty()) {
252 FX_Free(pGlyphAndPos);
255 int pixel_width = FXSYS_round(bmp_rect.Width() * scale_x);
256 int pixel_height = FXSYS_round(bmp_rect.Height() * scale_y);
257 int pixel_left = FXSYS_round(bmp_rect.left * scale_x);
258 int pixel_top = FXSYS_round(bmp_rect.top * scale_y);
259 if (anti_alias == FXFT_RENDER_MODE_MONO) {
261 if (!bitmap.Create(pixel_width, pixel_height, FXDIB_1bppMask)) {
262 FX_Free(pGlyphAndPos);
266 for (iChar = 0; iChar < nChars; iChar ++) {
267 FXTEXT_GLYPHPOS& glyph = pGlyphAndPos[iChar];
268 if (glyph.m_pGlyph == NULL) {
271 const CFX_DIBitmap* pGlyph = &glyph.m_pGlyph->m_Bitmap;
272 bitmap.TransferBitmap(glyph.m_OriginX + glyph.m_pGlyph->m_Left - pixel_left,
273 glyph.m_OriginY - glyph.m_pGlyph->m_Top - pixel_top,
274 pGlyph->GetWidth(), pGlyph->GetHeight(), pGlyph, 0, 0);
276 FX_Free(pGlyphAndPos);
277 return SetBitMask(&bitmap, bmp_rect.left, bmp_rect.top, fill_color);
281 if (!bitmap.Create(pixel_width, pixel_height, FXDIB_8bppMask)) {
282 FX_Free(pGlyphAndPos);
286 if (!CreateCompatibleBitmap(&bitmap, pixel_width, pixel_height)) {
287 FX_Free(pGlyphAndPos);
291 if (!bitmap.HasAlpha() && !bitmap.IsAlphaMask()) {
292 bitmap.Clear(0xFFFFFFFF);
293 if (!GetDIBits(&bitmap, bmp_rect.left, bmp_rect.top)) {
294 FX_Free(pGlyphAndPos);
299 if (bitmap.m_pAlphaMask) {
300 bitmap.m_pAlphaMask->Clear(0);
303 int dest_width = pixel_width;
304 FX_LPBYTE dest_buf = bitmap.GetBuffer();
305 int dest_pitch = bitmap.GetPitch();
306 int Bpp = bitmap.GetBPP() / 8;
308 if (anti_alias == FXFT_RENDER_MODE_LCD) {
309 _Color2Argb(fill_color, fill_color, alpha_flag | (1 << 24), pIccTransform);
310 ArgbDecode(fill_color, a, r, g, b);
315 for (iChar = 0; iChar < nChars; iChar ++) {
316 FXTEXT_GLYPHPOS& glyph = pGlyphAndPos[iChar];
317 if (glyph.m_pGlyph == NULL) {
320 const CFX_DIBitmap* pGlyph = &glyph.m_pGlyph->m_Bitmap;
321 int left = glyph.m_OriginX + glyph.m_pGlyph->m_Left - pixel_left;
322 int top = glyph.m_OriginY - glyph.m_pGlyph->m_Top - pixel_top;
323 int ncols = pGlyph->GetWidth();
324 int nrows = pGlyph->GetHeight();
325 if (anti_alias == FXFT_RENDER_MODE_NORMAL) {
326 if (!bitmap.CompositeMask(left, top, ncols, nrows, pGlyph, fill_color,
327 0, 0, FXDIB_BLEND_NORMAL, NULL, FALSE, alpha_flag, pIccTransform)) {
328 FX_Free(pGlyphAndPos);
333 FX_BOOL bBGRStripe = text_flags & FXTEXT_BGR_STRIPE;
335 int x_subpixel = (int)(glyph.m_fOriginX * 3) % 3;
336 FX_LPBYTE src_buf = pGlyph->GetBuffer();
337 int src_pitch = pGlyph->GetPitch();
338 int start_col = left;
342 int end_col = left + ncols;
343 if (end_col > dest_width) {
344 end_col = dest_width;
346 if (start_col >= end_col) {
349 if (bitmap.GetFormat() == FXDIB_Argb) {
350 for (int row = 0; row < nrows; row ++) {
351 int dest_row = row + top;
352 if (dest_row < 0 || dest_row >= bitmap.GetHeight()) {
355 FX_LPBYTE src_scan = src_buf + row * src_pitch + (start_col - left) * 3;
356 FX_LPBYTE dest_scan = dest_buf + dest_row * dest_pitch + (start_col << 2);
358 if (x_subpixel == 0) {
359 for (int col = start_col; col < end_col; col ++) {
360 int src_alpha = src_scan[2];
361 src_alpha = src_alpha * a / 255;
362 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
363 src_alpha = src_scan[1];
364 src_alpha = src_alpha * a / 255;
365 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
366 src_alpha = src_scan[0];
367 src_alpha = src_alpha * a / 255;
368 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
373 } else if (x_subpixel == 1) {
374 int src_alpha = src_scan[1];
375 ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
376 src_alpha = src_alpha * a / 255;
377 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
378 src_alpha = src_scan[0];
379 ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
380 src_alpha = src_alpha * a / 255;
381 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
382 if (start_col > left) {
383 src_alpha = src_scan[-1];
384 ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
385 src_alpha = src_alpha * a / 255;
386 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
391 for (int col = start_col + 1; col < end_col - 1; col ++) {
392 int src_alpha = src_scan[1];
393 ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
394 src_alpha = src_alpha * a / 255;
395 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
396 src_alpha = src_scan[0];
397 ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
398 src_alpha = src_alpha * a / 255;
399 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
400 src_alpha = src_scan[-1];
401 ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
402 src_alpha = src_alpha * a / 255;
403 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
409 int src_alpha = src_scan[0];
410 ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
411 src_alpha = src_alpha * a / 255;
412 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
413 if (start_col > left) {
414 src_alpha = src_scan[-1];
415 ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
416 src_alpha = src_alpha * a / 255;
417 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
418 src_alpha = src_scan[-2];
419 ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
420 src_alpha = src_alpha * a / 255;
421 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
426 for (int col = start_col + 1; col < end_col - 1; col ++) {
427 int src_alpha = src_scan[0];
428 ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
429 src_alpha = src_alpha * a / 255;
430 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
431 src_alpha = src_scan[-1];
432 ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
433 src_alpha = src_alpha * a / 255;
434 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
435 src_alpha = src_scan[-2];
436 ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
437 src_alpha = src_alpha * a / 255;
438 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
445 if (x_subpixel == 0) {
446 for (int col = start_col; col < end_col; col ++) {
448 int src_alpha1 = (src_scan[0] + src_scan[1] + src_scan[2]) / 3;
449 ADJUST_ALPHA(dest_scan[2], r, src_alpha1, nativetext_flags, a);
450 src_alpha1 = src_alpha1 * a / 255;
451 FX_BYTE back_alpha = dest_scan[3];
452 if (back_alpha == 0) {
453 FXARGB_SETDIB(dest_scan, FXARGB_MAKE(src_alpha1, r, g, b));
458 if (src_alpha1 == 0) {
463 FX_BYTE dest_alpha = back_alpha + src_alpha1 - back_alpha * src_alpha1 / 255;
464 dest_scan[3] = dest_alpha;
465 int alpha_ratio = src_alpha1 * 255 / dest_alpha;
466 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, alpha_ratio));
467 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, alpha_ratio));
468 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, alpha_ratio));
473 int src_alpha = src_scan[0];
474 ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
475 src_alpha = src_alpha * a / 255;
476 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
477 src_alpha = src_scan[1];
478 ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
479 src_alpha = src_alpha * a / 255;
480 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
481 src_alpha = src_scan[2];
482 ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
483 src_alpha = src_alpha * a / 255;
484 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
489 } else if (x_subpixel == 1) {
491 int src_alpha1 = start_col > left ? ((src_scan[-1] + src_scan[0] + src_scan[1]) / 3) : ((src_scan[0] + src_scan[1]) / 3);
492 ADJUST_ALPHA(dest_scan[2], r, src_alpha1, nativetext_flags, a);
493 src_alpha1 = src_alpha1 * a / 255;
494 if (src_alpha1 == 0) {
498 FX_BYTE back_alpha = dest_scan[3];
499 if (back_alpha == 0) {
500 FXARGB_SETDIB(dest_scan, FXARGB_MAKE(src_alpha1, r, g, b));
502 FX_BYTE dest_alpha = back_alpha + src_alpha1 - back_alpha * src_alpha1 / 255;
503 dest_scan[3] = dest_alpha;
504 int alpha_ratio = src_alpha1 * 255 / dest_alpha;
505 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, alpha_ratio));
506 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, alpha_ratio));
507 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, alpha_ratio));
513 if (start_col > left) {
514 int src_alpha = src_scan[-1];
515 ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
516 src_alpha = src_alpha * a / 255;
517 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
519 int src_alpha = src_scan[0];
520 ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
521 src_alpha = src_alpha * a / 255;
522 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
523 src_alpha = src_scan[1];
524 ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
525 src_alpha = src_alpha * a / 255;
526 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
531 for (int col = start_col + 1; col < end_col; col ++) {
533 int src_alpha1 = (src_scan[-1] + src_scan[0] + src_scan[1]) / 3;
534 ADJUST_ALPHA(dest_scan[2], r, src_alpha1, nativetext_flags, a);
535 src_alpha1 = src_alpha1 * a / 255;
536 FX_BYTE back_alpha = dest_scan[3];
537 if (back_alpha == 0) {
538 FXARGB_SETDIB(dest_scan, FXARGB_MAKE(src_alpha1, r, g, b));
543 if (src_alpha1 == 0) {
548 FX_BYTE dest_alpha = back_alpha + src_alpha1 - back_alpha * src_alpha1 / 255;
549 dest_scan[3] = dest_alpha;
550 int alpha_ratio = src_alpha1 * 255 / dest_alpha;
551 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, alpha_ratio));
552 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, alpha_ratio));
553 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, alpha_ratio));
558 int src_alpha = src_scan[-1];
559 ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
560 src_alpha = src_alpha * a / 255;
561 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
562 src_alpha = src_scan[0];
563 ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
564 src_alpha = src_alpha * a / 255;
565 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
566 src_alpha = src_scan[1];
567 ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
568 src_alpha = src_alpha * a / 255;
569 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
576 int src_alpha1 = start_col > left ? ((src_scan[-2] + src_scan[-1] + src_scan[0]) / 3) : ((src_scan[0]) / 3);
577 ADJUST_ALPHA(dest_scan[2], r, src_alpha1, nativetext_flags, a);
578 src_alpha1 = src_alpha1 * a / 255;
579 if (src_alpha1 == 0) {
583 FX_BYTE back_alpha = dest_scan[3];
584 if (back_alpha == 0) {
585 FXARGB_SETDIB(dest_scan, FXARGB_MAKE(src_alpha1, r, g, b));
587 FX_BYTE dest_alpha = back_alpha + src_alpha1 - back_alpha * src_alpha1 / 255;
588 dest_scan[3] = dest_alpha;
589 int alpha_ratio = src_alpha1 * 255 / dest_alpha;
590 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, alpha_ratio));
591 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, alpha_ratio));
592 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, alpha_ratio));
598 if (start_col > left) {
599 int src_alpha = src_scan[-2];
600 ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
601 src_alpha = src_alpha * a / 255;
602 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
603 src_alpha = src_scan[-1];
604 ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
605 src_alpha = src_alpha * a / 255;
606 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
608 int src_alpha = src_scan[0];
609 ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
610 src_alpha = src_alpha * a / 255;
611 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
616 for (int col = start_col + 1; col < end_col; col ++) {
618 int src_alpha1 = (src_scan[-2] + src_scan[-1] + src_scan[0]) / 3;
619 ADJUST_ALPHA(dest_scan[2], r, src_alpha1, nativetext_flags, a);
620 src_alpha1 = src_alpha1 * a / 255;
621 FX_BYTE back_alpha = dest_scan[3];
622 if (back_alpha == 0) {
623 FXARGB_SETDIB(dest_scan, FXARGB_MAKE(src_alpha1, r, g, b));
628 if (src_alpha1 == 0) {
633 FX_BYTE dest_alpha = back_alpha + src_alpha1 - back_alpha * src_alpha1 / 255;
634 dest_scan[3] = dest_alpha;
635 int alpha_ratio = src_alpha1 * 255 / dest_alpha;
636 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, alpha_ratio));
637 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, alpha_ratio));
638 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, alpha_ratio));
643 int src_alpha = src_scan[-2];
644 ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
645 src_alpha = src_alpha * a / 255;
646 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
647 src_alpha = src_scan[-1];
648 ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
649 src_alpha = src_alpha * a / 255;
650 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
651 src_alpha = src_scan[0];
652 ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
653 src_alpha = src_alpha * a / 255;
654 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
663 for (int row = 0; row < nrows; row ++) {
664 int dest_row = row + top;
665 if (dest_row < 0 || dest_row >= bitmap.GetHeight()) {
668 FX_LPBYTE src_scan = src_buf + row * src_pitch + (start_col - left) * 3;
669 FX_LPBYTE dest_scan = dest_buf + dest_row * dest_pitch + start_col * Bpp;
671 if (x_subpixel == 0) {
672 for (int col = start_col; col < end_col; col ++) {
673 int src_alpha = src_scan[2];
674 ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
675 src_alpha = src_alpha * a / 255;
676 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
677 src_alpha = src_scan[1];
678 ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
679 src_alpha = src_alpha * a / 255;
680 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
681 src_alpha = src_scan[0];
682 ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
683 src_alpha = src_alpha * a / 255;
684 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
688 } else if (x_subpixel == 1) {
689 int src_alpha = src_scan[1];
690 ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
691 src_alpha = src_alpha * a / 255;
692 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
693 src_alpha = src_scan[0];
694 ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
695 src_alpha = src_alpha * a / 255;
696 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
697 if (start_col > left) {
698 src_alpha = src_scan[-1];
699 ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
700 src_alpha = src_alpha * a / 255;
701 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
705 for (int col = start_col + 1; col < end_col - 1; col ++) {
706 int src_alpha = src_scan[1];
707 ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
708 src_alpha = src_alpha * a / 255;
709 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
710 src_alpha = src_scan[0];
711 ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
712 src_alpha = src_alpha * a / 255;
713 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
714 src_alpha = src_scan[-1];
715 ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
716 src_alpha = src_alpha * a / 255;
717 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
722 int src_alpha = src_scan[0];
723 ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
724 src_alpha = src_alpha * a / 255;
725 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
726 if (start_col > left) {
727 src_alpha = src_scan[-1];
728 ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
729 src_alpha = src_alpha * a / 255;
730 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
731 src_alpha = src_scan[-2];
732 ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
733 src_alpha = src_alpha * a / 255;
734 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
738 for (int col = start_col + 1; col < end_col - 1; col ++) {
739 int src_alpha = src_scan[0];
740 ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
741 src_alpha = src_alpha * a / 255;
742 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
743 src_alpha = src_scan[-1];
744 ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
745 src_alpha = src_alpha * a / 255;
746 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
747 src_alpha = src_scan[-2];
748 ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
749 src_alpha = src_alpha * a / 255;
750 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
756 if (x_subpixel == 0) {
757 for (int col = start_col; col < end_col; col ++) {
759 int src_alpha1 = (src_scan[0] + src_scan[1] + src_scan[2]) / 3;
760 ADJUST_ALPHA(dest_scan[2], r, src_alpha1, nativetext_flags, a);
761 src_alpha1 = src_alpha1 * a / 255;
762 if (src_alpha1 == 0) {
767 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha1));
768 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha1));
769 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha1));
774 int src_alpha = src_scan[0];
775 ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
776 src_alpha = src_alpha * a / 255;
777 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
778 src_alpha = src_scan[1];
779 ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
780 src_alpha = src_alpha * a / 255;
781 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
782 src_alpha = src_scan[2];
783 ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
784 src_alpha = src_alpha * a / 255;
785 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
789 } else if (x_subpixel == 1) {
791 int src_alpha1 = start_col > left ? (src_scan[0] + src_scan[1] + src_scan[-1]) / 3 : (src_scan[0] + src_scan[1]) / 3;
792 ADJUST_ALPHA(dest_scan[2], r, src_alpha1, nativetext_flags, a);
793 src_alpha1 = src_alpha1 * a / 255;
794 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha1));
795 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha1));
796 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha1));
800 if (start_col > left) {
801 int src_alpha = src_scan[-1];
802 ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
803 src_alpha = src_alpha * a / 255;
804 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
806 int src_alpha = src_scan[0];
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[1];
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 for (int col = start_col + 1; col < end_col; col ++) {
819 int src_alpha1 = (src_scan[0] + src_scan[1] + src_scan[-1]) / 3;
820 ADJUST_ALPHA(dest_scan[2], r, src_alpha1, nativetext_flags, a);
821 src_alpha1 = src_alpha1 * a / 255;
822 if (src_alpha1 == 0) {
827 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha1));
828 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha1));
829 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha1));
834 int src_alpha = src_scan[-1];
835 ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
836 src_alpha = src_alpha * a / 255;
837 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
838 src_alpha = src_scan[0];
839 ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
840 src_alpha = src_alpha * a / 255;
841 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
842 src_alpha = src_scan[1];
843 ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
844 src_alpha = src_alpha * a / 255;
845 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
851 int src_alpha1 = start_col > left ? (src_scan[0] + src_scan[-2] + src_scan[-1]) / 3 : src_scan[0] / 3;
852 ADJUST_ALPHA(dest_scan[2], r, src_alpha1, nativetext_flags, a);
853 src_alpha1 = src_alpha1 * a / 255;
854 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha1));
855 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha1));
856 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha1));
860 if (start_col > left) {
861 int src_alpha = src_scan[-2];
862 ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
863 src_alpha = src_alpha * a / 255;
864 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
865 src_alpha = src_scan[-1];
866 ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
867 src_alpha = src_alpha * a / 255;
868 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
870 int src_alpha = src_scan[0];
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));
877 for (int col = start_col + 1; col < end_col; col ++) {
879 int src_alpha1 = ((int)(src_scan[0]) + (int)(src_scan[-2]) + (int)(src_scan[-1])) / 3;
880 ADJUST_ALPHA(dest_scan[2], r, src_alpha1, nativetext_flags, a);
881 src_alpha1 = src_alpha1 * a / 255;
882 if (src_alpha1 == 0) {
887 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha1));
888 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha1));
889 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha1));
894 int src_alpha = src_scan[-2];
895 ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
896 src_alpha = src_alpha * a / 255;
897 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
898 src_alpha = src_scan[-1];
899 ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
900 src_alpha = src_alpha * a / 255;
901 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
902 src_alpha = src_scan[0];
903 ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
904 src_alpha = src_alpha * a / 255;
905 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
914 if (bitmap.IsAlphaMask()) {
915 SetBitMask(&bitmap, bmp_rect.left, bmp_rect.top, fill_color, alpha_flag, pIccTransform);
917 SetDIBits(&bitmap, bmp_rect.left, bmp_rect.top);
919 FX_Free(pGlyphAndPos);
922 FX_BOOL CFX_RenderDevice::DrawTextPath(int nChars, const FXTEXT_CHARPOS* pCharPos,
923 CFX_Font* pFont, CFX_FontCache* pCache,
924 FX_FLOAT font_size, const CFX_AffineMatrix* pText2User,
925 const CFX_AffineMatrix* pUser2Device, const CFX_GraphStateData* pGraphState,
926 FX_DWORD fill_color, FX_ARGB stroke_color, CFX_PathData* pClippingPath, int nFlag,
927 int alpha_flag, void* pIccTransform, int blend_type)
929 if (pCache == NULL) {
930 pCache = CFX_GEModule::Get()->GetFontCache();
932 CFX_FaceCache* pFaceCache = pCache->GetCachedFace(pFont);
933 FX_FONTCACHE_DEFINE(pCache, pFont);
934 for (int iChar = 0; iChar < nChars; iChar ++) {
935 const FXTEXT_CHARPOS& charpos = pCharPos[iChar];
936 CFX_AffineMatrix matrix;
937 if (charpos.m_bGlyphAdjust)
938 matrix.Set(charpos.m_AdjustMatrix[0], charpos.m_AdjustMatrix[1],
939 charpos.m_AdjustMatrix[2], charpos.m_AdjustMatrix[3], 0, 0);
940 matrix.Concat(font_size, 0, 0, font_size, charpos.m_OriginX, charpos.m_OriginY);
941 const CFX_PathData* pPath = pFaceCache->LoadGlyphPath(pFont, charpos.m_GlyphIndex, charpos.m_FontCharWidth);
945 matrix.Concat(*pText2User);
946 CFX_PathData TransformedPath(*pPath);
947 TransformedPath.Transform(&matrix);
948 FX_BOOL bHasAlpha = FXGETFLAG_COLORTYPE(alpha_flag) ?
949 (FXGETFLAG_ALPHA_FILL(alpha_flag) || FXGETFLAG_ALPHA_STROKE(alpha_flag)) :
950 (fill_color || stroke_color);
952 int fill_mode = nFlag;
953 if (FXGETFLAG_COLORTYPE(alpha_flag)) {
954 if (FXGETFLAG_ALPHA_FILL(alpha_flag)) {
955 fill_mode |= FXFILL_WINDING;
959 fill_mode |= FXFILL_WINDING;
962 fill_mode |= FX_FILL_TEXT_MODE;
963 if (!DrawPath(&TransformedPath, pUser2Device, pGraphState, fill_color, stroke_color, fill_mode, alpha_flag, pIccTransform, blend_type)) {
968 pClippingPath->Append(&TransformedPath, pUser2Device);
973 CFX_FontCache::~CFX_FontCache()
977 CFX_FaceCache* CFX_FontCache::GetCachedFace(CFX_Font* pFont)
979 FX_BOOL bExternal = pFont->GetFace() == NULL;
980 void* face = bExternal ? pFont->GetSubstFont()->m_ExtHandle : pFont->GetFace();
981 CFX_FTCacheMap& map = bExternal ? m_ExtFaceMap : m_FTFaceMap;
982 CFX_CountedFaceCache* counted_face_cache = NULL;
983 if (map.Lookup((FXFT_Face)face, counted_face_cache)) {
984 counted_face_cache->m_nCount++;
985 return counted_face_cache->m_Obj;
987 CFX_FaceCache* face_cache = NULL;
988 face_cache = FX_NEW CFX_FaceCache(bExternal ? NULL : (FXFT_Face)face);
989 if (face_cache == NULL) {
992 counted_face_cache = FX_NEW CFX_CountedFaceCache;
993 if (!counted_face_cache) {
1000 counted_face_cache->m_nCount = 2;
1001 counted_face_cache->m_Obj = face_cache;
1002 map.SetAt((FXFT_Face)face, counted_face_cache);
1005 void CFX_FontCache::ReleaseCachedFace(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)) {
1014 if (counted_face_cache->m_nCount > 1) {
1015 counted_face_cache->m_nCount--;
1018 void CFX_FontCache::FreeCache(FX_BOOL bRelease)
1022 pos = m_FTFaceMap.GetStartPosition();
1025 CFX_CountedFaceCache* cache;
1026 m_FTFaceMap.GetNextAssoc(pos, face, cache);
1027 if (bRelease || cache->m_nCount < 2) {
1028 delete cache->m_Obj;
1030 m_FTFaceMap.RemoveKey(face);
1033 pos = m_ExtFaceMap.GetStartPosition();
1036 CFX_CountedFaceCache* cache;
1037 m_ExtFaceMap.GetNextAssoc(pos, face, cache);
1038 if (bRelease || cache->m_nCount < 2) {
1039 delete cache->m_Obj;
1041 m_ExtFaceMap.RemoveKey(face);
1046 CFX_FaceCache::CFX_FaceCache(FXFT_Face face)
1051 CFX_FaceCache::~CFX_FaceCache()
1053 FX_POSITION pos = m_SizeMap.GetStartPosition();
1055 CFX_SizeGlyphCache* pSizeCache = NULL;
1057 m_SizeMap.GetNextAssoc( pos, Key, (void*&)pSizeCache);
1060 m_SizeMap.RemoveAll();
1061 pos = m_PathMap.GetStartPosition();
1063 CFX_PathData* pPath;
1065 m_PathMap.GetNextAssoc(pos, key1, (FX_LPVOID&)pPath);
1071 m_PathMap.RemoveAll();
1073 #if ((_FXM_PLATFORM_ != _FXM_PLATFORM_APPLE_)|| defined(_FPDFAPI_MINI_))
1074 void CFX_FaceCache::InitPlatform()
1078 CFX_GlyphBitmap* CFX_FaceCache::LookUpGlyphBitmap(CFX_Font* pFont, const CFX_AffineMatrix* pMatrix,
1079 CFX_ByteStringC& FaceGlyphsKey, FX_DWORD glyph_index, FX_BOOL bFontStyle,
1080 int dest_width, int anti_alias)
1082 CFX_SizeGlyphCache* pSizeCache = NULL;
1083 if (!m_SizeMap.Lookup(FaceGlyphsKey, (void*&)pSizeCache)) {
1084 pSizeCache = FX_NEW CFX_SizeGlyphCache;
1085 if (pSizeCache == NULL) {
1088 m_SizeMap.SetAt(FaceGlyphsKey, pSizeCache);
1090 CFX_GlyphBitmap* pGlyphBitmap = NULL;
1091 if (pSizeCache->m_GlyphMap.Lookup((FX_LPVOID)(FX_UINTPTR)glyph_index, (void*&)pGlyphBitmap)) {
1092 return pGlyphBitmap;
1094 pGlyphBitmap = RenderGlyph(pFont, glyph_index, bFontStyle, pMatrix, dest_width, anti_alias);
1095 if (pGlyphBitmap == NULL) {
1098 pSizeCache->m_GlyphMap.SetAt((FX_LPVOID)(FX_UINTPTR)glyph_index, pGlyphBitmap);
1099 return pGlyphBitmap;
1101 const CFX_GlyphBitmap* CFX_FaceCache::LoadGlyphBitmap(CFX_Font* pFont, FX_DWORD glyph_index, FX_BOOL bFontStyle, const CFX_AffineMatrix* pMatrix,
1102 int dest_width, int anti_alias, int& text_flags)
1104 if (glyph_index == (FX_DWORD) - 1) {
1107 _CFX_UniqueKeyGen keygen;
1108 #if ((_FXM_PLATFORM_ != _FXM_PLATFORM_APPLE_)|| defined(_FPDFAPI_MINI_))
1109 if (pFont->GetSubstFont())
1110 keygen.Generate(9, (int)(pMatrix->a * 10000), (int)(pMatrix->b * 10000),
1111 (int)(pMatrix->c * 10000), (int)(pMatrix->d * 10000), dest_width, anti_alias,
1112 pFont->GetSubstFont()->m_Weight, pFont->GetSubstFont()->m_ItalicAngle, pFont->IsVertical());
1114 keygen.Generate(6, (int)(pMatrix->a * 10000), (int)(pMatrix->b * 10000),
1115 (int)(pMatrix->c * 10000), (int)(pMatrix->d * 10000), dest_width, anti_alias);
1117 if (text_flags & FXTEXT_NO_NATIVETEXT) {
1118 if (pFont->GetSubstFont())
1119 keygen.Generate(9, (int)(pMatrix->a * 10000), (int)(pMatrix->b * 10000),
1120 (int)(pMatrix->c * 10000), (int)(pMatrix->d * 10000), dest_width, anti_alias,
1121 pFont->GetSubstFont()->m_Weight, pFont->GetSubstFont()->m_ItalicAngle, pFont->IsVertical());
1123 keygen.Generate(6, (int)(pMatrix->a * 10000), (int)(pMatrix->b * 10000),
1124 (int)(pMatrix->c * 10000), (int)(pMatrix->d * 10000), dest_width, anti_alias);
1126 if (pFont->GetSubstFont())
1127 keygen.Generate(10, (int)(pMatrix->a * 10000), (int)(pMatrix->b * 10000),
1128 (int)(pMatrix->c * 10000), (int)(pMatrix->d * 10000), dest_width, anti_alias,
1129 pFont->GetSubstFont()->m_Weight, pFont->GetSubstFont()->m_ItalicAngle, pFont->IsVertical(), 3);
1131 keygen.Generate(7, (int)(pMatrix->a * 10000), (int)(pMatrix->b * 10000),
1132 (int)(pMatrix->c * 10000), (int)(pMatrix->d * 10000), dest_width, anti_alias, 3);
1135 CFX_ByteStringC FaceGlyphsKey(keygen.m_Key, keygen.m_KeyLen);
1136 #if ((_FXM_PLATFORM_ != _FXM_PLATFORM_APPLE_)|| defined(_FPDFAPI_MINI_))
1137 return LookUpGlyphBitmap(pFont, pMatrix, FaceGlyphsKey, glyph_index, bFontStyle, dest_width, anti_alias);
1139 if (text_flags & FXTEXT_NO_NATIVETEXT) {
1140 return LookUpGlyphBitmap(pFont, pMatrix, FaceGlyphsKey, glyph_index, bFontStyle, dest_width, anti_alias);
1142 CFX_GlyphBitmap* pGlyphBitmap;
1143 CFX_SizeGlyphCache* pSizeCache = NULL;
1144 if (m_SizeMap.Lookup(FaceGlyphsKey, (void*&)pSizeCache)) {
1145 if (pSizeCache->m_GlyphMap.Lookup((FX_LPVOID)(FX_UINTPTR)glyph_index, (void*&)pGlyphBitmap)) {
1146 return pGlyphBitmap;
1148 pGlyphBitmap = RenderGlyph_Nativetext(pFont, glyph_index, pMatrix, dest_width, anti_alias);
1150 pSizeCache->m_GlyphMap.SetAt((FX_LPVOID)(FX_UINTPTR)glyph_index, pGlyphBitmap);
1151 return pGlyphBitmap;
1154 pGlyphBitmap = RenderGlyph_Nativetext(pFont, glyph_index, pMatrix, dest_width, anti_alias);
1156 pSizeCache = FX_NEW CFX_SizeGlyphCache;
1157 if (pSizeCache == NULL) {
1160 m_SizeMap.SetAt(FaceGlyphsKey, pSizeCache);
1161 pSizeCache->m_GlyphMap.SetAt((FX_LPVOID)(FX_UINTPTR)glyph_index, pGlyphBitmap);
1162 return pGlyphBitmap;
1165 if (pFont->GetSubstFont())
1166 keygen.Generate(9, (int)(pMatrix->a * 10000), (int)(pMatrix->b * 10000),
1167 (int)(pMatrix->c * 10000), (int)(pMatrix->d * 10000), dest_width, anti_alias,
1168 pFont->GetSubstFont()->m_Weight, pFont->GetSubstFont()->m_ItalicAngle, pFont->IsVertical());
1170 keygen.Generate(6, (int)(pMatrix->a * 10000), (int)(pMatrix->b * 10000),
1171 (int)(pMatrix->c * 10000), (int)(pMatrix->d * 10000), dest_width, anti_alias);
1172 CFX_ByteStringC FaceGlyphsKey(keygen.m_Key, keygen.m_KeyLen);
1173 text_flags |= FXTEXT_NO_NATIVETEXT;
1174 return LookUpGlyphBitmap(pFont, pMatrix, FaceGlyphsKey, glyph_index, bFontStyle, dest_width, anti_alias);
1178 CFX_SizeGlyphCache::~CFX_SizeGlyphCache()
1180 FX_POSITION pos = m_GlyphMap.GetStartPosition();
1182 CFX_GlyphBitmap* pGlyphBitmap = NULL;
1184 m_GlyphMap.GetNextAssoc(pos, Key, (void*&)pGlyphBitmap);
1185 delete pGlyphBitmap;
1187 m_GlyphMap.RemoveAll();
1189 #if defined(_FPDFAPI_MINI_)
1190 #define CONTRAST_RAMP_STEP 16
1192 #define CONTRAST_RAMP_STEP 1
1194 void CFX_Font::AdjustMMParams(int glyph_index, int dest_width, int weight)
1196 FXFT_MM_Var pMasters = NULL;
1197 FXFT_Get_MM_Var(m_Face, &pMasters);
1198 if (pMasters == NULL) {
1203 coords[0] = FXFT_Get_MM_Axis_Def(FXFT_Get_MM_Axis(pMasters, 0)) / 65536;
1207 if (dest_width == 0) {
1208 coords[1] = FXFT_Get_MM_Axis_Def(FXFT_Get_MM_Axis(pMasters, 1)) / 65536;
1210 int min_param = FXFT_Get_MM_Axis_Min(FXFT_Get_MM_Axis(pMasters, 1)) / 65536;
1211 int max_param = FXFT_Get_MM_Axis_Max(FXFT_Get_MM_Axis(pMasters, 1)) / 65536;
1212 coords[1] = min_param;
1213 int error = FXFT_Set_MM_Design_Coordinates(m_Face, 2, coords);
1214 error = FXFT_Load_Glyph(m_Face, glyph_index, FXFT_LOAD_NO_SCALE | FXFT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH);
1215 int min_width = FXFT_Get_Glyph_HoriAdvance(m_Face) * 1000 / FXFT_Get_Face_UnitsPerEM(m_Face);
1216 coords[1] = max_param;
1217 error = FXFT_Set_MM_Design_Coordinates(m_Face, 2, coords);
1218 error = FXFT_Load_Glyph(m_Face, glyph_index, FXFT_LOAD_NO_SCALE | FXFT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH);
1219 int max_width = FXFT_Get_Glyph_HoriAdvance(m_Face) * 1000 / FXFT_Get_Face_UnitsPerEM(m_Face);
1220 if (max_width == min_width) {
1223 int param = min_param + (max_param - min_param) * (dest_width - min_width) / (max_width - min_width);
1226 FXFT_Free(m_Face, pMasters);
1227 FXFT_Set_MM_Design_Coordinates(m_Face, 2, coords);
1229 static const size_t ANGLESKEW_ARRAY_SIZE = 30;
1230 static const char g_AngleSkew[ANGLESKEW_ARRAY_SIZE] = {
1231 0, 2, 3, 5, 7, 9, 11, 12, 14, 16,
1232 18, 19, 21, 23, 25, 27, 29, 31, 32, 34,
1233 36, 38, 40, 42, 45, 47, 49, 51, 53, 55,
1235 static const size_t WEIGHTPOW_ARRAY_SIZE = 100;
1236 static const FX_BYTE g_WeightPow[WEIGHTPOW_ARRAY_SIZE] = {
1237 0, 3, 6, 7, 8, 9, 11, 12, 14, 15, 16, 17, 18, 19, 20,
1238 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 35, 36, 36,
1239 37, 37, 37, 38, 38, 38, 39, 39, 39, 40, 40, 40, 41, 41, 41, 42, 42, 42,
1240 42, 43, 43, 43, 44, 44, 44, 44, 45, 45, 45, 45, 46, 46, 46, 46, 47, 47,
1241 47, 47, 48, 48, 48, 48, 48, 49, 49, 49, 49, 50, 50, 50, 50, 50, 51, 51,
1242 51, 51, 51, 52, 52, 52, 52, 52, 53, 53, 53, 53, 53,
1244 static const FX_BYTE g_WeightPow_11[WEIGHTPOW_ARRAY_SIZE] = {
1245 0, 4, 7, 8, 9, 10, 12, 13, 15, 17, 18, 19, 20, 21, 22,
1246 23, 24, 25, 26, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 39, 39, 40, 40,
1247 41, 41, 41, 42, 42, 42, 43, 43, 43, 44, 44, 44, 45, 45, 45, 46, 46, 46,
1248 46, 43, 47, 47, 48, 48, 48, 48, 45, 50, 50, 50, 46, 51, 51, 51, 52, 52,
1249 52, 52, 53, 53, 53, 53, 53, 54, 54, 54, 54, 55, 55, 55, 55, 55, 56, 56,
1250 56, 56, 56, 57, 57, 57, 57, 57, 58, 58, 58, 58, 58,
1252 static const FX_BYTE g_WeightPow_SHIFTJIS[WEIGHTPOW_ARRAY_SIZE] = {
1253 0, 0, 1, 2, 3, 4, 5, 7, 8, 10, 11, 13, 14, 16, 17, 19, 21, 22, 24, 26, 28,
1254 30, 32, 33, 35, 37, 39, 41, 43, 45, 48, 48, 48, 48, 49, 49, 49, 50, 50, 50, 50,
1255 51, 51, 51, 51, 52, 52, 52, 52, 52, 53, 53, 53, 53, 53, 54, 54, 54, 54, 54, 55, 55,
1256 55, 55, 55, 56, 56, 56, 56, 56 , 56, 57, 57, 57 , 57 , 57, 57, 57, 58, 58, 58, 58, 58,
1257 58, 58, 59, 59, 59, 59, 59, 59, 59, 60, 60, 60, 60, 60, 60, 60, 60,
1259 static void _GammaAdjust(FX_LPBYTE pData, int nWid, int nHei, int src_pitch, FX_LPCBYTE gammaTable)
1261 int count = nHei * src_pitch;
1262 for(int i = 0; i < count; i++) {
1263 pData[i] = gammaTable[pData[i]];
1266 static void _ContrastAdjust(FX_LPBYTE pDataIn, FX_LPBYTE pDataOut, int nWid, int nHei, int nSrcRowBytes, int nDstRowBytes)
1269 int max = 0, min = 255;
1271 for (row = 0; row < nHei; row ++) {
1272 FX_LPBYTE pRow = pDataIn + row * nSrcRowBytes;
1273 for (col = 0; col < nWid; col++) {
1284 if (0 == temp || 255 == temp) {
1285 int rowbytes = FXSYS_abs(nSrcRowBytes) > nDstRowBytes ? nDstRowBytes : FXSYS_abs(nSrcRowBytes);
1286 for (row = 0; row < nHei; row ++) {
1287 FXSYS_memcpy32(pDataOut + row * nDstRowBytes, pDataIn + row * nSrcRowBytes, rowbytes);
1291 rate = 255.f / temp;
1292 for (row = 0; row < nHei; row ++) {
1293 FX_LPBYTE pSrcRow = pDataIn + row * nSrcRowBytes;
1294 FX_LPBYTE pDstRow = pDataOut + row * nDstRowBytes;
1295 for (col = 0; col < nWid; col ++) {
1296 temp = (int)((*(pSrcRow++) - min) * rate + 0.5);
1299 } else if (temp < 0) {
1302 *pDstRow ++ = (FX_BYTE)temp;
1306 CFX_GlyphBitmap* CFX_FaceCache::RenderGlyph(CFX_Font* pFont, FX_DWORD glyph_index, FX_BOOL bFontStyle,
1307 const CFX_AffineMatrix* pMatrix, int dest_width, int anti_alias)
1309 if (m_Face == NULL) {
1312 FXFT_Matrix ft_matrix;
1313 ft_matrix.xx = (signed long)(pMatrix->GetA() / 64 * 65536);
1314 ft_matrix.xy = (signed long)(pMatrix->GetC() / 64 * 65536);
1315 ft_matrix.yx = (signed long)(pMatrix->GetB() / 64 * 65536);
1316 ft_matrix.yy = (signed long)(pMatrix->GetD() / 64 * 65536);
1317 FX_BOOL bUseCJKSubFont = FALSE;
1318 const CFX_SubstFont* pSubstFont = pFont->GetSubstFont();
1320 bUseCJKSubFont = pSubstFont->m_bSubstOfCJK && bFontStyle;
1322 if (bUseCJKSubFont) {
1323 skew = pSubstFont->m_bItlicCJK ? -15 : 0;
1325 skew = pSubstFont->m_ItalicAngle;
1328 skew = skew <= -ANGLESKEW_ARRAY_SIZE ? -58 : -g_AngleSkew[-skew];
1329 if (pFont->IsVertical()) {
1330 ft_matrix.yx += ft_matrix.yy * skew / 100;
1332 ft_matrix.xy += -ft_matrix.xx * skew / 100;
1335 if (pSubstFont->m_SubstFlags & FXFONT_SUBST_MM) {
1336 pFont->AdjustMMParams(glyph_index, dest_width, pFont->GetSubstFont()->m_Weight);
1339 int transflag = FXFT_Get_Face_Internal_Flag(m_Face);
1340 FXFT_Set_Transform(m_Face, &ft_matrix, 0);
1341 int load_flags = (m_Face->face_flags & FT_FACE_FLAG_SFNT) ? FXFT_LOAD_NO_BITMAP : (FXFT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING);
1342 int error = FXFT_Load_Glyph(m_Face, glyph_index, load_flags);
1344 FXFT_Set_Face_Internal_Flag(m_Face, transflag);
1348 if (bUseCJKSubFont) {
1349 weight = pSubstFont->m_WeightCJK;
1351 weight = pSubstFont ? pSubstFont->m_Weight : 0;
1353 if (pSubstFont && !(pSubstFont->m_SubstFlags & FXFONT_SUBST_MM) && weight > 400) {
1354 int index = (weight - 400) / 10;
1355 if (index >= WEIGHTPOW_ARRAY_SIZE) {
1356 FXFT_Set_Face_Internal_Flag(m_Face, transflag);
1360 if (pSubstFont->m_Charset == FXFONT_SHIFTJIS_CHARSET) {
1361 level = g_WeightPow_SHIFTJIS[index] * 2 * (FXSYS_abs((int)(ft_matrix.xx)) + FXSYS_abs((int)(ft_matrix.xy))) / 36655;
1363 level = g_WeightPow_11[index] * (FXSYS_abs((int)(ft_matrix.xx)) + FXSYS_abs((int)(ft_matrix.xy))) / 36655;
1365 FXFT_Outline_Embolden(FXFT_Get_Glyph_Outline(m_Face), level);
1367 FXFT_Library_SetLcdFilter(CFX_GEModule::Get()->GetFontMgr()->m_FTLibrary, FT_LCD_FILTER_DEFAULT);
1368 error = FXFT_Render_Glyph(m_Face, anti_alias);
1370 FXFT_Set_Face_Internal_Flag(m_Face, transflag);
1373 int bmwidth = FXFT_Get_Bitmap_Width(FXFT_Get_Glyph_Bitmap(m_Face));
1374 int bmheight = FXFT_Get_Bitmap_Rows(FXFT_Get_Glyph_Bitmap(m_Face));
1375 if (bmwidth > 2048 || bmheight > 2048) {
1376 FXFT_Set_Face_Internal_Flag(m_Face, transflag);
1379 int dib_width = bmwidth;
1380 CFX_GlyphBitmap* pGlyphBitmap = FX_NEW CFX_GlyphBitmap;
1381 if (!pGlyphBitmap) {
1384 pGlyphBitmap->m_Bitmap.Create(dib_width, bmheight,
1385 anti_alias == FXFT_RENDER_MODE_MONO ? FXDIB_1bppMask : FXDIB_8bppMask);
1386 pGlyphBitmap->m_Left = FXFT_Get_Glyph_BitmapLeft(m_Face);
1387 pGlyphBitmap->m_Top = FXFT_Get_Glyph_BitmapTop(m_Face);
1388 int dest_pitch = pGlyphBitmap->m_Bitmap.GetPitch();
1389 int src_pitch = FXFT_Get_Bitmap_Pitch(FXFT_Get_Glyph_Bitmap(m_Face));
1390 FX_BYTE* pDestBuf = pGlyphBitmap->m_Bitmap.GetBuffer();
1391 FX_BYTE* pSrcBuf = (FX_BYTE*)FXFT_Get_Bitmap_Buffer(FXFT_Get_Glyph_Bitmap(m_Face));
1392 if (anti_alias != FXFT_RENDER_MODE_MONO && FXFT_Get_Bitmap_PixelMode(FXFT_Get_Glyph_Bitmap(m_Face)) == FXFT_PIXEL_MODE_MONO) {
1393 int bytes = anti_alias == FXFT_RENDER_MODE_LCD ? 3 : 1;
1394 for(int i = 0; i < bmheight; i++)
1395 for(int n = 0; n < bmwidth; n++) {
1396 FX_BYTE data = (pSrcBuf[i * src_pitch + n / 8] & (0x80 >> (n % 8))) ? 255 : 0;
1397 for (int b = 0; b < bytes; b ++) {
1398 pDestBuf[i * dest_pitch + n * bytes + b] = data;
1402 FXSYS_memset32(pDestBuf, 0, dest_pitch * bmheight);
1403 if (anti_alias == FXFT_RENDER_MODE_MONO && FXFT_Get_Bitmap_PixelMode(FXFT_Get_Glyph_Bitmap(m_Face)) == FXFT_PIXEL_MODE_MONO) {
1404 int rowbytes = FXSYS_abs(src_pitch) > dest_pitch ? dest_pitch : FXSYS_abs(src_pitch);
1405 for (int row = 0; row < bmheight; row ++) {
1406 FXSYS_memcpy32(pDestBuf + row * dest_pitch, pSrcBuf + row * src_pitch, rowbytes);
1409 _ContrastAdjust(pSrcBuf, pDestBuf, bmwidth, bmheight, src_pitch, dest_pitch);
1410 _GammaAdjust(pDestBuf, bmwidth, bmheight, dest_pitch, CFX_GEModule::Get()->GetTextGammaTable());
1413 FXFT_Set_Face_Internal_Flag(m_Face, transflag);
1414 return pGlyphBitmap;
1416 FX_BOOL _OutputGlyph(void* dib, int x, int y, CFX_Font* pFont,
1417 int glyph_index, FX_ARGB argb)
1419 CFX_DIBitmap* pDib = (CFX_DIBitmap*)dib;
1420 FXFT_Face face = pFont->GetFace();
1421 int error = FXFT_Load_Glyph(face, glyph_index, FXFT_LOAD_NO_BITMAP);
1425 error = FXFT_Render_Glyph(face, FXFT_RENDER_MODE_NORMAL);
1429 int bmwidth = FXFT_Get_Bitmap_Width(FXFT_Get_Glyph_Bitmap(face));
1430 int bmheight = FXFT_Get_Bitmap_Rows(FXFT_Get_Glyph_Bitmap(face));
1431 int left = FXFT_Get_Glyph_BitmapLeft(face);
1432 int top = FXFT_Get_Glyph_BitmapTop(face);
1433 FX_LPCBYTE src_buf = (FX_LPCBYTE)FXFT_Get_Bitmap_Buffer(FXFT_Get_Glyph_Bitmap(face));
1434 int src_pitch = FXFT_Get_Bitmap_Pitch(FXFT_Get_Glyph_Bitmap(face));
1436 mask.Create(bmwidth, bmheight, FXDIB_8bppMask);
1437 FX_LPBYTE dest_buf = mask.GetBuffer();
1438 int dest_pitch = mask.GetPitch();
1439 for (int row = 0; row < bmheight; row ++) {
1440 FX_LPCBYTE src_scan = src_buf + row * src_pitch;
1441 FX_LPBYTE dest_scan = dest_buf + row * dest_pitch;
1442 FXSYS_memcpy32(dest_scan, src_scan, dest_pitch);
1444 pDib->CompositeMask(x + left, y - top, bmwidth, bmheight, &mask, argb, 0, 0);
1447 FX_BOOL OutputText(void* dib, int x, int y, CFX_Font* pFont, double font_size,
1448 CFX_AffineMatrix* pText_matrix, unsigned short const* text, unsigned long argb)
1453 FXFT_Face face = pFont->GetFace();
1454 FXFT_Select_Charmap(pFont->m_Face, FXFT_ENCODING_UNICODE);
1455 int transflag = FXFT_Get_Face_Internal_Flag(pFont->m_Face);
1457 FXFT_Matrix ft_matrix;
1458 ft_matrix.xx = (signed long)(pText_matrix->a / 64 * 65536);
1459 ft_matrix.xy = (signed long)(pText_matrix->c / 64 * 65536);
1460 ft_matrix.yx = (signed long)(pText_matrix->b / 64 * 65536);
1461 ft_matrix.yy = (signed long)(pText_matrix->d / 64 * 65536);
1462 FXFT_Set_Transform(face, &ft_matrix, 0);
1465 for (; *text != 0; text ++) {
1466 FX_WCHAR unicode = *text;
1467 int glyph_index = FXFT_Get_Char_Index(pFont->m_Face, unicode);
1468 if (glyph_index <= 0) {
1471 int err = FXFT_Load_Glyph(pFont->m_Face, glyph_index, FXFT_LOAD_NO_SCALE | FXFT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH);
1475 int w = FXFT_Get_Glyph_HoriAdvance(pFont->m_Face);
1476 int em = FXFT_Get_Face_UnitsPerEM(pFont->m_Face);
1478 pText_matrix->Transform(x_pos, 0, x1, y1);
1479 _OutputGlyph(dib, (int)x1 + x, (int) - y1 + y, pFont,
1481 x_pos += (FX_FLOAT)w / em;
1483 FXFT_Set_Face_Internal_Flag(pFont->m_Face, transflag);
1486 FX_BOOL OutputGlyph(void* dib, int x, int y, CFX_Font* pFont, double font_size,
1487 CFX_AffineMatrix* pMatrix, unsigned long glyph_index, unsigned long argb)
1489 FXFT_Matrix ft_matrix;
1491 ft_matrix.xx = (signed long)(pMatrix->a * font_size / 64 * 65536);
1492 ft_matrix.xy = (signed long)(pMatrix->c * font_size / 64 * 65536);
1493 ft_matrix.yx = (signed long)(pMatrix->b * font_size / 64 * 65536);
1494 ft_matrix.yy = (signed long)(pMatrix->d * font_size / 64 * 65536);
1496 ft_matrix.xx = (signed long)(font_size / 64 * 65536);
1497 ft_matrix.xy = ft_matrix.yx = 0;
1498 ft_matrix.yy = (signed long)(font_size / 64 * 65536);
1500 int transflag = FXFT_Get_Face_Internal_Flag(pFont->m_Face);
1501 FXFT_Set_Transform(pFont->m_Face, &ft_matrix, 0);
1502 FX_BOOL ret = _OutputGlyph(dib, x, y, pFont,
1504 FXFT_Set_Face_Internal_Flag(pFont->m_Face, transflag);
1507 const CFX_PathData* CFX_FaceCache::LoadGlyphPath(CFX_Font* pFont, FX_DWORD glyph_index, int dest_width)
1509 if (m_Face == NULL || glyph_index == (FX_DWORD) - 1) {
1512 CFX_PathData* pGlyphPath = NULL;
1514 if (pFont->GetSubstFont())
1515 key = (FX_LPVOID)(FX_UINTPTR)(glyph_index + ((pFont->GetSubstFont()->m_Weight / 16) << 15) +
1516 ((pFont->GetSubstFont()->m_ItalicAngle / 2) << 21) + ((dest_width / 16) << 25) +
1517 (pFont->IsVertical() << 31));
1519 key = (FX_LPVOID)(FX_UINTPTR)glyph_index;
1521 if (m_PathMap.Lookup(key, (FX_LPVOID&)pGlyphPath)) {
1524 pGlyphPath = pFont->LoadGlyphPath(glyph_index, dest_width);
1525 m_PathMap.SetAt(key, pGlyphPath);
1531 FX_PATHPOINT* m_pPoints;
1534 FX_FLOAT m_CoordUnit;
1536 void _Outline_CheckEmptyContour(OUTLINE_PARAMS* param)
1538 if (param->m_PointCount >= 2 && param->m_pPoints[param->m_PointCount - 2].m_Flag == FXPT_MOVETO &&
1539 param->m_pPoints[param->m_PointCount - 2].m_PointX == param->m_pPoints[param->m_PointCount - 1].m_PointX &&
1540 param->m_pPoints[param->m_PointCount - 2].m_PointY == param->m_pPoints[param->m_PointCount - 1].m_PointY) {
1541 param->m_PointCount -= 2;
1543 if (param->m_PointCount >= 4 && param->m_pPoints[param->m_PointCount - 4].m_Flag == FXPT_MOVETO &&
1544 param->m_pPoints[param->m_PointCount - 3].m_Flag == FXPT_BEZIERTO &&
1545 param->m_pPoints[param->m_PointCount - 3].m_PointX == param->m_pPoints[param->m_PointCount - 4].m_PointX &&
1546 param->m_pPoints[param->m_PointCount - 3].m_PointY == param->m_pPoints[param->m_PointCount - 4].m_PointY &&
1547 param->m_pPoints[param->m_PointCount - 2].m_PointX == param->m_pPoints[param->m_PointCount - 4].m_PointX &&
1548 param->m_pPoints[param->m_PointCount - 2].m_PointY == param->m_pPoints[param->m_PointCount - 4].m_PointY &&
1549 param->m_pPoints[param->m_PointCount - 1].m_PointX == param->m_pPoints[param->m_PointCount - 4].m_PointX &&
1550 param->m_pPoints[param->m_PointCount - 1].m_PointY == param->m_pPoints[param->m_PointCount - 4].m_PointY) {
1551 param->m_PointCount -= 4;
1555 static int _Outline_MoveTo(const FXFT_Vector* to, void* user)
1557 OUTLINE_PARAMS* param = (OUTLINE_PARAMS*)user;
1558 if (!param->m_bCount) {
1559 _Outline_CheckEmptyContour(param);
1560 param->m_pPoints[param->m_PointCount].m_PointX = to->x / param->m_CoordUnit;
1561 param->m_pPoints[param->m_PointCount].m_PointY = to->y / param->m_CoordUnit;
1562 param->m_pPoints[param->m_PointCount].m_Flag = FXPT_MOVETO;
1563 param->m_CurX = to->x;
1564 param->m_CurY = to->y;
1565 if (param->m_PointCount) {
1566 param->m_pPoints[param->m_PointCount - 1].m_Flag |= FXPT_CLOSEFIGURE;
1569 param->m_PointCount ++;
1574 static int _Outline_LineTo(const FXFT_Vector* to, void* user)
1576 OUTLINE_PARAMS* param = (OUTLINE_PARAMS*)user;
1577 if (!param->m_bCount) {
1578 param->m_pPoints[param->m_PointCount].m_PointX = to->x / param->m_CoordUnit;
1579 param->m_pPoints[param->m_PointCount].m_PointY = to->y / param->m_CoordUnit;
1580 param->m_pPoints[param->m_PointCount].m_Flag = FXPT_LINETO;
1581 param->m_CurX = to->x;
1582 param->m_CurY = to->y;
1584 param->m_PointCount ++;
1589 static int _Outline_ConicTo(const FXFT_Vector* control, const FXFT_Vector* to, void* user)
1591 OUTLINE_PARAMS* param = (OUTLINE_PARAMS*)user;
1592 if (!param->m_bCount) {
1593 param->m_pPoints[param->m_PointCount].m_PointX = (param->m_CurX + (control->x - param->m_CurX) * 2 / 3) / param->m_CoordUnit;
1594 param->m_pPoints[param->m_PointCount].m_PointY = (param->m_CurY + (control->y - param->m_CurY) * 2 / 3) / param->m_CoordUnit;
1595 param->m_pPoints[param->m_PointCount].m_Flag = FXPT_BEZIERTO;
1596 param->m_pPoints[param->m_PointCount + 1].m_PointX = (control->x + (to->x - control->x) / 3) / param->m_CoordUnit;
1597 param->m_pPoints[param->m_PointCount + 1].m_PointY = (control->y + (to->y - control->y) / 3) / param->m_CoordUnit;
1598 param->m_pPoints[param->m_PointCount + 1].m_Flag = FXPT_BEZIERTO;
1599 param->m_pPoints[param->m_PointCount + 2].m_PointX = to->x / param->m_CoordUnit;
1600 param->m_pPoints[param->m_PointCount + 2].m_PointY = to->y / param->m_CoordUnit;
1601 param->m_pPoints[param->m_PointCount + 2].m_Flag = FXPT_BEZIERTO;
1602 param->m_CurX = to->x;
1603 param->m_CurY = to->y;
1605 param->m_PointCount += 3;
1610 static int _Outline_CubicTo(const FXFT_Vector* control1, const FXFT_Vector* control2, const FXFT_Vector* to, void* user)
1612 OUTLINE_PARAMS* param = (OUTLINE_PARAMS*)user;
1613 if (!param->m_bCount) {
1614 param->m_pPoints[param->m_PointCount].m_PointX = control1->x / param->m_CoordUnit;
1615 param->m_pPoints[param->m_PointCount].m_PointY = control1->y / param->m_CoordUnit;
1616 param->m_pPoints[param->m_PointCount].m_Flag = FXPT_BEZIERTO;
1617 param->m_pPoints[param->m_PointCount + 1].m_PointX = control2->x / param->m_CoordUnit;
1618 param->m_pPoints[param->m_PointCount + 1].m_PointY = control2->y / param->m_CoordUnit;
1619 param->m_pPoints[param->m_PointCount + 1].m_Flag = FXPT_BEZIERTO;
1620 param->m_pPoints[param->m_PointCount + 2].m_PointX = to->x / param->m_CoordUnit;
1621 param->m_pPoints[param->m_PointCount + 2].m_PointY = to->y / param->m_CoordUnit;
1622 param->m_pPoints[param->m_PointCount + 2].m_Flag = FXPT_BEZIERTO;
1623 param->m_CurX = to->x;
1624 param->m_CurY = to->y;
1626 param->m_PointCount += 3;
1630 CFX_PathData* CFX_Font::LoadGlyphPath(FX_DWORD glyph_index, int dest_width)
1632 if (m_Face == NULL) {
1635 FXFT_Set_Pixel_Sizes(m_Face, 0, 64);
1636 FXFT_Matrix ft_matrix = {65536, 0, 0, 65536};
1638 if (m_pSubstFont->m_ItalicAngle) {
1639 int skew = m_pSubstFont->m_ItalicAngle;
1640 skew = skew <= -ANGLESKEW_ARRAY_SIZE ? -58 : -g_AngleSkew[-skew];
1642 ft_matrix.yx += ft_matrix.yy * skew / 100;
1644 ft_matrix.xy += -ft_matrix.xx * skew / 100;
1647 if (m_pSubstFont->m_SubstFlags & FXFONT_SUBST_MM) {
1648 AdjustMMParams(glyph_index, dest_width, m_pSubstFont->m_Weight);
1651 int transflag = FXFT_Get_Face_Internal_Flag(m_Face);
1652 FXFT_Set_Transform(m_Face, &ft_matrix, 0);
1653 int load_flags = (m_Face->face_flags & FT_FACE_FLAG_SFNT) ? FXFT_LOAD_NO_BITMAP : FXFT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING;
1654 int error = FXFT_Load_Glyph(m_Face, glyph_index, load_flags);
1656 FXFT_Set_Face_Internal_Flag(m_Face, transflag);
1659 if (m_pSubstFont && !(m_pSubstFont->m_SubstFlags & FXFONT_SUBST_MM) && m_pSubstFont->m_Weight > 400) {
1660 int index = (m_pSubstFont->m_Weight - 400) / 10;
1661 if (index >= WEIGHTPOW_ARRAY_SIZE)
1662 index = WEIGHTPOW_ARRAY_SIZE - 1;
1664 if (m_pSubstFont->m_Charset == FXFONT_SHIFTJIS_CHARSET) {
1665 level = g_WeightPow_SHIFTJIS[index] * 2 * 65536 / 36655;
1667 level = g_WeightPow[index] * 2;
1669 FXFT_Outline_Embolden(FXFT_Get_Glyph_Outline(m_Face), level);
1671 FXFT_Outline_Funcs funcs;
1672 funcs.move_to = _Outline_MoveTo;
1673 funcs.line_to = _Outline_LineTo;
1674 funcs.conic_to = _Outline_ConicTo;
1675 funcs.cubic_to = _Outline_CubicTo;
1678 OUTLINE_PARAMS params;
1679 params.m_bCount = TRUE;
1680 params.m_PointCount = 0;
1681 FXFT_Outline_Decompose(FXFT_Get_Glyph_Outline(m_Face), &funcs, ¶ms);
1682 if (params.m_PointCount == 0) {
1683 FXFT_Set_Face_Internal_Flag(m_Face, transflag);
1686 CFX_PathData* pPath = FX_NEW CFX_PathData;
1690 pPath->SetPointCount(params.m_PointCount);
1691 params.m_bCount = FALSE;
1692 params.m_PointCount = 0;
1693 params.m_pPoints = pPath->GetPoints();
1694 params.m_CurX = params.m_CurY = 0;
1695 params.m_CoordUnit = 64 * 64.0;
1696 FXFT_Outline_Decompose(FXFT_Get_Glyph_Outline(m_Face), &funcs, ¶ms);
1697 _Outline_CheckEmptyContour(¶ms);
1698 pPath->TrimPoints(params.m_PointCount);
1699 if (params.m_PointCount) {
1700 pPath->GetPoints()[params.m_PointCount - 1].m_Flag |= FXPT_CLOSEFIGURE;
1702 FXFT_Set_Face_Internal_Flag(m_Face, transflag);
1705 void _CFX_UniqueKeyGen::Generate(int count, ...)
1708 va_start(argList, count);
1709 for (int i = 0; i < count; i ++) {
1710 int p = va_arg(argList, int);
1711 ((FX_DWORD*)m_Key)[i] = p;
1714 m_KeyLen = count * sizeof(FX_DWORD);