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_GdipGamma_bgw[9] = {0, 0, 63, 120, 0, 168, 210, 239, 255};
82 static const FX_BYTE g_GdipGamma_fgw[9] = {0, 0, 16, 45, 0, 87, 135, 192, 255};
83 static const FX_BYTE g_GdipGammaAdjust_47[48] = {
84 0, 30, 33, 34, 35, 36, 37, 38, 38, 39, 39, 40, 40, 40, 41, 41, 41, 42, 42, 42, 42, 43,
85 43, 43, 43, 43, 44, 44, 44, 44, 44, 44, 45, 45, 45, 45, 45, 45, 45, 46,
86 46, 46, 46, 46, 46, 46, 46, 47
88 static const FX_BYTE g_GdipGammaAdjust_75[76] = {
89 0, 46, 50, 52, 54, 55, 56, 57, 58, 59, 60, 60, 61, 61, 62, 62, 63, 63, 64, 64, 64, 65,
90 65, 65, 66, 66, 66, 67, 67, 67, 67, 68, 68, 68, 68, 68, 69, 69, 69, 69, 69, 70, 70, 70,
91 70, 70, 71, 71, 71, 71, 71, 71, 72, 72, 72, 72, 72, 72, 72, 73, 73, 73, 73, 73, 73, 73,
92 73, 74, 74, 74, 74, 74, 74, 74, 74, 75
94 static const FX_BYTE g_GdipGammaAdjust_81[82] = {
95 0, 49, 53, 56, 58, 59, 60, 61, 62, 63, 64, 65, 65, 66, 66, 67, 67, 68, 68, 69, 69, 69, 70, 70, 70,
96 71, 71, 71, 72, 72, 72, 72, 73, 73, 73, 73, 74, 74, 74, 74, 74, 75, 75, 75, 75, 75, 76, 76, 76, 76,
97 76, 76, 77, 77, 77, 77, 77, 77, 78, 78, 78, 78, 78, 78, 78, 79, 79, 79, 79, 79, 79, 79, 79, 80,
98 80, 80, 80, 80, 80, 80, 80, 81
100 static void _Adjust_alpha(int background, int foreground, int& src_alpha, int text_flags, int a)
103 static const FX_BYTE g_TextGammaAdjust[256] = {
104 0, 2, 3, 4, 6, 7, 8, 10, 11, 12, 13, 15, 16, 17, 18, 19,
105 21, 22, 23, 24, 25, 26, 27, 29, 30, 31, 32, 33, 34, 35, 36, 38,
106 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 51, 52, 53, 54, 55,
107 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 71, 72,
108 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88,
109 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104,
110 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120,
111 121, 122, 123, 124, 125, 126, 127, 128, 129, 129, 130, 131, 132, 133, 134, 135,
112 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151,
113 152, 153, 154, 155, 156, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166,
114 167, 168, 169, 170, 171, 172, 173, 174, 174, 175, 176, 177, 178, 179, 180, 181,
115 182, 183, 184, 185, 186, 187, 188, 189, 190, 190, 191, 192, 193, 194, 195, 196,
116 197, 198, 199, 200, 201, 202, 203, 204, 204, 205, 206, 207, 208, 209, 210, 211,
117 212, 213, 214, 215, 216, 217, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226,
118 227, 228, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 239, 240,
119 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 250, 251, 252, 253, 254, 255,
121 #define ADJUST_ALPHA(background, foreground, src_alpha, text_flags, a) \
122 src_alpha = g_TextGammaAdjust[(FX_BYTE)src_alpha];
123 void _Color2Argb(FX_ARGB& argb, FX_DWORD color, int alpha_flag, void* pIccTransform)
125 if (pIccTransform == NULL && !FXGETFLAG_COLORTYPE(alpha_flag)) {
129 if (!CFX_GEModule::Get()->GetCodecModule() || !CFX_GEModule::Get()->GetCodecModule()->GetIccModule()) {
130 pIccTransform = NULL;
134 ICodec_IccModule* pIccModule = CFX_GEModule::Get()->GetCodecModule()->GetIccModule();
135 color = FXGETFLAG_COLORTYPE(alpha_flag) ? FXCMYK_TODIB(color) : FXARGB_TODIB(color);
136 pIccModule->TranslateScanline(pIccTransform, bgra, (FX_LPCBYTE)&color, 1);
137 bgra[3] = FXGETFLAG_COLORTYPE(alpha_flag) ?
138 (alpha_flag >> 24) ? FXGETFLAG_ALPHA_FILL(alpha_flag) : FXGETFLAG_ALPHA_STROKE(alpha_flag) :
140 argb = FXARGB_MAKE(bgra[3], bgra[2], bgra[1], bgra[0]);
143 AdobeCMYK_to_sRGB1(FXSYS_GetCValue(color), FXSYS_GetMValue(color),
144 FXSYS_GetYValue(color), FXSYS_GetKValue(color),
145 bgra[2], bgra[1], bgra[0]);
146 bgra[3] = (alpha_flag >> 24) ? FXGETFLAG_ALPHA_FILL(alpha_flag) : FXGETFLAG_ALPHA_STROKE(alpha_flag);
147 argb = FXARGB_MAKE(bgra[3], bgra[2], bgra[1], bgra[0]);
149 FX_BOOL CFX_RenderDevice::DrawNormalText(int nChars, const FXTEXT_CHARPOS* pCharPos,
150 CFX_Font* pFont, CFX_FontCache* pCache,
151 FX_FLOAT font_size, const CFX_AffineMatrix* pText2Device,
152 FX_DWORD fill_color, FX_DWORD text_flags,
153 int alpha_flag, void* pIccTransform)
155 int nativetext_flags = text_flags;
156 if (m_DeviceClass != FXDC_DISPLAY) {
157 if (!(text_flags & FXTEXT_PRINTGRAPHICTEXT)) {
158 #if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
159 if (!(text_flags & FXFONT_CIDFONT) && pFont->GetPsName().Find(CFX_WideString::FromLocal("+ZJHL")) == -1)
160 #ifdef FOXIT_CHROME_BUILD
161 if (pFont->GetPsName() != CFX_WideString::FromLocal("CNAAJI+cmex10"))
164 if (m_pDeviceDriver->DrawDeviceText(nChars, pCharPos, pFont, pCache, pText2Device, font_size, fill_color, alpha_flag, pIccTransform)) {
168 int alpha = FXGETFLAG_COLORTYPE(alpha_flag) ? FXGETFLAG_ALPHA_FILL(alpha_flag) : FXARGB_A(fill_color);
172 } else if (!(text_flags & FXTEXT_NO_NATIVETEXT)) {
173 #if _FXM_PLATFORM_ == _FXM_PLATFORM_APPLE_
174 if (!(text_flags & FXFONT_CIDFONT))
175 #ifdef FOXIT_CHROME_BUILD
176 if (pFont->GetPsName() != CFX_WideString::FromLocal("CNAAJI+cmex10"))
179 if (m_pDeviceDriver->DrawDeviceText(nChars, pCharPos, pFont, pCache, pText2Device, font_size, fill_color, alpha_flag, pIccTransform)) {
183 CFX_AffineMatrix char2device, deviceCtm, text2Device;
185 char2device = *pText2Device;
186 text2Device = *pText2Device;
188 char2device.Scale(font_size, -font_size);
189 if (FXSYS_fabs(char2device.a) + FXSYS_fabs(char2device.b) > 50 * 1.0f ||
190 ((m_DeviceClass == FXDC_PRINTER && !m_pDeviceDriver->IsPSPrintDriver())
191 && !(text_flags & FXTEXT_PRINTIMAGETEXT))) {
192 if (pFont->GetFace() != NULL || (pFont->GetSubstFont()->m_SubstFlags & FXFONT_SUBST_GLYPHPATH)) {
193 int nPathFlags = (text_flags & FXTEXT_NOSMOOTH) == 0 ? 0 : FXFILL_NOPATHSMOOTH;
194 return DrawTextPath(nChars, pCharPos, pFont, pCache, font_size, pText2Device, NULL, NULL, fill_color, 0, NULL, nPathFlags, alpha_flag, pIccTransform);
197 int anti_alias = FXFT_RENDER_MODE_MONO;
198 FX_BOOL bNormal = FALSE;
199 if ((text_flags & FXTEXT_NOSMOOTH) == 0) {
200 if (m_DeviceClass == FXDC_DISPLAY && m_bpp > 1) {
202 if (pFont->GetFace() == NULL && !(pFont->GetSubstFont()->m_SubstFlags & FXFONT_SUBST_CLEARTYPE)) {
205 bClearType = text_flags & FXTEXT_CLEARTYPE;
207 if ((m_RenderCaps & (FXRC_ALPHA_OUTPUT | FXRC_CMYK_OUTPUT))) {
208 anti_alias = FXFT_RENDER_MODE_LCD;
210 } else if (m_bpp < 16) {
211 anti_alias = FXFT_RENDER_MODE_NORMAL;
213 if (bClearType == FALSE) {
214 anti_alias = FXFT_RENDER_MODE_LCD;
217 anti_alias = FXFT_RENDER_MODE_LCD;
222 if (pCache == NULL) {
223 pCache = CFX_GEModule::Get()->GetFontCache();
225 CFX_FaceCache* pFaceCache = pCache->GetCachedFace(pFont);
226 FX_FONTCACHE_DEFINE(pCache, pFont);
227 FXTEXT_GLYPHPOS* pGlyphAndPos = FX_Alloc(FXTEXT_GLYPHPOS, nChars);
232 deviceCtm = char2device;
233 CFX_AffineMatrix matrixCTM = GetCTM();
234 FX_FLOAT scale_x = FXSYS_fabs(matrixCTM.a);
235 FX_FLOAT scale_y = FXSYS_fabs(matrixCTM.d);
236 deviceCtm.Concat(scale_x, 0, 0, scale_y, 0, 0);
237 text2Device.Concat(scale_x, 0, 0, scale_y, 0, 0);
238 for (iChar = 0; iChar < nChars; iChar ++) {
239 FXTEXT_GLYPHPOS& glyph = pGlyphAndPos[iChar];
240 const FXTEXT_CHARPOS& charpos = pCharPos[iChar];
241 glyph.m_fOriginX = charpos.m_OriginX;
242 glyph.m_fOriginY = charpos.m_OriginY;
243 text2Device.Transform(glyph.m_fOriginX, glyph.m_fOriginY);
244 if (anti_alias < FXFT_RENDER_MODE_LCD) {
245 glyph.m_OriginX = FXSYS_round(glyph.m_fOriginX);
247 glyph.m_OriginX = (int)FXSYS_floor(glyph.m_fOriginX);
249 glyph.m_OriginY = FXSYS_round(glyph.m_fOriginY);
250 if (charpos.m_bGlyphAdjust) {
251 CFX_AffineMatrix new_matrix(charpos.m_AdjustMatrix[0], charpos.m_AdjustMatrix[1],
252 charpos.m_AdjustMatrix[2], charpos.m_AdjustMatrix[3], 0, 0);
253 new_matrix.Concat(deviceCtm);
254 glyph.m_pGlyph = pFaceCache->LoadGlyphBitmap(pFont, charpos.m_GlyphIndex, charpos.m_bFontStyle, &new_matrix,
255 charpos.m_FontCharWidth, anti_alias, nativetext_flags);
257 glyph.m_pGlyph = pFaceCache->LoadGlyphBitmap(pFont, charpos.m_GlyphIndex, charpos.m_bFontStyle, &deviceCtm,
258 charpos.m_FontCharWidth, anti_alias, nativetext_flags);
260 if (anti_alias < FXFT_RENDER_MODE_LCD && nChars > 1) {
261 _AdjustGlyphSpace(pGlyphAndPos, nChars);
263 FX_RECT bmp_rect1 = FXGE_GetGlyphsBBox(pGlyphAndPos, nChars, anti_alias);
264 if (scale_x > 1 && scale_y > 1) {
270 FX_RECT bmp_rect(FXSYS_round((FX_FLOAT)(bmp_rect1.left) / scale_x), FXSYS_round((FX_FLOAT)(bmp_rect1.top) / scale_y),
271 FXSYS_round((FX_FLOAT)bmp_rect1.right / scale_x), FXSYS_round((FX_FLOAT)bmp_rect1.bottom / scale_y));
272 bmp_rect.Intersect(m_ClipBox);
273 if (bmp_rect.IsEmpty()) {
274 FX_Free(pGlyphAndPos);
277 int pixel_width = FXSYS_round(bmp_rect.Width() * scale_x);
278 int pixel_height = FXSYS_round(bmp_rect.Height() * scale_y);
279 int pixel_left = FXSYS_round(bmp_rect.left * scale_x);
280 int pixel_top = FXSYS_round(bmp_rect.top * scale_y);
281 if (anti_alias == FXFT_RENDER_MODE_MONO) {
283 if (!bitmap.Create(pixel_width, pixel_height, FXDIB_1bppMask)) {
284 FX_Free(pGlyphAndPos);
288 for (iChar = 0; iChar < nChars; iChar ++) {
289 FXTEXT_GLYPHPOS& glyph = pGlyphAndPos[iChar];
290 if (glyph.m_pGlyph == NULL) {
293 const CFX_DIBitmap* pGlyph = &glyph.m_pGlyph->m_Bitmap;
294 bitmap.TransferBitmap(glyph.m_OriginX + glyph.m_pGlyph->m_Left - pixel_left,
295 glyph.m_OriginY - glyph.m_pGlyph->m_Top - pixel_top,
296 pGlyph->GetWidth(), pGlyph->GetHeight(), pGlyph, 0, 0);
298 FX_Free(pGlyphAndPos);
299 return SetBitMask(&bitmap, bmp_rect.left, bmp_rect.top, fill_color);
303 if (!bitmap.Create(pixel_width, pixel_height, FXDIB_8bppMask)) {
304 FX_Free(pGlyphAndPos);
308 if (!CreateCompatibleBitmap(&bitmap, pixel_width, pixel_height)) {
309 FX_Free(pGlyphAndPos);
313 if (!bitmap.HasAlpha() && !bitmap.IsAlphaMask()) {
314 bitmap.Clear(0xFFFFFFFF);
315 if (!GetDIBits(&bitmap, bmp_rect.left, bmp_rect.top)) {
316 FX_Free(pGlyphAndPos);
321 if (bitmap.m_pAlphaMask) {
322 bitmap.m_pAlphaMask->Clear(0);
325 int dest_width = pixel_width;
326 FX_LPBYTE dest_buf = bitmap.GetBuffer();
327 int dest_pitch = bitmap.GetPitch();
328 int Bpp = bitmap.GetBPP() / 8;
330 if (anti_alias == FXFT_RENDER_MODE_LCD) {
331 _Color2Argb(fill_color, fill_color, alpha_flag | (1 << 24), pIccTransform);
332 ArgbDecode(fill_color, a, r, g, b);
337 for (iChar = 0; iChar < nChars; iChar ++) {
338 FXTEXT_GLYPHPOS& glyph = pGlyphAndPos[iChar];
339 if (glyph.m_pGlyph == NULL) {
342 const CFX_DIBitmap* pGlyph = &glyph.m_pGlyph->m_Bitmap;
343 int left = glyph.m_OriginX + glyph.m_pGlyph->m_Left - pixel_left;
344 int top = glyph.m_OriginY - glyph.m_pGlyph->m_Top - pixel_top;
345 int ncols = pGlyph->GetWidth();
346 int nrows = pGlyph->GetHeight();
347 if (anti_alias == FXFT_RENDER_MODE_NORMAL) {
348 if (!bitmap.CompositeMask(left, top, ncols, nrows, pGlyph, fill_color,
349 0, 0, FXDIB_BLEND_NORMAL, NULL, FALSE, alpha_flag, pIccTransform)) {
350 FX_Free(pGlyphAndPos);
355 FX_BOOL bBGRStripe = text_flags & FXTEXT_BGR_STRIPE;
357 int x_subpixel = (int)(glyph.m_fOriginX * 3) % 3;
358 FX_LPBYTE src_buf = pGlyph->GetBuffer();
359 int src_pitch = pGlyph->GetPitch();
360 int start_col = left;
364 int end_col = left + ncols;
365 if (end_col > dest_width) {
366 end_col = dest_width;
368 if (start_col >= end_col) {
371 if (bitmap.GetFormat() == FXDIB_Argb) {
372 for (int row = 0; row < nrows; row ++) {
373 int dest_row = row + top;
374 if (dest_row < 0 || dest_row >= bitmap.GetHeight()) {
377 FX_LPBYTE src_scan = src_buf + row * src_pitch + (start_col - left) * 3;
378 FX_LPBYTE dest_scan = dest_buf + dest_row * dest_pitch + (start_col << 2);
380 if (x_subpixel == 0) {
381 for (int col = start_col; col < end_col; col ++) {
382 int src_alpha = src_scan[2];
383 src_alpha = src_alpha * a / 255;
384 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
385 src_alpha = src_scan[1];
386 src_alpha = src_alpha * a / 255;
387 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
388 src_alpha = src_scan[0];
389 src_alpha = src_alpha * a / 255;
390 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
395 } else if (x_subpixel == 1) {
396 int src_alpha = src_scan[1];
397 ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
398 src_alpha = src_alpha * a / 255;
399 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
400 src_alpha = src_scan[0];
401 ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
402 src_alpha = src_alpha * a / 255;
403 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
404 if (start_col > left) {
405 src_alpha = src_scan[-1];
406 ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
407 src_alpha = src_alpha * a / 255;
408 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
413 for (int col = start_col + 1; col < end_col - 1; col ++) {
414 int src_alpha = src_scan[1];
415 ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
416 src_alpha = src_alpha * a / 255;
417 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
418 src_alpha = src_scan[0];
419 ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
420 src_alpha = src_alpha * a / 255;
421 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
422 src_alpha = src_scan[-1];
423 ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
424 src_alpha = src_alpha * a / 255;
425 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
431 int src_alpha = src_scan[0];
432 ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
433 src_alpha = src_alpha * a / 255;
434 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
435 if (start_col > left) {
436 src_alpha = src_scan[-1];
437 ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
438 src_alpha = src_alpha * a / 255;
439 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
440 src_alpha = src_scan[-2];
441 ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
442 src_alpha = src_alpha * a / 255;
443 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
448 for (int col = start_col + 1; col < end_col - 1; col ++) {
449 int src_alpha = src_scan[0];
450 ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
451 src_alpha = src_alpha * a / 255;
452 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
453 src_alpha = src_scan[-1];
454 ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
455 src_alpha = src_alpha * a / 255;
456 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
457 src_alpha = src_scan[-2];
458 ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
459 src_alpha = src_alpha * a / 255;
460 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
467 if (x_subpixel == 0) {
468 for (int col = start_col; col < end_col; col ++) {
470 int src_alpha1 = (src_scan[0] + src_scan[1] + src_scan[2]) / 3;
471 ADJUST_ALPHA(dest_scan[2], r, src_alpha1, nativetext_flags, a);
472 src_alpha1 = src_alpha1 * a / 255;
473 FX_BYTE back_alpha = dest_scan[3];
474 if (back_alpha == 0) {
475 FXARGB_SETDIB(dest_scan, FXARGB_MAKE(src_alpha1, r, g, b));
480 if (src_alpha1 == 0) {
485 FX_BYTE dest_alpha = back_alpha + src_alpha1 - back_alpha * src_alpha1 / 255;
486 dest_scan[3] = dest_alpha;
487 int alpha_ratio = src_alpha1 * 255 / dest_alpha;
488 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, alpha_ratio));
489 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, alpha_ratio));
490 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, alpha_ratio));
495 int src_alpha = src_scan[0];
496 ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
497 src_alpha = src_alpha * a / 255;
498 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
499 src_alpha = src_scan[1];
500 ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
501 src_alpha = src_alpha * a / 255;
502 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
503 src_alpha = src_scan[2];
504 ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
505 src_alpha = src_alpha * a / 255;
506 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
511 } else if (x_subpixel == 1) {
513 int src_alpha1 = start_col > left ? ((src_scan[-1] + src_scan[0] + src_scan[1]) / 3) : ((src_scan[0] + src_scan[1]) / 3);
514 ADJUST_ALPHA(dest_scan[2], r, src_alpha1, nativetext_flags, a);
515 src_alpha1 = src_alpha1 * a / 255;
516 if (src_alpha1 == 0) {
520 FX_BYTE back_alpha = dest_scan[3];
521 if (back_alpha == 0) {
522 FXARGB_SETDIB(dest_scan, FXARGB_MAKE(src_alpha1, r, g, b));
524 FX_BYTE dest_alpha = back_alpha + src_alpha1 - back_alpha * src_alpha1 / 255;
525 dest_scan[3] = dest_alpha;
526 int alpha_ratio = src_alpha1 * 255 / dest_alpha;
527 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, alpha_ratio));
528 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, alpha_ratio));
529 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, alpha_ratio));
535 if (start_col > left) {
536 int src_alpha = src_scan[-1];
537 ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
538 src_alpha = src_alpha * a / 255;
539 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
541 int src_alpha = src_scan[0];
542 ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
543 src_alpha = src_alpha * a / 255;
544 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
545 src_alpha = src_scan[1];
546 ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
547 src_alpha = src_alpha * a / 255;
548 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
553 for (int col = start_col + 1; col < end_col; col ++) {
555 int src_alpha1 = (src_scan[-1] + src_scan[0] + src_scan[1]) / 3;
556 ADJUST_ALPHA(dest_scan[2], r, src_alpha1, nativetext_flags, a);
557 src_alpha1 = src_alpha1 * a / 255;
558 FX_BYTE back_alpha = dest_scan[3];
559 if (back_alpha == 0) {
560 FXARGB_SETDIB(dest_scan, FXARGB_MAKE(src_alpha1, r, g, b));
565 if (src_alpha1 == 0) {
570 FX_BYTE dest_alpha = back_alpha + src_alpha1 - back_alpha * src_alpha1 / 255;
571 dest_scan[3] = dest_alpha;
572 int alpha_ratio = src_alpha1 * 255 / dest_alpha;
573 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, alpha_ratio));
574 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, alpha_ratio));
575 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, alpha_ratio));
580 int src_alpha = src_scan[-1];
581 ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
582 src_alpha = src_alpha * a / 255;
583 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
584 src_alpha = src_scan[0];
585 ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
586 src_alpha = src_alpha * a / 255;
587 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
588 src_alpha = src_scan[1];
589 ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
590 src_alpha = src_alpha * a / 255;
591 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
598 int src_alpha1 = start_col > left ? ((src_scan[-2] + src_scan[-1] + src_scan[0]) / 3) : ((src_scan[0]) / 3);
599 ADJUST_ALPHA(dest_scan[2], r, src_alpha1, nativetext_flags, a);
600 src_alpha1 = src_alpha1 * a / 255;
601 if (src_alpha1 == 0) {
605 FX_BYTE back_alpha = dest_scan[3];
606 if (back_alpha == 0) {
607 FXARGB_SETDIB(dest_scan, FXARGB_MAKE(src_alpha1, r, g, b));
609 FX_BYTE dest_alpha = back_alpha + src_alpha1 - back_alpha * src_alpha1 / 255;
610 dest_scan[3] = dest_alpha;
611 int alpha_ratio = src_alpha1 * 255 / dest_alpha;
612 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, alpha_ratio));
613 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, alpha_ratio));
614 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, alpha_ratio));
620 if (start_col > left) {
621 int src_alpha = src_scan[-2];
622 ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
623 src_alpha = src_alpha * a / 255;
624 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
625 src_alpha = src_scan[-1];
626 ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
627 src_alpha = src_alpha * a / 255;
628 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
630 int src_alpha = src_scan[0];
631 ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
632 src_alpha = src_alpha * a / 255;
633 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
638 for (int col = start_col + 1; col < end_col; col ++) {
640 int src_alpha1 = (src_scan[-2] + src_scan[-1] + src_scan[0]) / 3;
641 ADJUST_ALPHA(dest_scan[2], r, src_alpha1, nativetext_flags, a);
642 src_alpha1 = src_alpha1 * a / 255;
643 FX_BYTE back_alpha = dest_scan[3];
644 if (back_alpha == 0) {
645 FXARGB_SETDIB(dest_scan, FXARGB_MAKE(src_alpha1, r, g, b));
650 if (src_alpha1 == 0) {
655 FX_BYTE dest_alpha = back_alpha + src_alpha1 - back_alpha * src_alpha1 / 255;
656 dest_scan[3] = dest_alpha;
657 int alpha_ratio = src_alpha1 * 255 / dest_alpha;
658 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, alpha_ratio));
659 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, alpha_ratio));
660 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, alpha_ratio));
665 int src_alpha = src_scan[-2];
666 ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
667 src_alpha = src_alpha * a / 255;
668 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
669 src_alpha = src_scan[-1];
670 ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
671 src_alpha = src_alpha * a / 255;
672 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
673 src_alpha = src_scan[0];
674 ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
675 src_alpha = src_alpha * a / 255;
676 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
685 for (int row = 0; row < nrows; row ++) {
686 int dest_row = row + top;
687 if (dest_row < 0 || dest_row >= bitmap.GetHeight()) {
690 FX_LPBYTE src_scan = src_buf + row * src_pitch + (start_col - left) * 3;
691 FX_LPBYTE dest_scan = dest_buf + dest_row * dest_pitch + start_col * Bpp;
693 if (x_subpixel == 0) {
694 for (int col = start_col; col < end_col; col ++) {
695 int src_alpha = src_scan[2];
696 ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
697 src_alpha = src_alpha * a / 255;
698 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
699 src_alpha = src_scan[1];
700 ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
701 src_alpha = src_alpha * a / 255;
702 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
703 src_alpha = src_scan[0];
704 ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
705 src_alpha = src_alpha * a / 255;
706 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
710 } else if (x_subpixel == 1) {
711 int src_alpha = src_scan[1];
712 ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
713 src_alpha = src_alpha * a / 255;
714 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
715 src_alpha = src_scan[0];
716 ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
717 src_alpha = src_alpha * a / 255;
718 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
719 if (start_col > left) {
720 src_alpha = src_scan[-1];
721 ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
722 src_alpha = src_alpha * a / 255;
723 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
727 for (int col = start_col + 1; col < end_col - 1; col ++) {
728 int src_alpha = src_scan[1];
729 ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
730 src_alpha = src_alpha * a / 255;
731 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
732 src_alpha = src_scan[0];
733 ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
734 src_alpha = src_alpha * a / 255;
735 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
736 src_alpha = src_scan[-1];
737 ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
738 src_alpha = src_alpha * a / 255;
739 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
744 int src_alpha = src_scan[0];
745 ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
746 src_alpha = src_alpha * a / 255;
747 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
748 if (start_col > left) {
749 src_alpha = src_scan[-1];
750 ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
751 src_alpha = src_alpha * a / 255;
752 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
753 src_alpha = src_scan[-2];
754 ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
755 src_alpha = src_alpha * a / 255;
756 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
760 for (int col = start_col + 1; col < end_col - 1; col ++) {
761 int src_alpha = src_scan[0];
762 ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
763 src_alpha = src_alpha * a / 255;
764 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
765 src_alpha = src_scan[-1];
766 ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
767 src_alpha = src_alpha * a / 255;
768 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
769 src_alpha = src_scan[-2];
770 ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
771 src_alpha = src_alpha * a / 255;
772 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
778 if (x_subpixel == 0) {
779 for (int col = start_col; col < end_col; col ++) {
781 int src_alpha1 = (src_scan[0] + src_scan[1] + src_scan[2]) / 3;
782 ADJUST_ALPHA(dest_scan[2], r, src_alpha1, nativetext_flags, a);
783 src_alpha1 = src_alpha1 * a / 255;
784 if (src_alpha1 == 0) {
789 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha1));
790 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha1));
791 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha1));
796 int src_alpha = src_scan[0];
797 ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
798 src_alpha = src_alpha * a / 255;
799 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
800 src_alpha = src_scan[1];
801 ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
802 src_alpha = src_alpha * a / 255;
803 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
804 src_alpha = src_scan[2];
805 ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
806 src_alpha = src_alpha * a / 255;
807 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
811 } else if (x_subpixel == 1) {
813 int src_alpha1 = start_col > left ? (src_scan[0] + src_scan[1] + src_scan[-1]) / 3 : (src_scan[0] + src_scan[1]) / 3;
814 ADJUST_ALPHA(dest_scan[2], r, src_alpha1, nativetext_flags, a);
815 src_alpha1 = src_alpha1 * a / 255;
816 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha1));
817 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha1));
818 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha1));
822 if (start_col > left) {
823 int src_alpha = src_scan[-1];
824 ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
825 src_alpha = src_alpha * a / 255;
826 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
828 int src_alpha = src_scan[0];
829 ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
830 src_alpha = src_alpha * a / 255;
831 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
832 src_alpha = src_scan[1];
833 ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
834 src_alpha = src_alpha * a / 255;
835 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
839 for (int col = start_col + 1; col < end_col; col ++) {
841 int src_alpha1 = (src_scan[0] + src_scan[1] + src_scan[-1]) / 3;
842 ADJUST_ALPHA(dest_scan[2], r, src_alpha1, nativetext_flags, a);
843 src_alpha1 = src_alpha1 * a / 255;
844 if (src_alpha1 == 0) {
849 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha1));
850 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha1));
851 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha1));
856 int src_alpha = src_scan[-1];
857 ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
858 src_alpha = src_alpha * a / 255;
859 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
860 src_alpha = src_scan[0];
861 ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
862 src_alpha = src_alpha * a / 255;
863 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
864 src_alpha = src_scan[1];
865 ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
866 src_alpha = src_alpha * a / 255;
867 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
873 int src_alpha1 = start_col > left ? (src_scan[0] + src_scan[-2] + src_scan[-1]) / 3 : src_scan[0] / 3;
874 ADJUST_ALPHA(dest_scan[2], r, src_alpha1, nativetext_flags, a);
875 src_alpha1 = src_alpha1 * a / 255;
876 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha1));
877 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha1));
878 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha1));
882 if (start_col > left) {
883 int src_alpha = src_scan[-2];
884 ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
885 src_alpha = src_alpha * a / 255;
886 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
887 src_alpha = src_scan[-1];
888 ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
889 src_alpha = src_alpha * a / 255;
890 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
892 int src_alpha = src_scan[0];
893 ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
894 src_alpha = src_alpha * a / 255;
895 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
899 for (int col = start_col + 1; col < end_col; col ++) {
901 int src_alpha1 = ((int)(src_scan[0]) + (int)(src_scan[-2]) + (int)(src_scan[-1])) / 3;
902 ADJUST_ALPHA(dest_scan[2], r, src_alpha1, nativetext_flags, a);
903 src_alpha1 = src_alpha1 * a / 255;
904 if (src_alpha1 == 0) {
909 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha1));
910 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha1));
911 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha1));
916 int src_alpha = src_scan[-2];
917 ADJUST_ALPHA(dest_scan[2], r, src_alpha, nativetext_flags, a);
918 src_alpha = src_alpha * a / 255;
919 dest_scan[2] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[2]), r, src_alpha));
920 src_alpha = src_scan[-1];
921 ADJUST_ALPHA(dest_scan[1], g, src_alpha, nativetext_flags, a);
922 src_alpha = src_alpha * a / 255;
923 dest_scan[1] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[1]), g, src_alpha));
924 src_alpha = src_scan[0];
925 ADJUST_ALPHA(dest_scan[0], b, src_alpha, nativetext_flags, a);
926 src_alpha = src_alpha * a / 255;
927 dest_scan[0] = FX_GAMMA_INVERSE(FXDIB_ALPHA_MERGE(FX_GAMMA(dest_scan[0]), b, src_alpha));
936 if (bitmap.IsAlphaMask()) {
937 SetBitMask(&bitmap, bmp_rect.left, bmp_rect.top, fill_color, alpha_flag, pIccTransform);
939 SetDIBits(&bitmap, bmp_rect.left, bmp_rect.top);
941 FX_Free(pGlyphAndPos);
944 FX_BOOL CFX_RenderDevice::DrawTextPath(int nChars, const FXTEXT_CHARPOS* pCharPos,
945 CFX_Font* pFont, CFX_FontCache* pCache,
946 FX_FLOAT font_size, const CFX_AffineMatrix* pText2User,
947 const CFX_AffineMatrix* pUser2Device, const CFX_GraphStateData* pGraphState,
948 FX_DWORD fill_color, FX_ARGB stroke_color, CFX_PathData* pClippingPath, int nFlag,
949 int alpha_flag, void* pIccTransform, int blend_type)
951 if (pCache == NULL) {
952 pCache = CFX_GEModule::Get()->GetFontCache();
954 CFX_FaceCache* pFaceCache = pCache->GetCachedFace(pFont);
955 FX_FONTCACHE_DEFINE(pCache, pFont);
956 for (int iChar = 0; iChar < nChars; iChar ++) {
957 const FXTEXT_CHARPOS& charpos = pCharPos[iChar];
958 CFX_AffineMatrix matrix;
959 if (charpos.m_bGlyphAdjust)
960 matrix.Set(charpos.m_AdjustMatrix[0], charpos.m_AdjustMatrix[1],
961 charpos.m_AdjustMatrix[2], charpos.m_AdjustMatrix[3], 0, 0);
962 matrix.Concat(font_size, 0, 0, font_size, charpos.m_OriginX, charpos.m_OriginY);
963 const CFX_PathData* pPath = pFaceCache->LoadGlyphPath(pFont, charpos.m_GlyphIndex, charpos.m_FontCharWidth);
967 matrix.Concat(*pText2User);
968 CFX_PathData TransformedPath(*pPath);
969 TransformedPath.Transform(&matrix);
970 FX_BOOL bHasAlpha = FXGETFLAG_COLORTYPE(alpha_flag) ?
971 (FXGETFLAG_ALPHA_FILL(alpha_flag) || FXGETFLAG_ALPHA_STROKE(alpha_flag)) :
972 (fill_color || stroke_color);
974 int fill_mode = nFlag;
975 if (FXGETFLAG_COLORTYPE(alpha_flag)) {
976 if (FXGETFLAG_ALPHA_FILL(alpha_flag)) {
977 fill_mode |= FXFILL_WINDING;
981 fill_mode |= FXFILL_WINDING;
984 fill_mode |= FX_FILL_TEXT_MODE;
985 if (!DrawPath(&TransformedPath, pUser2Device, pGraphState, fill_color, stroke_color, fill_mode, alpha_flag, pIccTransform, blend_type)) {
990 pClippingPath->Append(&TransformedPath, pUser2Device);
995 CFX_FontCache::~CFX_FontCache()
999 CFX_FaceCache* CFX_FontCache::GetCachedFace(CFX_Font* pFont)
1001 FX_BOOL bExternal = pFont->GetFace() == NULL;
1002 void* face = bExternal ? pFont->GetSubstFont()->m_ExtHandle : pFont->GetFace();
1003 CFX_FTCacheMap& map = bExternal ? m_ExtFaceMap : m_FTFaceMap;
1004 CFX_CountedFaceCache* counted_face_cache = NULL;
1005 if (map.Lookup((FXFT_Face)face, counted_face_cache)) {
1006 counted_face_cache->m_nCount++;
1007 return counted_face_cache->m_Obj;
1009 CFX_FaceCache* face_cache = NULL;
1010 face_cache = FX_NEW CFX_FaceCache(bExternal ? NULL : (FXFT_Face)face);
1011 if (face_cache == NULL) {
1014 counted_face_cache = FX_NEW CFX_CountedFaceCache;
1015 if (!counted_face_cache) {
1022 counted_face_cache->m_nCount = 2;
1023 counted_face_cache->m_Obj = face_cache;
1024 map.SetAt((FXFT_Face)face, counted_face_cache);
1027 void CFX_FontCache::ReleaseCachedFace(CFX_Font* pFont)
1029 FX_BOOL bExternal = pFont->GetFace() == NULL;
1030 void* face = bExternal ? pFont->GetSubstFont()->m_ExtHandle : pFont->GetFace();
1031 CFX_FTCacheMap& map = bExternal ? m_ExtFaceMap : m_FTFaceMap;
1032 CFX_CountedFaceCache* counted_face_cache = NULL;
1033 if (!map.Lookup((FXFT_Face)face, counted_face_cache)) {
1036 if (counted_face_cache->m_nCount > 1) {
1037 counted_face_cache->m_nCount--;
1040 void CFX_FontCache::FreeCache(FX_BOOL bRelease)
1044 pos = m_FTFaceMap.GetStartPosition();
1047 CFX_CountedFaceCache* cache;
1048 m_FTFaceMap.GetNextAssoc(pos, face, cache);
1049 if (bRelease || cache->m_nCount < 2) {
1050 delete cache->m_Obj;
1052 m_FTFaceMap.RemoveKey(face);
1055 pos = m_ExtFaceMap.GetStartPosition();
1058 CFX_CountedFaceCache* cache;
1059 m_ExtFaceMap.GetNextAssoc(pos, face, cache);
1060 if (bRelease || cache->m_nCount < 2) {
1061 delete cache->m_Obj;
1063 m_ExtFaceMap.RemoveKey(face);
1068 CFX_FaceCache::CFX_FaceCache(FXFT_Face face)
1073 CFX_FaceCache::~CFX_FaceCache()
1075 FX_POSITION pos = m_SizeMap.GetStartPosition();
1077 CFX_SizeGlyphCache* pSizeCache = NULL;
1079 m_SizeMap.GetNextAssoc( pos, Key, (void*&)pSizeCache);
1082 m_SizeMap.RemoveAll();
1083 pos = m_PathMap.GetStartPosition();
1085 CFX_PathData* pPath;
1087 m_PathMap.GetNextAssoc(pos, key1, (FX_LPVOID&)pPath);
1093 m_PathMap.RemoveAll();
1095 #if ((_FXM_PLATFORM_ != _FXM_PLATFORM_APPLE_)|| defined(_FPDFAPI_MINI_))
1096 void CFX_FaceCache::InitPlatform()
1100 CFX_GlyphBitmap* CFX_FaceCache::LookUpGlyphBitmap(CFX_Font* pFont, const CFX_AffineMatrix* pMatrix,
1101 CFX_ByteStringC& FaceGlyphsKey, FX_DWORD glyph_index, FX_BOOL bFontStyle,
1102 int dest_width, int anti_alias)
1104 CFX_SizeGlyphCache* pSizeCache = NULL;
1105 if (!m_SizeMap.Lookup(FaceGlyphsKey, (void*&)pSizeCache)) {
1106 pSizeCache = FX_NEW CFX_SizeGlyphCache;
1107 if (pSizeCache == NULL) {
1110 m_SizeMap.SetAt(FaceGlyphsKey, pSizeCache);
1112 CFX_GlyphBitmap* pGlyphBitmap = NULL;
1113 if (pSizeCache->m_GlyphMap.Lookup((FX_LPVOID)(FX_UINTPTR)glyph_index, (void*&)pGlyphBitmap)) {
1114 return pGlyphBitmap;
1116 pGlyphBitmap = RenderGlyph(pFont, glyph_index, bFontStyle, pMatrix, dest_width, anti_alias);
1117 if (pGlyphBitmap == NULL) {
1120 pSizeCache->m_GlyphMap.SetAt((FX_LPVOID)(FX_UINTPTR)glyph_index, pGlyphBitmap);
1121 return pGlyphBitmap;
1123 const CFX_GlyphBitmap* CFX_FaceCache::LoadGlyphBitmap(CFX_Font* pFont, FX_DWORD glyph_index, FX_BOOL bFontStyle, const CFX_AffineMatrix* pMatrix,
1124 int dest_width, int anti_alias, int& text_flags)
1126 if (glyph_index == (FX_DWORD) - 1) {
1129 _CFX_UniqueKeyGen keygen;
1130 #if ((_FXM_PLATFORM_ != _FXM_PLATFORM_APPLE_)|| defined(_FPDFAPI_MINI_))
1131 if (pFont->GetSubstFont())
1132 keygen.Generate(9, (int)(pMatrix->a * 10000), (int)(pMatrix->b * 10000),
1133 (int)(pMatrix->c * 10000), (int)(pMatrix->d * 10000), dest_width, anti_alias,
1134 pFont->GetSubstFont()->m_Weight, pFont->GetSubstFont()->m_ItalicAngle, pFont->IsVertical());
1136 keygen.Generate(6, (int)(pMatrix->a * 10000), (int)(pMatrix->b * 10000),
1137 (int)(pMatrix->c * 10000), (int)(pMatrix->d * 10000), dest_width, anti_alias);
1139 if (text_flags & FXTEXT_NO_NATIVETEXT) {
1140 if (pFont->GetSubstFont())
1141 keygen.Generate(9, (int)(pMatrix->a * 10000), (int)(pMatrix->b * 10000),
1142 (int)(pMatrix->c * 10000), (int)(pMatrix->d * 10000), dest_width, anti_alias,
1143 pFont->GetSubstFont()->m_Weight, pFont->GetSubstFont()->m_ItalicAngle, pFont->IsVertical());
1145 keygen.Generate(6, (int)(pMatrix->a * 10000), (int)(pMatrix->b * 10000),
1146 (int)(pMatrix->c * 10000), (int)(pMatrix->d * 10000), dest_width, anti_alias);
1148 if (pFont->GetSubstFont())
1149 keygen.Generate(10, (int)(pMatrix->a * 10000), (int)(pMatrix->b * 10000),
1150 (int)(pMatrix->c * 10000), (int)(pMatrix->d * 10000), dest_width, anti_alias,
1151 pFont->GetSubstFont()->m_Weight, pFont->GetSubstFont()->m_ItalicAngle, pFont->IsVertical(), 3);
1153 keygen.Generate(7, (int)(pMatrix->a * 10000), (int)(pMatrix->b * 10000),
1154 (int)(pMatrix->c * 10000), (int)(pMatrix->d * 10000), dest_width, anti_alias, 3);
1157 CFX_ByteStringC FaceGlyphsKey(keygen.m_Key, keygen.m_KeyLen);
1158 #if ((_FXM_PLATFORM_ != _FXM_PLATFORM_APPLE_)|| defined(_FPDFAPI_MINI_))
1159 return LookUpGlyphBitmap(pFont, pMatrix, FaceGlyphsKey, glyph_index, bFontStyle, dest_width, anti_alias);
1161 if (text_flags & FXTEXT_NO_NATIVETEXT) {
1162 return LookUpGlyphBitmap(pFont, pMatrix, FaceGlyphsKey, glyph_index, bFontStyle, dest_width, anti_alias);
1164 CFX_GlyphBitmap* pGlyphBitmap;
1165 CFX_SizeGlyphCache* pSizeCache = NULL;
1166 if (m_SizeMap.Lookup(FaceGlyphsKey, (void*&)pSizeCache)) {
1167 if (pSizeCache->m_GlyphMap.Lookup((FX_LPVOID)(FX_UINTPTR)glyph_index, (void*&)pGlyphBitmap)) {
1168 return pGlyphBitmap;
1170 pGlyphBitmap = RenderGlyph_Nativetext(pFont, glyph_index, pMatrix, dest_width, anti_alias);
1172 pSizeCache->m_GlyphMap.SetAt((FX_LPVOID)(FX_UINTPTR)glyph_index, pGlyphBitmap);
1173 return pGlyphBitmap;
1176 pGlyphBitmap = RenderGlyph_Nativetext(pFont, glyph_index, pMatrix, dest_width, anti_alias);
1178 pSizeCache = FX_NEW CFX_SizeGlyphCache;
1179 if (pSizeCache == NULL) {
1182 m_SizeMap.SetAt(FaceGlyphsKey, pSizeCache);
1183 pSizeCache->m_GlyphMap.SetAt((FX_LPVOID)(FX_UINTPTR)glyph_index, pGlyphBitmap);
1184 return pGlyphBitmap;
1187 if (pFont->GetSubstFont())
1188 keygen.Generate(9, (int)(pMatrix->a * 10000), (int)(pMatrix->b * 10000),
1189 (int)(pMatrix->c * 10000), (int)(pMatrix->d * 10000), dest_width, anti_alias,
1190 pFont->GetSubstFont()->m_Weight, pFont->GetSubstFont()->m_ItalicAngle, pFont->IsVertical());
1192 keygen.Generate(6, (int)(pMatrix->a * 10000), (int)(pMatrix->b * 10000),
1193 (int)(pMatrix->c * 10000), (int)(pMatrix->d * 10000), dest_width, anti_alias);
1194 CFX_ByteStringC FaceGlyphsKey(keygen.m_Key, keygen.m_KeyLen);
1195 text_flags |= FXTEXT_NO_NATIVETEXT;
1196 return LookUpGlyphBitmap(pFont, pMatrix, FaceGlyphsKey, glyph_index, bFontStyle, dest_width, anti_alias);
1200 CFX_SizeGlyphCache::~CFX_SizeGlyphCache()
1202 FX_POSITION pos = m_GlyphMap.GetStartPosition();
1204 CFX_GlyphBitmap* pGlyphBitmap = NULL;
1206 m_GlyphMap.GetNextAssoc(pos, Key, (void*&)pGlyphBitmap);
1207 delete pGlyphBitmap;
1209 m_GlyphMap.RemoveAll();
1211 #if defined(_FPDFAPI_MINI_)
1212 #define CONTRAST_RAMP_STEP 16
1214 #define CONTRAST_RAMP_STEP 1
1216 static const FX_BYTE g_adjust_contrast11[256] = {
1217 0, 0, 2, 3, 4, 5, 6, 8, 9, 10, 11, 13, 14, 15, 17, 18, 19, 21, 22, 24, 25, 26, 28, 29, 31,
1218 32, 33, 35, 36, 38, 39, 40, 42, 43, 45, 46, 48, 49, 51, 52, 54, 55, 56, 58, 59, 61, 62, 64, 65,
1219 67, 68, 70, 71, 72, 74, 75, 77, 78, 80, 81, 83, 84, 86, 87, 89, 90, 91, 93, 94, 96, 97, 99, 100,
1220 101, 103, 104, 106, 107, 109, 110, 111, 113, 114, 116, 117, 118, 120, 121, 123, 124, 125, 127,
1221 128, 130, 131, 132, 134, 135, 136, 138, 139, 140, 142, 143, 144, 146, 147, 148, 149, 151, 152,
1222 153, 155, 156, 157, 158, 160, 161, 162, 163, 165, 166, 167, 168, 169, 171, 172, 173, 174, 175,
1223 177, 178, 179, 180, 181, 182, 183, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196,
1224 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215,
1225 215, 216, 217, 218, 219, 220, 221, 221, 222, 223, 224, 224, 225, 226, 227, 227, 228, 229, 230,
1226 230, 231, 232, 232, 233, 234, 234, 235, 236, 236, 237, 237, 238, 239, 239, 240, 240, 241, 241,
1227 242, 242, 243, 243, 244, 244, 245, 245, 246, 246, 246, 247, 247, 248, 248, 248, 249, 249, 249,
1228 250, 250, 250, 251, 251, 251, 251, 252, 252, 252, 252, 253, 253, 253, 253, 253, 253, 254, 254,
1229 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 255,
1231 static const FX_BYTE g_adjust_contrast15[256] = {
1232 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 5, 5, 6, 7, 7, 8, 9, 10, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
1233 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 34, 35, 36, 37, 38, 40, 41, 42, 43, 45, 46, 47, 48, 50, 51,
1234 52, 54, 55, 56, 58, 59, 60, 62, 63, 64, 66, 67, 68, 70, 71, 73, 74, 75, 77, 78, 80, 81, 82, 84, 85, 87,
1235 88, 90, 91, 93, 94, 95, 97, 98, 100, 101, 103, 104, 106, 107, 109, 110, 111, 113, 114, 116, 117, 119,
1236 120, 122, 123, 125, 126, 128, 129, 130, 132, 133, 135, 136, 138, 139, 141, 142, 143, 145, 146, 148,
1237 149, 150, 152, 153, 155, 156, 157, 159, 160, 161, 163, 164, 166, 167, 168, 170, 171, 172, 174, 175,
1238 176, 177, 179, 180, 181, 183, 184, 185, 186, 188, 189, 190, 191, 192, 194, 195, 196, 197, 198, 199,
1239 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220,
1240 221, 222, 223, 224, 225, 226, 227, 227, 228, 229, 230, 231, 232, 232, 233, 234, 235, 235, 236, 237,
1241 237, 238, 239, 239, 240, 241, 241, 242, 242, 243, 244, 244, 245, 245, 246, 246, 247, 247, 248, 248,
1242 248, 249, 249, 250, 250, 250, 251, 251, 251, 252, 252, 252, 252, 253, 253, 253, 253, 253, 254, 254,
1243 254, 254, 254, 254, 254, 254, 254, 254, 254, 255,
1245 static void _CalcContrastRamp(FX_LPBYTE ramp, int level)
1247 int contrast_min = 0, contrast_max = 255 - level, i;
1248 for (i = 0; i < contrast_min; i ++) {
1251 for (i = contrast_min; i < contrast_max; i ++) {
1252 ramp[i] = 255 * (i - contrast_min) / (contrast_max - contrast_min);
1254 for (i = contrast_max; i < 256; i ++) {
1258 void CFX_Font::AdjustMMParams(int glyph_index, int dest_width, int weight)
1260 FXFT_MM_Var pMasters = NULL;
1261 FXFT_Get_MM_Var(m_Face, &pMasters);
1262 if (pMasters == NULL) {
1267 coords[0] = FXFT_Get_MM_Axis_Def(FXFT_Get_MM_Axis(pMasters, 0)) / 65536;
1271 if (dest_width == 0) {
1272 coords[1] = FXFT_Get_MM_Axis_Def(FXFT_Get_MM_Axis(pMasters, 1)) / 65536;
1274 int min_param = FXFT_Get_MM_Axis_Min(FXFT_Get_MM_Axis(pMasters, 1)) / 65536;
1275 int max_param = FXFT_Get_MM_Axis_Max(FXFT_Get_MM_Axis(pMasters, 1)) / 65536;
1276 coords[1] = min_param;
1277 int error = FXFT_Set_MM_Design_Coordinates(m_Face, 2, coords);
1278 error = FXFT_Load_Glyph(m_Face, glyph_index, FXFT_LOAD_NO_SCALE | FXFT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH);
1279 int min_width = FXFT_Get_Glyph_HoriAdvance(m_Face) * 1000 / FXFT_Get_Face_UnitsPerEM(m_Face);
1280 coords[1] = max_param;
1281 error = FXFT_Set_MM_Design_Coordinates(m_Face, 2, coords);
1282 error = FXFT_Load_Glyph(m_Face, glyph_index, FXFT_LOAD_NO_SCALE | FXFT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH);
1283 int max_width = FXFT_Get_Glyph_HoriAdvance(m_Face) * 1000 / FXFT_Get_Face_UnitsPerEM(m_Face);
1284 if (max_width == min_width) {
1287 int param = min_param + (max_param - min_param) * (dest_width - min_width) / (max_width - min_width);
1290 FXFT_Free(m_Face, pMasters);
1291 FXFT_Set_MM_Design_Coordinates(m_Face, 2, coords);
1293 extern const char g_AngleSkew[30] = {
1294 0, 2, 3, 5, 7, 9, 11, 12, 14, 16,
1295 18, 19, 21, 23, 25, 27, 29, 31, 32, 34,
1296 36, 38, 40, 42, 45, 47, 49, 51, 53, 55,
1298 static const FX_BYTE g_WeightPow[100] = {
1299 0, 3, 6, 7, 8, 9, 11, 12, 14, 15, 16, 17, 18, 19, 20,
1300 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 35, 36, 36,
1301 37, 37, 37, 38, 38, 38, 39, 39, 39, 40, 40, 40, 41, 41, 41, 42, 42, 42,
1302 42, 43, 43, 43, 44, 44, 44, 44, 45, 45, 45, 45, 46, 46, 46, 46, 47, 47,
1303 47, 47, 48, 48, 48, 48, 48, 49, 49, 49, 49, 50, 50, 50, 50, 50, 51, 51,
1304 51, 51, 51, 52, 52, 52, 52, 52, 53, 53, 53, 53, 53,
1306 extern const FX_BYTE g_WeightPow_11[100] = {
1307 0, 4, 7, 8, 9, 10, 12, 13, 15, 17, 18, 19, 20, 21, 22,
1308 23, 24, 25, 26, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 39, 39, 40, 40,
1309 41, 41, 41, 42, 42, 42, 43, 43, 43, 44, 44, 44, 45, 45, 45, 46, 46, 46,
1310 46, 43, 47, 47, 48, 48, 48, 48, 45, 50, 50, 50, 46, 51, 51, 51, 52, 52,
1311 52, 52, 53, 53, 53, 53, 53, 54, 54, 54, 54, 55, 55, 55, 55, 55, 56, 56,
1312 56, 56, 56, 57, 57, 57, 57, 57, 58, 58, 58, 58, 58,
1314 extern const FX_BYTE g_WeightPow_SHIFTJIS[100] = {
1315 0, 0, 1, 2, 3, 4, 5, 7, 8, 10, 11, 13, 14, 16, 17, 19, 21, 22, 24, 26, 28,
1316 30, 32, 33, 35, 37, 39, 41, 43, 45, 48, 48, 48, 48, 49, 49, 49, 50, 50, 50, 50,
1317 51, 51, 51, 51, 52, 52, 52, 52, 52, 53, 53, 53, 53, 53, 54, 54, 54, 54, 54, 55, 55,
1318 55, 55, 55, 56, 56, 56, 56, 56 , 56, 57, 57, 57 , 57 , 57, 57, 57, 58, 58, 58, 58, 58,
1319 58, 58, 59, 59, 59, 59, 59, 59, 59, 60, 60, 60, 60, 60, 60, 60, 60,
1321 static void _GammaAdjust(FX_LPBYTE pData, int nWid, int nHei, int src_pitch, FX_LPCBYTE gammaTable)
1323 int count = nHei * src_pitch;
1324 for(int i = 0; i < count; i++) {
1325 pData[i] = gammaTable[pData[i]];
1328 static void _ContrastAdjust(FX_LPBYTE pDataIn, FX_LPBYTE pDataOut, int nWid, int nHei, int nSrcRowBytes, int nDstRowBytes)
1331 int max = 0, min = 255;
1333 for (row = 0; row < nHei; row ++) {
1334 FX_LPBYTE pRow = pDataIn + row * nSrcRowBytes;
1335 for (col = 0; col < nWid; col++) {
1346 if (0 == temp || 255 == temp) {
1347 int rowbytes = FXSYS_abs(nSrcRowBytes) > nDstRowBytes ? nDstRowBytes : FXSYS_abs(nSrcRowBytes);
1348 for (row = 0; row < nHei; row ++) {
1349 FXSYS_memcpy32(pDataOut + row * nDstRowBytes, pDataIn + row * nSrcRowBytes, rowbytes);
1353 rate = 255.f / temp;
1354 for (row = 0; row < nHei; row ++) {
1355 FX_LPBYTE pSrcRow = pDataIn + row * nSrcRowBytes;
1356 FX_LPBYTE pDstRow = pDataOut + row * nDstRowBytes;
1357 for (col = 0; col < nWid; col ++) {
1358 temp = (int)((*(pSrcRow++) - min) * rate + 0.5);
1361 } else if (temp < 0) {
1364 *pDstRow ++ = (FX_BYTE)temp;
1368 CFX_GlyphBitmap* CFX_FaceCache::RenderGlyph(CFX_Font* pFont, FX_DWORD glyph_index, FX_BOOL bFontStyle,
1369 const CFX_AffineMatrix* pMatrix, int dest_width, int anti_alias)
1371 if (m_Face == NULL) {
1374 FXFT_Matrix ft_matrix;
1375 ft_matrix.xx = (signed long)(pMatrix->GetA() / 64 * 65536);
1376 ft_matrix.xy = (signed long)(pMatrix->GetC() / 64 * 65536);
1377 ft_matrix.yx = (signed long)(pMatrix->GetB() / 64 * 65536);
1378 ft_matrix.yy = (signed long)(pMatrix->GetD() / 64 * 65536);
1379 FX_BOOL bUseCJKSubFont = FALSE;
1380 const CFX_SubstFont* pSubstFont = pFont->GetSubstFont();
1382 bUseCJKSubFont = pSubstFont->m_bSubstOfCJK && bFontStyle;
1384 if (bUseCJKSubFont) {
1385 skew = pSubstFont->m_bItlicCJK ? -15 : 0;
1387 skew = pSubstFont->m_ItalicAngle;
1390 skew = skew <= -30 ? -58 : -g_AngleSkew[-skew];
1391 if (pFont->IsVertical()) {
1392 ft_matrix.yx += ft_matrix.yy * skew / 100;
1394 ft_matrix.xy += -ft_matrix.xx * skew / 100;
1397 if (pSubstFont->m_SubstFlags & FXFONT_SUBST_MM) {
1398 pFont->AdjustMMParams(glyph_index, dest_width, pFont->GetSubstFont()->m_Weight);
1401 int transflag = FXFT_Get_Face_Internal_Flag(m_Face);
1402 FXFT_Set_Transform(m_Face, &ft_matrix, 0);
1403 int load_flags = (m_Face->face_flags & FT_FACE_FLAG_SFNT) ? FXFT_LOAD_NO_BITMAP : (FXFT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING);
1404 int error = FXFT_Load_Glyph(m_Face, glyph_index, load_flags);
1406 FXFT_Set_Face_Internal_Flag(m_Face, transflag);
1410 if (bUseCJKSubFont) {
1411 weight = pSubstFont->m_WeightCJK;
1413 weight = pSubstFont ? pSubstFont->m_Weight : 0;
1415 if (pSubstFont && !(pSubstFont->m_SubstFlags & FXFONT_SUBST_MM) && weight > 400) {
1416 int index = (weight - 400) / 10;
1418 FXFT_Set_Face_Internal_Flag(m_Face, transflag);
1422 if (pSubstFont->m_Charset == FXFONT_SHIFTJIS_CHARSET) {
1423 level = g_WeightPow_SHIFTJIS[index] * 2 * (FXSYS_abs((int)(ft_matrix.xx)) + FXSYS_abs((int)(ft_matrix.xy))) / 36655;
1425 level = g_WeightPow_11[index] * (FXSYS_abs((int)(ft_matrix.xx)) + FXSYS_abs((int)(ft_matrix.xy))) / 36655;
1427 FXFT_Outline_Embolden(FXFT_Get_Glyph_Outline(m_Face), level);
1429 FXFT_Library_SetLcdFilter(CFX_GEModule::Get()->GetFontMgr()->m_FTLibrary, FT_LCD_FILTER_DEFAULT);
1430 error = FXFT_Render_Glyph(m_Face, anti_alias);
1432 FXFT_Set_Face_Internal_Flag(m_Face, transflag);
1435 int bmwidth = FXFT_Get_Bitmap_Width(FXFT_Get_Glyph_Bitmap(m_Face));
1436 int bmheight = FXFT_Get_Bitmap_Rows(FXFT_Get_Glyph_Bitmap(m_Face));
1437 if (bmwidth > 2048 || bmheight > 2048) {
1438 FXFT_Set_Face_Internal_Flag(m_Face, transflag);
1441 int dib_width = bmwidth;
1442 CFX_GlyphBitmap* pGlyphBitmap = FX_NEW CFX_GlyphBitmap;
1443 if (!pGlyphBitmap) {
1446 pGlyphBitmap->m_Bitmap.Create(dib_width, bmheight,
1447 anti_alias == FXFT_RENDER_MODE_MONO ? FXDIB_1bppMask : FXDIB_8bppMask);
1448 pGlyphBitmap->m_Left = FXFT_Get_Glyph_BitmapLeft(m_Face);
1449 pGlyphBitmap->m_Top = FXFT_Get_Glyph_BitmapTop(m_Face);
1450 int dest_pitch = pGlyphBitmap->m_Bitmap.GetPitch();
1451 int src_pitch = FXFT_Get_Bitmap_Pitch(FXFT_Get_Glyph_Bitmap(m_Face));
1452 FX_BYTE* pDestBuf = pGlyphBitmap->m_Bitmap.GetBuffer();
1453 FX_BYTE* pSrcBuf = (FX_BYTE*)FXFT_Get_Bitmap_Buffer(FXFT_Get_Glyph_Bitmap(m_Face));
1454 if (anti_alias != FXFT_RENDER_MODE_MONO && FXFT_Get_Bitmap_PixelMode(FXFT_Get_Glyph_Bitmap(m_Face)) == FXFT_PIXEL_MODE_MONO) {
1455 int bytes = anti_alias == FXFT_RENDER_MODE_LCD ? 3 : 1;
1456 for(int i = 0; i < bmheight; i++)
1457 for(int n = 0; n < bmwidth; n++) {
1458 FX_BYTE data = (pSrcBuf[i * src_pitch + n / 8] & (0x80 >> (n % 8))) ? 255 : 0;
1459 for (int b = 0; b < bytes; b ++) {
1460 pDestBuf[i * dest_pitch + n * bytes + b] = data;
1464 FXSYS_memset32(pDestBuf, 0, dest_pitch * bmheight);
1465 if (anti_alias == FXFT_RENDER_MODE_MONO && FXFT_Get_Bitmap_PixelMode(FXFT_Get_Glyph_Bitmap(m_Face)) == FXFT_PIXEL_MODE_MONO) {
1466 int rowbytes = FXSYS_abs(src_pitch) > dest_pitch ? dest_pitch : FXSYS_abs(src_pitch);
1467 for (int row = 0; row < bmheight; row ++) {
1468 FXSYS_memcpy32(pDestBuf + row * dest_pitch, pSrcBuf + row * src_pitch, rowbytes);
1471 _ContrastAdjust(pSrcBuf, pDestBuf, bmwidth, bmheight, src_pitch, dest_pitch);
1472 _GammaAdjust(pDestBuf, bmwidth, bmheight, dest_pitch, CFX_GEModule::Get()->GetTextGammaTable());
1475 FXFT_Set_Face_Internal_Flag(m_Face, transflag);
1476 return pGlyphBitmap;
1478 FX_BOOL _OutputGlyph(void* dib, int x, int y, CFX_Font* pFont,
1479 int glyph_index, FX_ARGB argb)
1481 CFX_DIBitmap* pDib = (CFX_DIBitmap*)dib;
1482 FXFT_Face face = pFont->GetFace();
1483 int error = FXFT_Load_Glyph(face, glyph_index, FXFT_LOAD_NO_BITMAP);
1487 error = FXFT_Render_Glyph(face, FXFT_RENDER_MODE_NORMAL);
1491 int bmwidth = FXFT_Get_Bitmap_Width(FXFT_Get_Glyph_Bitmap(face));
1492 int bmheight = FXFT_Get_Bitmap_Rows(FXFT_Get_Glyph_Bitmap(face));
1493 int left = FXFT_Get_Glyph_BitmapLeft(face);
1494 int top = FXFT_Get_Glyph_BitmapTop(face);
1495 FX_LPCBYTE src_buf = (FX_LPCBYTE)FXFT_Get_Bitmap_Buffer(FXFT_Get_Glyph_Bitmap(face));
1496 int src_pitch = FXFT_Get_Bitmap_Pitch(FXFT_Get_Glyph_Bitmap(face));
1498 mask.Create(bmwidth, bmheight, FXDIB_8bppMask);
1499 FX_LPBYTE dest_buf = mask.GetBuffer();
1500 int dest_pitch = mask.GetPitch();
1501 for (int row = 0; row < bmheight; row ++) {
1502 FX_LPCBYTE src_scan = src_buf + row * src_pitch;
1503 FX_LPBYTE dest_scan = dest_buf + row * dest_pitch;
1504 FXSYS_memcpy32(dest_scan, src_scan, dest_pitch);
1506 pDib->CompositeMask(x + left, y - top, bmwidth, bmheight, &mask, argb, 0, 0);
1509 FX_BOOL OutputText(void* dib, int x, int y, CFX_Font* pFont, double font_size,
1510 CFX_AffineMatrix* pText_matrix, unsigned short const* text, unsigned long argb)
1515 FXFT_Face face = pFont->GetFace();
1516 FXFT_Select_Charmap(pFont->m_Face, FXFT_ENCODING_UNICODE);
1517 int transflag = FXFT_Get_Face_Internal_Flag(pFont->m_Face);
1519 FXFT_Matrix ft_matrix;
1520 ft_matrix.xx = (signed long)(pText_matrix->a / 64 * 65536);
1521 ft_matrix.xy = (signed long)(pText_matrix->c / 64 * 65536);
1522 ft_matrix.yx = (signed long)(pText_matrix->b / 64 * 65536);
1523 ft_matrix.yy = (signed long)(pText_matrix->d / 64 * 65536);
1524 FXFT_Set_Transform(face, &ft_matrix, 0);
1527 for (; *text != 0; text ++) {
1528 FX_WCHAR unicode = *text;
1529 int glyph_index = FXFT_Get_Char_Index(pFont->m_Face, unicode);
1530 if (glyph_index <= 0) {
1533 int err = FXFT_Load_Glyph(pFont->m_Face, glyph_index, FXFT_LOAD_NO_SCALE | FXFT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH);
1537 int w = FXFT_Get_Glyph_HoriAdvance(pFont->m_Face);
1538 int em = FXFT_Get_Face_UnitsPerEM(pFont->m_Face);
1540 pText_matrix->Transform(x_pos, 0, x1, y1);
1541 _OutputGlyph(dib, (int)x1 + x, (int) - y1 + y, pFont,
1543 x_pos += (FX_FLOAT)w / em;
1545 FXFT_Set_Face_Internal_Flag(pFont->m_Face, transflag);
1548 FX_BOOL OutputGlyph(void* dib, int x, int y, CFX_Font* pFont, double font_size,
1549 CFX_AffineMatrix* pMatrix, unsigned long glyph_index, unsigned long argb)
1551 FXFT_Matrix ft_matrix;
1553 ft_matrix.xx = (signed long)(pMatrix->a * font_size / 64 * 65536);
1554 ft_matrix.xy = (signed long)(pMatrix->c * font_size / 64 * 65536);
1555 ft_matrix.yx = (signed long)(pMatrix->b * font_size / 64 * 65536);
1556 ft_matrix.yy = (signed long)(pMatrix->d * font_size / 64 * 65536);
1558 ft_matrix.xx = (signed long)(font_size / 64 * 65536);
1559 ft_matrix.xy = ft_matrix.yx = 0;
1560 ft_matrix.yy = (signed long)(font_size / 64 * 65536);
1562 int transflag = FXFT_Get_Face_Internal_Flag(pFont->m_Face);
1563 FXFT_Set_Transform(pFont->m_Face, &ft_matrix, 0);
1564 FX_BOOL ret = _OutputGlyph(dib, x, y, pFont,
1566 FXFT_Set_Face_Internal_Flag(pFont->m_Face, transflag);
1569 const CFX_PathData* CFX_FaceCache::LoadGlyphPath(CFX_Font* pFont, FX_DWORD glyph_index, int dest_width)
1571 if (m_Face == NULL || glyph_index == (FX_DWORD) - 1) {
1574 CFX_PathData* pGlyphPath = NULL;
1576 if (pFont->GetSubstFont())
1577 key = (FX_LPVOID)(FX_UINTPTR)(glyph_index + ((pFont->GetSubstFont()->m_Weight / 16) << 15) +
1578 ((pFont->GetSubstFont()->m_ItalicAngle / 2) << 21) + ((dest_width / 16) << 25) +
1579 (pFont->IsVertical() << 31));
1581 key = (FX_LPVOID)(FX_UINTPTR)glyph_index;
1583 if (m_PathMap.Lookup(key, (FX_LPVOID&)pGlyphPath)) {
1586 pGlyphPath = pFont->LoadGlyphPath(glyph_index, dest_width);
1587 m_PathMap.SetAt(key, pGlyphPath);
1593 FX_PATHPOINT* m_pPoints;
1596 FX_FLOAT m_CoordUnit;
1598 void _Outline_CheckEmptyContour(OUTLINE_PARAMS* param)
1600 if (param->m_PointCount >= 2 && param->m_pPoints[param->m_PointCount - 2].m_Flag == FXPT_MOVETO &&
1601 param->m_pPoints[param->m_PointCount - 2].m_PointX == param->m_pPoints[param->m_PointCount - 1].m_PointX &&
1602 param->m_pPoints[param->m_PointCount - 2].m_PointY == param->m_pPoints[param->m_PointCount - 1].m_PointY) {
1603 param->m_PointCount -= 2;
1605 if (param->m_PointCount >= 4 && param->m_pPoints[param->m_PointCount - 4].m_Flag == FXPT_MOVETO &&
1606 param->m_pPoints[param->m_PointCount - 3].m_Flag == FXPT_BEZIERTO &&
1607 param->m_pPoints[param->m_PointCount - 3].m_PointX == param->m_pPoints[param->m_PointCount - 4].m_PointX &&
1608 param->m_pPoints[param->m_PointCount - 3].m_PointY == param->m_pPoints[param->m_PointCount - 4].m_PointY &&
1609 param->m_pPoints[param->m_PointCount - 2].m_PointX == param->m_pPoints[param->m_PointCount - 4].m_PointX &&
1610 param->m_pPoints[param->m_PointCount - 2].m_PointY == param->m_pPoints[param->m_PointCount - 4].m_PointY &&
1611 param->m_pPoints[param->m_PointCount - 1].m_PointX == param->m_pPoints[param->m_PointCount - 4].m_PointX &&
1612 param->m_pPoints[param->m_PointCount - 1].m_PointY == param->m_pPoints[param->m_PointCount - 4].m_PointY) {
1613 param->m_PointCount -= 4;
1617 static int _Outline_MoveTo(const FXFT_Vector* to, void* user)
1619 OUTLINE_PARAMS* param = (OUTLINE_PARAMS*)user;
1620 if (!param->m_bCount) {
1621 _Outline_CheckEmptyContour(param);
1622 param->m_pPoints[param->m_PointCount].m_PointX = to->x / param->m_CoordUnit;
1623 param->m_pPoints[param->m_PointCount].m_PointY = to->y / param->m_CoordUnit;
1624 param->m_pPoints[param->m_PointCount].m_Flag = FXPT_MOVETO;
1625 param->m_CurX = to->x;
1626 param->m_CurY = to->y;
1627 if (param->m_PointCount) {
1628 param->m_pPoints[param->m_PointCount - 1].m_Flag |= FXPT_CLOSEFIGURE;
1631 param->m_PointCount ++;
1636 static int _Outline_LineTo(const FXFT_Vector* to, void* user)
1638 OUTLINE_PARAMS* param = (OUTLINE_PARAMS*)user;
1639 if (!param->m_bCount) {
1640 param->m_pPoints[param->m_PointCount].m_PointX = to->x / param->m_CoordUnit;
1641 param->m_pPoints[param->m_PointCount].m_PointY = to->y / param->m_CoordUnit;
1642 param->m_pPoints[param->m_PointCount].m_Flag = FXPT_LINETO;
1643 param->m_CurX = to->x;
1644 param->m_CurY = to->y;
1646 param->m_PointCount ++;
1651 static int _Outline_ConicTo(const FXFT_Vector* control, const FXFT_Vector* to, void* user)
1653 OUTLINE_PARAMS* param = (OUTLINE_PARAMS*)user;
1654 if (!param->m_bCount) {
1655 param->m_pPoints[param->m_PointCount].m_PointX = (param->m_CurX + (control->x - param->m_CurX) * 2 / 3) / param->m_CoordUnit;
1656 param->m_pPoints[param->m_PointCount].m_PointY = (param->m_CurY + (control->y - param->m_CurY) * 2 / 3) / param->m_CoordUnit;
1657 param->m_pPoints[param->m_PointCount].m_Flag = FXPT_BEZIERTO;
1658 param->m_pPoints[param->m_PointCount + 1].m_PointX = (control->x + (to->x - control->x) / 3) / param->m_CoordUnit;
1659 param->m_pPoints[param->m_PointCount + 1].m_PointY = (control->y + (to->y - control->y) / 3) / param->m_CoordUnit;
1660 param->m_pPoints[param->m_PointCount + 1].m_Flag = FXPT_BEZIERTO;
1661 param->m_pPoints[param->m_PointCount + 2].m_PointX = to->x / param->m_CoordUnit;
1662 param->m_pPoints[param->m_PointCount + 2].m_PointY = to->y / param->m_CoordUnit;
1663 param->m_pPoints[param->m_PointCount + 2].m_Flag = FXPT_BEZIERTO;
1664 param->m_CurX = to->x;
1665 param->m_CurY = to->y;
1667 param->m_PointCount += 3;
1672 static int _Outline_CubicTo(const FXFT_Vector* control1, const FXFT_Vector* control2, const FXFT_Vector* to, void* user)
1674 OUTLINE_PARAMS* param = (OUTLINE_PARAMS*)user;
1675 if (!param->m_bCount) {
1676 param->m_pPoints[param->m_PointCount].m_PointX = control1->x / param->m_CoordUnit;
1677 param->m_pPoints[param->m_PointCount].m_PointY = control1->y / param->m_CoordUnit;
1678 param->m_pPoints[param->m_PointCount].m_Flag = FXPT_BEZIERTO;
1679 param->m_pPoints[param->m_PointCount + 1].m_PointX = control2->x / param->m_CoordUnit;
1680 param->m_pPoints[param->m_PointCount + 1].m_PointY = control2->y / param->m_CoordUnit;
1681 param->m_pPoints[param->m_PointCount + 1].m_Flag = FXPT_BEZIERTO;
1682 param->m_pPoints[param->m_PointCount + 2].m_PointX = to->x / param->m_CoordUnit;
1683 param->m_pPoints[param->m_PointCount + 2].m_PointY = to->y / param->m_CoordUnit;
1684 param->m_pPoints[param->m_PointCount + 2].m_Flag = FXPT_BEZIERTO;
1685 param->m_CurX = to->x;
1686 param->m_CurY = to->y;
1688 param->m_PointCount += 3;
1692 CFX_PathData* CFX_Font::LoadGlyphPath(FX_DWORD glyph_index, int dest_width)
1694 if (m_Face == NULL) {
1697 FXFT_Set_Pixel_Sizes(m_Face, 0, 64);
1698 FXFT_Matrix ft_matrix = {65536, 0, 0, 65536};
1700 if (m_pSubstFont->m_ItalicAngle) {
1701 int skew = m_pSubstFont->m_ItalicAngle;
1702 skew = skew <= -30 ? -58 : -g_AngleSkew[-skew];
1704 ft_matrix.yx += ft_matrix.yy * skew / 100;
1706 ft_matrix.xy += -ft_matrix.xx * skew / 100;
1709 if (m_pSubstFont->m_SubstFlags & FXFONT_SUBST_MM) {
1710 AdjustMMParams(glyph_index, dest_width, m_pSubstFont->m_Weight);
1713 int transflag = FXFT_Get_Face_Internal_Flag(m_Face);
1714 FXFT_Set_Transform(m_Face, &ft_matrix, 0);
1715 int load_flags = (m_Face->face_flags & FT_FACE_FLAG_SFNT) ? FXFT_LOAD_NO_BITMAP : FXFT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING;
1716 int error = FXFT_Load_Glyph(m_Face, glyph_index, load_flags);
1718 FXFT_Set_Face_Internal_Flag(m_Face, transflag);
1721 if (m_pSubstFont && !(m_pSubstFont->m_SubstFlags & FXFONT_SUBST_MM) && m_pSubstFont->m_Weight > 400) {
1723 if (m_pSubstFont->m_Charset == FXFONT_SHIFTJIS_CHARSET) {
1724 level = g_WeightPow_SHIFTJIS[(m_pSubstFont->m_Weight - 400) / 10] * 2 * 65536 / 36655;
1726 level = g_WeightPow[(m_pSubstFont->m_Weight - 400) / 10] * 2;
1728 FXFT_Outline_Embolden(FXFT_Get_Glyph_Outline(m_Face), level);
1730 FXFT_Outline_Funcs funcs;
1731 funcs.move_to = _Outline_MoveTo;
1732 funcs.line_to = _Outline_LineTo;
1733 funcs.conic_to = _Outline_ConicTo;
1734 funcs.cubic_to = _Outline_CubicTo;
1737 OUTLINE_PARAMS params;
1738 params.m_bCount = TRUE;
1739 params.m_PointCount = 0;
1740 FXFT_Outline_Decompose(FXFT_Get_Glyph_Outline(m_Face), &funcs, ¶ms);
1741 if (params.m_PointCount == 0) {
1742 FXFT_Set_Face_Internal_Flag(m_Face, transflag);
1745 CFX_PathData* pPath = FX_NEW CFX_PathData;
1749 pPath->SetPointCount(params.m_PointCount);
1750 params.m_bCount = FALSE;
1751 params.m_PointCount = 0;
1752 params.m_pPoints = pPath->GetPoints();
1753 params.m_CurX = params.m_CurY = 0;
1754 params.m_CoordUnit = 64 * 64.0;
1755 FXFT_Outline_Decompose(FXFT_Get_Glyph_Outline(m_Face), &funcs, ¶ms);
1756 _Outline_CheckEmptyContour(¶ms);
1757 pPath->TrimPoints(params.m_PointCount);
1758 if (params.m_PointCount) {
1759 pPath->GetPoints()[params.m_PointCount - 1].m_Flag |= FXPT_CLOSEFIGURE;
1761 FXFT_Set_Face_Internal_Flag(m_Face, transflag);
1764 void _CFX_UniqueKeyGen::Generate(int count, ...)
1767 va_start(argList, count);
1768 for (int i = 0; i < count; i ++) {
1769 int p = va_arg(argList, int);
1770 ((FX_DWORD*)m_Key)[i] = p;
1773 m_KeyLen = count * sizeof(FX_DWORD);