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 extern const char g_AngleSkew[30] = {
1230 0, 2, 3, 5, 7, 9, 11, 12, 14, 16,
1231 18, 19, 21, 23, 25, 27, 29, 31, 32, 34,
1232 36, 38, 40, 42, 45, 47, 49, 51, 53, 55,
1234 static const FX_BYTE g_WeightPow[100] = {
1235 0, 3, 6, 7, 8, 9, 11, 12, 14, 15, 16, 17, 18, 19, 20,
1236 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 35, 36, 36,
1237 37, 37, 37, 38, 38, 38, 39, 39, 39, 40, 40, 40, 41, 41, 41, 42, 42, 42,
1238 42, 43, 43, 43, 44, 44, 44, 44, 45, 45, 45, 45, 46, 46, 46, 46, 47, 47,
1239 47, 47, 48, 48, 48, 48, 48, 49, 49, 49, 49, 50, 50, 50, 50, 50, 51, 51,
1240 51, 51, 51, 52, 52, 52, 52, 52, 53, 53, 53, 53, 53,
1242 extern const FX_BYTE g_WeightPow_11[100] = {
1243 0, 4, 7, 8, 9, 10, 12, 13, 15, 17, 18, 19, 20, 21, 22,
1244 23, 24, 25, 26, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 39, 39, 40, 40,
1245 41, 41, 41, 42, 42, 42, 43, 43, 43, 44, 44, 44, 45, 45, 45, 46, 46, 46,
1246 46, 43, 47, 47, 48, 48, 48, 48, 45, 50, 50, 50, 46, 51, 51, 51, 52, 52,
1247 52, 52, 53, 53, 53, 53, 53, 54, 54, 54, 54, 55, 55, 55, 55, 55, 56, 56,
1248 56, 56, 56, 57, 57, 57, 57, 57, 58, 58, 58, 58, 58,
1250 extern const FX_BYTE g_WeightPow_SHIFTJIS[100] = {
1251 0, 0, 1, 2, 3, 4, 5, 7, 8, 10, 11, 13, 14, 16, 17, 19, 21, 22, 24, 26, 28,
1252 30, 32, 33, 35, 37, 39, 41, 43, 45, 48, 48, 48, 48, 49, 49, 49, 50, 50, 50, 50,
1253 51, 51, 51, 51, 52, 52, 52, 52, 52, 53, 53, 53, 53, 53, 54, 54, 54, 54, 54, 55, 55,
1254 55, 55, 55, 56, 56, 56, 56, 56 , 56, 57, 57, 57 , 57 , 57, 57, 57, 58, 58, 58, 58, 58,
1255 58, 58, 59, 59, 59, 59, 59, 59, 59, 60, 60, 60, 60, 60, 60, 60, 60,
1257 static void _GammaAdjust(FX_LPBYTE pData, int nWid, int nHei, int src_pitch, FX_LPCBYTE gammaTable)
1259 int count = nHei * src_pitch;
1260 for(int i = 0; i < count; i++) {
1261 pData[i] = gammaTable[pData[i]];
1264 static void _ContrastAdjust(FX_LPBYTE pDataIn, FX_LPBYTE pDataOut, int nWid, int nHei, int nSrcRowBytes, int nDstRowBytes)
1267 int max = 0, min = 255;
1269 for (row = 0; row < nHei; row ++) {
1270 FX_LPBYTE pRow = pDataIn + row * nSrcRowBytes;
1271 for (col = 0; col < nWid; col++) {
1282 if (0 == temp || 255 == temp) {
1283 int rowbytes = FXSYS_abs(nSrcRowBytes) > nDstRowBytes ? nDstRowBytes : FXSYS_abs(nSrcRowBytes);
1284 for (row = 0; row < nHei; row ++) {
1285 FXSYS_memcpy32(pDataOut + row * nDstRowBytes, pDataIn + row * nSrcRowBytes, rowbytes);
1289 rate = 255.f / temp;
1290 for (row = 0; row < nHei; row ++) {
1291 FX_LPBYTE pSrcRow = pDataIn + row * nSrcRowBytes;
1292 FX_LPBYTE pDstRow = pDataOut + row * nDstRowBytes;
1293 for (col = 0; col < nWid; col ++) {
1294 temp = (int)((*(pSrcRow++) - min) * rate + 0.5);
1297 } else if (temp < 0) {
1300 *pDstRow ++ = (FX_BYTE)temp;
1304 CFX_GlyphBitmap* CFX_FaceCache::RenderGlyph(CFX_Font* pFont, FX_DWORD glyph_index, FX_BOOL bFontStyle,
1305 const CFX_AffineMatrix* pMatrix, int dest_width, int anti_alias)
1307 if (m_Face == NULL) {
1310 FXFT_Matrix ft_matrix;
1311 ft_matrix.xx = (signed long)(pMatrix->GetA() / 64 * 65536);
1312 ft_matrix.xy = (signed long)(pMatrix->GetC() / 64 * 65536);
1313 ft_matrix.yx = (signed long)(pMatrix->GetB() / 64 * 65536);
1314 ft_matrix.yy = (signed long)(pMatrix->GetD() / 64 * 65536);
1315 FX_BOOL bUseCJKSubFont = FALSE;
1316 const CFX_SubstFont* pSubstFont = pFont->GetSubstFont();
1318 bUseCJKSubFont = pSubstFont->m_bSubstOfCJK && bFontStyle;
1320 if (bUseCJKSubFont) {
1321 skew = pSubstFont->m_bItlicCJK ? -15 : 0;
1323 skew = pSubstFont->m_ItalicAngle;
1326 skew = skew <= -30 ? -58 : -g_AngleSkew[-skew];
1327 if (pFont->IsVertical()) {
1328 ft_matrix.yx += ft_matrix.yy * skew / 100;
1330 ft_matrix.xy += -ft_matrix.xx * skew / 100;
1333 if (pSubstFont->m_SubstFlags & FXFONT_SUBST_MM) {
1334 pFont->AdjustMMParams(glyph_index, dest_width, pFont->GetSubstFont()->m_Weight);
1337 int transflag = FXFT_Get_Face_Internal_Flag(m_Face);
1338 FXFT_Set_Transform(m_Face, &ft_matrix, 0);
1339 int load_flags = (m_Face->face_flags & FT_FACE_FLAG_SFNT) ? FXFT_LOAD_NO_BITMAP : (FXFT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING);
1340 int error = FXFT_Load_Glyph(m_Face, glyph_index, load_flags);
1342 FXFT_Set_Face_Internal_Flag(m_Face, transflag);
1346 if (bUseCJKSubFont) {
1347 weight = pSubstFont->m_WeightCJK;
1349 weight = pSubstFont ? pSubstFont->m_Weight : 0;
1351 if (pSubstFont && !(pSubstFont->m_SubstFlags & FXFONT_SUBST_MM) && weight > 400) {
1352 int index = (weight - 400) / 10;
1354 FXFT_Set_Face_Internal_Flag(m_Face, transflag);
1358 if (pSubstFont->m_Charset == FXFONT_SHIFTJIS_CHARSET) {
1359 level = g_WeightPow_SHIFTJIS[index] * 2 * (FXSYS_abs((int)(ft_matrix.xx)) + FXSYS_abs((int)(ft_matrix.xy))) / 36655;
1361 level = g_WeightPow_11[index] * (FXSYS_abs((int)(ft_matrix.xx)) + FXSYS_abs((int)(ft_matrix.xy))) / 36655;
1363 FXFT_Outline_Embolden(FXFT_Get_Glyph_Outline(m_Face), level);
1365 FXFT_Library_SetLcdFilter(CFX_GEModule::Get()->GetFontMgr()->m_FTLibrary, FT_LCD_FILTER_DEFAULT);
1366 error = FXFT_Render_Glyph(m_Face, anti_alias);
1368 FXFT_Set_Face_Internal_Flag(m_Face, transflag);
1371 int bmwidth = FXFT_Get_Bitmap_Width(FXFT_Get_Glyph_Bitmap(m_Face));
1372 int bmheight = FXFT_Get_Bitmap_Rows(FXFT_Get_Glyph_Bitmap(m_Face));
1373 if (bmwidth > 2048 || bmheight > 2048) {
1374 FXFT_Set_Face_Internal_Flag(m_Face, transflag);
1377 int dib_width = bmwidth;
1378 CFX_GlyphBitmap* pGlyphBitmap = FX_NEW CFX_GlyphBitmap;
1379 if (!pGlyphBitmap) {
1382 pGlyphBitmap->m_Bitmap.Create(dib_width, bmheight,
1383 anti_alias == FXFT_RENDER_MODE_MONO ? FXDIB_1bppMask : FXDIB_8bppMask);
1384 pGlyphBitmap->m_Left = FXFT_Get_Glyph_BitmapLeft(m_Face);
1385 pGlyphBitmap->m_Top = FXFT_Get_Glyph_BitmapTop(m_Face);
1386 int dest_pitch = pGlyphBitmap->m_Bitmap.GetPitch();
1387 int src_pitch = FXFT_Get_Bitmap_Pitch(FXFT_Get_Glyph_Bitmap(m_Face));
1388 FX_BYTE* pDestBuf = pGlyphBitmap->m_Bitmap.GetBuffer();
1389 FX_BYTE* pSrcBuf = (FX_BYTE*)FXFT_Get_Bitmap_Buffer(FXFT_Get_Glyph_Bitmap(m_Face));
1390 if (anti_alias != FXFT_RENDER_MODE_MONO && FXFT_Get_Bitmap_PixelMode(FXFT_Get_Glyph_Bitmap(m_Face)) == FXFT_PIXEL_MODE_MONO) {
1391 int bytes = anti_alias == FXFT_RENDER_MODE_LCD ? 3 : 1;
1392 for(int i = 0; i < bmheight; i++)
1393 for(int n = 0; n < bmwidth; n++) {
1394 FX_BYTE data = (pSrcBuf[i * src_pitch + n / 8] & (0x80 >> (n % 8))) ? 255 : 0;
1395 for (int b = 0; b < bytes; b ++) {
1396 pDestBuf[i * dest_pitch + n * bytes + b] = data;
1400 FXSYS_memset32(pDestBuf, 0, dest_pitch * bmheight);
1401 if (anti_alias == FXFT_RENDER_MODE_MONO && FXFT_Get_Bitmap_PixelMode(FXFT_Get_Glyph_Bitmap(m_Face)) == FXFT_PIXEL_MODE_MONO) {
1402 int rowbytes = FXSYS_abs(src_pitch) > dest_pitch ? dest_pitch : FXSYS_abs(src_pitch);
1403 for (int row = 0; row < bmheight; row ++) {
1404 FXSYS_memcpy32(pDestBuf + row * dest_pitch, pSrcBuf + row * src_pitch, rowbytes);
1407 _ContrastAdjust(pSrcBuf, pDestBuf, bmwidth, bmheight, src_pitch, dest_pitch);
1408 _GammaAdjust(pDestBuf, bmwidth, bmheight, dest_pitch, CFX_GEModule::Get()->GetTextGammaTable());
1411 FXFT_Set_Face_Internal_Flag(m_Face, transflag);
1412 return pGlyphBitmap;
1414 FX_BOOL _OutputGlyph(void* dib, int x, int y, CFX_Font* pFont,
1415 int glyph_index, FX_ARGB argb)
1417 CFX_DIBitmap* pDib = (CFX_DIBitmap*)dib;
1418 FXFT_Face face = pFont->GetFace();
1419 int error = FXFT_Load_Glyph(face, glyph_index, FXFT_LOAD_NO_BITMAP);
1423 error = FXFT_Render_Glyph(face, FXFT_RENDER_MODE_NORMAL);
1427 int bmwidth = FXFT_Get_Bitmap_Width(FXFT_Get_Glyph_Bitmap(face));
1428 int bmheight = FXFT_Get_Bitmap_Rows(FXFT_Get_Glyph_Bitmap(face));
1429 int left = FXFT_Get_Glyph_BitmapLeft(face);
1430 int top = FXFT_Get_Glyph_BitmapTop(face);
1431 FX_LPCBYTE src_buf = (FX_LPCBYTE)FXFT_Get_Bitmap_Buffer(FXFT_Get_Glyph_Bitmap(face));
1432 int src_pitch = FXFT_Get_Bitmap_Pitch(FXFT_Get_Glyph_Bitmap(face));
1434 mask.Create(bmwidth, bmheight, FXDIB_8bppMask);
1435 FX_LPBYTE dest_buf = mask.GetBuffer();
1436 int dest_pitch = mask.GetPitch();
1437 for (int row = 0; row < bmheight; row ++) {
1438 FX_LPCBYTE src_scan = src_buf + row * src_pitch;
1439 FX_LPBYTE dest_scan = dest_buf + row * dest_pitch;
1440 FXSYS_memcpy32(dest_scan, src_scan, dest_pitch);
1442 pDib->CompositeMask(x + left, y - top, bmwidth, bmheight, &mask, argb, 0, 0);
1445 FX_BOOL OutputText(void* dib, int x, int y, CFX_Font* pFont, double font_size,
1446 CFX_AffineMatrix* pText_matrix, unsigned short const* text, unsigned long argb)
1451 FXFT_Face face = pFont->GetFace();
1452 FXFT_Select_Charmap(pFont->m_Face, FXFT_ENCODING_UNICODE);
1453 int transflag = FXFT_Get_Face_Internal_Flag(pFont->m_Face);
1455 FXFT_Matrix ft_matrix;
1456 ft_matrix.xx = (signed long)(pText_matrix->a / 64 * 65536);
1457 ft_matrix.xy = (signed long)(pText_matrix->c / 64 * 65536);
1458 ft_matrix.yx = (signed long)(pText_matrix->b / 64 * 65536);
1459 ft_matrix.yy = (signed long)(pText_matrix->d / 64 * 65536);
1460 FXFT_Set_Transform(face, &ft_matrix, 0);
1463 for (; *text != 0; text ++) {
1464 FX_WCHAR unicode = *text;
1465 int glyph_index = FXFT_Get_Char_Index(pFont->m_Face, unicode);
1466 if (glyph_index <= 0) {
1469 int err = FXFT_Load_Glyph(pFont->m_Face, glyph_index, FXFT_LOAD_NO_SCALE | FXFT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH);
1473 int w = FXFT_Get_Glyph_HoriAdvance(pFont->m_Face);
1474 int em = FXFT_Get_Face_UnitsPerEM(pFont->m_Face);
1476 pText_matrix->Transform(x_pos, 0, x1, y1);
1477 _OutputGlyph(dib, (int)x1 + x, (int) - y1 + y, pFont,
1479 x_pos += (FX_FLOAT)w / em;
1481 FXFT_Set_Face_Internal_Flag(pFont->m_Face, transflag);
1484 FX_BOOL OutputGlyph(void* dib, int x, int y, CFX_Font* pFont, double font_size,
1485 CFX_AffineMatrix* pMatrix, unsigned long glyph_index, unsigned long argb)
1487 FXFT_Matrix ft_matrix;
1489 ft_matrix.xx = (signed long)(pMatrix->a * font_size / 64 * 65536);
1490 ft_matrix.xy = (signed long)(pMatrix->c * font_size / 64 * 65536);
1491 ft_matrix.yx = (signed long)(pMatrix->b * font_size / 64 * 65536);
1492 ft_matrix.yy = (signed long)(pMatrix->d * font_size / 64 * 65536);
1494 ft_matrix.xx = (signed long)(font_size / 64 * 65536);
1495 ft_matrix.xy = ft_matrix.yx = 0;
1496 ft_matrix.yy = (signed long)(font_size / 64 * 65536);
1498 int transflag = FXFT_Get_Face_Internal_Flag(pFont->m_Face);
1499 FXFT_Set_Transform(pFont->m_Face, &ft_matrix, 0);
1500 FX_BOOL ret = _OutputGlyph(dib, x, y, pFont,
1502 FXFT_Set_Face_Internal_Flag(pFont->m_Face, transflag);
1505 const CFX_PathData* CFX_FaceCache::LoadGlyphPath(CFX_Font* pFont, FX_DWORD glyph_index, int dest_width)
1507 if (m_Face == NULL || glyph_index == (FX_DWORD) - 1) {
1510 CFX_PathData* pGlyphPath = NULL;
1512 if (pFont->GetSubstFont())
1513 key = (FX_LPVOID)(FX_UINTPTR)(glyph_index + ((pFont->GetSubstFont()->m_Weight / 16) << 15) +
1514 ((pFont->GetSubstFont()->m_ItalicAngle / 2) << 21) + ((dest_width / 16) << 25) +
1515 (pFont->IsVertical() << 31));
1517 key = (FX_LPVOID)(FX_UINTPTR)glyph_index;
1519 if (m_PathMap.Lookup(key, (FX_LPVOID&)pGlyphPath)) {
1522 pGlyphPath = pFont->LoadGlyphPath(glyph_index, dest_width);
1523 m_PathMap.SetAt(key, pGlyphPath);
1529 FX_PATHPOINT* m_pPoints;
1532 FX_FLOAT m_CoordUnit;
1534 void _Outline_CheckEmptyContour(OUTLINE_PARAMS* param)
1536 if (param->m_PointCount >= 2 && param->m_pPoints[param->m_PointCount - 2].m_Flag == FXPT_MOVETO &&
1537 param->m_pPoints[param->m_PointCount - 2].m_PointX == param->m_pPoints[param->m_PointCount - 1].m_PointX &&
1538 param->m_pPoints[param->m_PointCount - 2].m_PointY == param->m_pPoints[param->m_PointCount - 1].m_PointY) {
1539 param->m_PointCount -= 2;
1541 if (param->m_PointCount >= 4 && param->m_pPoints[param->m_PointCount - 4].m_Flag == FXPT_MOVETO &&
1542 param->m_pPoints[param->m_PointCount - 3].m_Flag == FXPT_BEZIERTO &&
1543 param->m_pPoints[param->m_PointCount - 3].m_PointX == param->m_pPoints[param->m_PointCount - 4].m_PointX &&
1544 param->m_pPoints[param->m_PointCount - 3].m_PointY == param->m_pPoints[param->m_PointCount - 4].m_PointY &&
1545 param->m_pPoints[param->m_PointCount - 2].m_PointX == param->m_pPoints[param->m_PointCount - 4].m_PointX &&
1546 param->m_pPoints[param->m_PointCount - 2].m_PointY == param->m_pPoints[param->m_PointCount - 4].m_PointY &&
1547 param->m_pPoints[param->m_PointCount - 1].m_PointX == param->m_pPoints[param->m_PointCount - 4].m_PointX &&
1548 param->m_pPoints[param->m_PointCount - 1].m_PointY == param->m_pPoints[param->m_PointCount - 4].m_PointY) {
1549 param->m_PointCount -= 4;
1553 static int _Outline_MoveTo(const FXFT_Vector* to, void* user)
1555 OUTLINE_PARAMS* param = (OUTLINE_PARAMS*)user;
1556 if (!param->m_bCount) {
1557 _Outline_CheckEmptyContour(param);
1558 param->m_pPoints[param->m_PointCount].m_PointX = to->x / param->m_CoordUnit;
1559 param->m_pPoints[param->m_PointCount].m_PointY = to->y / param->m_CoordUnit;
1560 param->m_pPoints[param->m_PointCount].m_Flag = FXPT_MOVETO;
1561 param->m_CurX = to->x;
1562 param->m_CurY = to->y;
1563 if (param->m_PointCount) {
1564 param->m_pPoints[param->m_PointCount - 1].m_Flag |= FXPT_CLOSEFIGURE;
1567 param->m_PointCount ++;
1572 static int _Outline_LineTo(const FXFT_Vector* to, void* user)
1574 OUTLINE_PARAMS* param = (OUTLINE_PARAMS*)user;
1575 if (!param->m_bCount) {
1576 param->m_pPoints[param->m_PointCount].m_PointX = to->x / param->m_CoordUnit;
1577 param->m_pPoints[param->m_PointCount].m_PointY = to->y / param->m_CoordUnit;
1578 param->m_pPoints[param->m_PointCount].m_Flag = FXPT_LINETO;
1579 param->m_CurX = to->x;
1580 param->m_CurY = to->y;
1582 param->m_PointCount ++;
1587 static int _Outline_ConicTo(const FXFT_Vector* control, const FXFT_Vector* to, void* user)
1589 OUTLINE_PARAMS* param = (OUTLINE_PARAMS*)user;
1590 if (!param->m_bCount) {
1591 param->m_pPoints[param->m_PointCount].m_PointX = (param->m_CurX + (control->x - param->m_CurX) * 2 / 3) / param->m_CoordUnit;
1592 param->m_pPoints[param->m_PointCount].m_PointY = (param->m_CurY + (control->y - param->m_CurY) * 2 / 3) / param->m_CoordUnit;
1593 param->m_pPoints[param->m_PointCount].m_Flag = FXPT_BEZIERTO;
1594 param->m_pPoints[param->m_PointCount + 1].m_PointX = (control->x + (to->x - control->x) / 3) / param->m_CoordUnit;
1595 param->m_pPoints[param->m_PointCount + 1].m_PointY = (control->y + (to->y - control->y) / 3) / param->m_CoordUnit;
1596 param->m_pPoints[param->m_PointCount + 1].m_Flag = FXPT_BEZIERTO;
1597 param->m_pPoints[param->m_PointCount + 2].m_PointX = to->x / param->m_CoordUnit;
1598 param->m_pPoints[param->m_PointCount + 2].m_PointY = to->y / param->m_CoordUnit;
1599 param->m_pPoints[param->m_PointCount + 2].m_Flag = FXPT_BEZIERTO;
1600 param->m_CurX = to->x;
1601 param->m_CurY = to->y;
1603 param->m_PointCount += 3;
1608 static int _Outline_CubicTo(const FXFT_Vector* control1, const FXFT_Vector* control2, const FXFT_Vector* to, void* user)
1610 OUTLINE_PARAMS* param = (OUTLINE_PARAMS*)user;
1611 if (!param->m_bCount) {
1612 param->m_pPoints[param->m_PointCount].m_PointX = control1->x / param->m_CoordUnit;
1613 param->m_pPoints[param->m_PointCount].m_PointY = control1->y / param->m_CoordUnit;
1614 param->m_pPoints[param->m_PointCount].m_Flag = FXPT_BEZIERTO;
1615 param->m_pPoints[param->m_PointCount + 1].m_PointX = control2->x / param->m_CoordUnit;
1616 param->m_pPoints[param->m_PointCount + 1].m_PointY = control2->y / param->m_CoordUnit;
1617 param->m_pPoints[param->m_PointCount + 1].m_Flag = FXPT_BEZIERTO;
1618 param->m_pPoints[param->m_PointCount + 2].m_PointX = to->x / param->m_CoordUnit;
1619 param->m_pPoints[param->m_PointCount + 2].m_PointY = to->y / param->m_CoordUnit;
1620 param->m_pPoints[param->m_PointCount + 2].m_Flag = FXPT_BEZIERTO;
1621 param->m_CurX = to->x;
1622 param->m_CurY = to->y;
1624 param->m_PointCount += 3;
1628 CFX_PathData* CFX_Font::LoadGlyphPath(FX_DWORD glyph_index, int dest_width)
1630 if (m_Face == NULL) {
1633 FXFT_Set_Pixel_Sizes(m_Face, 0, 64);
1634 FXFT_Matrix ft_matrix = {65536, 0, 0, 65536};
1636 if (m_pSubstFont->m_ItalicAngle) {
1637 int skew = m_pSubstFont->m_ItalicAngle;
1638 skew = skew <= -30 ? -58 : -g_AngleSkew[-skew];
1640 ft_matrix.yx += ft_matrix.yy * skew / 100;
1642 ft_matrix.xy += -ft_matrix.xx * skew / 100;
1645 if (m_pSubstFont->m_SubstFlags & FXFONT_SUBST_MM) {
1646 AdjustMMParams(glyph_index, dest_width, m_pSubstFont->m_Weight);
1649 int transflag = FXFT_Get_Face_Internal_Flag(m_Face);
1650 FXFT_Set_Transform(m_Face, &ft_matrix, 0);
1651 int load_flags = (m_Face->face_flags & FT_FACE_FLAG_SFNT) ? FXFT_LOAD_NO_BITMAP : FXFT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING;
1652 int error = FXFT_Load_Glyph(m_Face, glyph_index, load_flags);
1654 FXFT_Set_Face_Internal_Flag(m_Face, transflag);
1657 if (m_pSubstFont && !(m_pSubstFont->m_SubstFlags & FXFONT_SUBST_MM) && m_pSubstFont->m_Weight > 400) {
1659 if (m_pSubstFont->m_Charset == FXFONT_SHIFTJIS_CHARSET) {
1660 level = g_WeightPow_SHIFTJIS[(m_pSubstFont->m_Weight - 400) / 10] * 2 * 65536 / 36655;
1662 level = g_WeightPow[(m_pSubstFont->m_Weight - 400) / 10] * 2;
1664 FXFT_Outline_Embolden(FXFT_Get_Glyph_Outline(m_Face), level);
1666 FXFT_Outline_Funcs funcs;
1667 funcs.move_to = _Outline_MoveTo;
1668 funcs.line_to = _Outline_LineTo;
1669 funcs.conic_to = _Outline_ConicTo;
1670 funcs.cubic_to = _Outline_CubicTo;
1673 OUTLINE_PARAMS params;
1674 params.m_bCount = TRUE;
1675 params.m_PointCount = 0;
1676 FXFT_Outline_Decompose(FXFT_Get_Glyph_Outline(m_Face), &funcs, ¶ms);
1677 if (params.m_PointCount == 0) {
1678 FXFT_Set_Face_Internal_Flag(m_Face, transflag);
1681 CFX_PathData* pPath = FX_NEW CFX_PathData;
1685 pPath->SetPointCount(params.m_PointCount);
1686 params.m_bCount = FALSE;
1687 params.m_PointCount = 0;
1688 params.m_pPoints = pPath->GetPoints();
1689 params.m_CurX = params.m_CurY = 0;
1690 params.m_CoordUnit = 64 * 64.0;
1691 FXFT_Outline_Decompose(FXFT_Get_Glyph_Outline(m_Face), &funcs, ¶ms);
1692 _Outline_CheckEmptyContour(¶ms);
1693 pPath->TrimPoints(params.m_PointCount);
1694 if (params.m_PointCount) {
1695 pPath->GetPoints()[params.m_PointCount - 1].m_Flag |= FXPT_CLOSEFIGURE;
1697 FXFT_Set_Face_Internal_Flag(m_Face, transflag);
1700 void _CFX_UniqueKeyGen::Generate(int count, ...)
1703 va_start(argList, count);
1704 for (int i = 0; i < count; i ++) {
1705 int p = va_arg(argList, int);
1706 ((FX_DWORD*)m_Key)[i] = p;
1709 m_KeyLen = count * sizeof(FX_DWORD);