* add svn ignore
[ezgdi.git] / ezgdi / ft.cpp
blob18377b47da645346c5103613af55f0f967ed5111
1 #include "stdafx.h"
3 #include "override.h"
4 #include "ft.h"
5 #include "fteng.h"
6 #include "ft2vert.h"
8 #define IsFontBold(lf) ((lf).lfWeight > FW_NORMAL)
9 #define FT_FixedToInt(x) (FT_RoundFix(x) >> 16)
10 #define FT_PosToInt(x) (((x) + (1 << 5)) >> 6)
11 #define RESOLUTION_X 72
12 #define RESOLUTION_Y 72
13 FT_Error New_FT_Outline_Embolden( FT_Outline* outline, FT_Pos str_h, FT_Pos str_v );
14 FT_Error Old_FT_Outline_Embolden( FT_Outline* outline, FT_Pos strength );
15 FT_Error Vert_FT_Outline_Embolden( FT_Outline* outline, FT_Pos strength );
17 class CGGOKerning : public CMap<DWORD, int>
19 private:
20 DWORD makekey(WORD first, WORD second) {
21 return ((DWORD)first << 16) | second;
23 public:
24 void init(HDC hdc);
25 int get(WORD first, WORD second) {
26 DWORD key = makekey(first, second);
27 int x = FindKey(key);
28 return (x >= 0) ? GetValueAt(x) : 0;
32 void
33 CGGOKerning::init(HDC hdc)
35 DWORD rc;
36 rc = GetKerningPairs(hdc, 0, NULL);
37 if (rc <= 0) return;
38 DWORD kpcnt = rc;
39 LPKERNINGPAIR kpp = (LPKERNINGPAIR)calloc(kpcnt, sizeof *kpp);
40 if (!kpp) return;
41 rc = GetKerningPairs(hdc, kpcnt, kpp);
42 for (DWORD i = 0; i < rc; ++i) {
43 Add(makekey(kpp[i].wFirst, kpp[i].wSecond), kpp[i].iKernAmount);
45 free(kpp);
48 struct FreeTypeDrawInfo
50 FT_FaceRec_ dummy_freetype_face;
52 //FreeTypePrepare‚ª�Ý’è‚·‚é
53 FT_Face freetype_face;
54 FT_Bool useKerning;
55 FT_Render_Mode render_mode;
56 FTC_ImageTypeRec font_type;
57 FreeTypeFontInfo* pfi;
58 const CFontSettings* pfs;
59 FreeTypeFontCache* pftCache;
60 FTC_FaceID face_id_list[CFontLinkInfo::FONTMAX * 2 + 1];
61 FT_Int cmap_list[CFontLinkInfo::FONTMAX * 2 + 1];
62 int face_id_list_num;
64 //ŒÄ‚Ñ�o‚µ‘O‚ÉŽ©•ª‚Å�Ý’è‚·‚é
65 HDC hdc;
66 int x;
67 int yBase;
68 int yTop;
69 const int* lpDx;
70 CBitmapCache* pCache;
71 FREETYPE_PARAMS params;
73 FreeTypeDrawInfo(const FREETYPE_PARAMS& fp, HDC dc, LOGFONTW* lf = NULL, CBitmapCache* ca = NULL, const int* dx = NULL)
74 : freetype_face(&dummy_freetype_face), useKerning(0)
75 , pfi(NULL), pfs(NULL), pftCache(NULL), face_id_list_num(0)
76 , hdc(dc), x(0), yBase(0), yTop(0)
78 render_mode = FT_RENDER_MODE_NORMAL;
79 ZeroMemory(&font_type, sizeof(font_type));
80 ZeroMemory(&face_id_list, sizeof face_id_list);
81 ZeroMemory(&cmap_list, sizeof cmap_list);
82 lpDx = dx;
83 pCache = ca;
84 params = fp;
85 if(lf) params.lplf = lf;
86 memset(&dummy_freetype_face, 0, sizeof dummy_freetype_face);
89 const LOGFONTW& LogFont() const { return *params.lplf; }
90 COLORREF Color() const { return params.color; }
91 UINT GetETO() const { return params.etoOptions; }
92 bool IsGlyphIndex() const { return !!(params.etoOptions & ETO_GLYPH_INDEX); }
93 bool IsMono() const { return !!(params.ftOptions & FTO_MONO); }
94 bool IsSizeOnly() const { return !!(params.ftOptions & FTO_SIZE_ONLY); }
95 CGGOKerning ggokerning;
98 //fteng.cpp‚Å’è‹`
99 extern FT_Library freetype_library;
100 extern FTC_Manager cache_man;
101 extern FTC_CMapCache cmap_cache;
102 extern FTC_ImageCache image_cache;
104 class CAlphaBlend
106 private:
107 int alphatbl[256];
108 int tbl1[257];
109 BYTE tbl2[256 * 16 + 1];
110 // ’Ê�í‚̃Aƒ‹ƒtƒ@’l•â�³
111 int tunetbl[256];
112 int tunetblR[256];
113 int tunetblG[256];
114 int tunetblB[256];
115 // ‰e•¶Žš—p‚̃Aƒ‹ƒtƒ@’l•â�³
116 int tunetblS[256];
117 int tunetblRS[256];
118 int tunetblGS[256];
119 int tunetblBS[256];
120 public:
121 static const int BASE;
122 public:
123 CAlphaBlend() { }
124 ~CAlphaBlend() {}
125 void init();
126 BYTE doAB(BYTE fg, BYTE bg, int alpha);
127 void gettunetbl(int paramalpha, bool lcd, const int * &tblR, const int * &tblG, const int * &tblB) const;
128 inline int conv1(BYTE n) {
129 return tbl1[n];
131 inline BYTE conv2(int n) {
132 return tbl2[n / (BASE * BASE / (sizeof tbl2 - 1))];
134 private:
135 inline int convalpha(int alpha) {
136 return alphatbl[alpha];
138 inline BYTE rconv1(int n);
140 const int CAlphaBlend::BASE = 0x4000;
142 static CAlphaBlend s_AlphaBlendTable;
144 void CAlphaBlend::gettunetbl(int paramalpha, bool lcd, const int * &tblR, const int * &tblG, const int * &tblB) const
146 if (paramalpha == 1) {
147 if (lcd) {
148 tblR = tunetblR;
149 tblG = tunetblG;
150 tblB = tunetblB;
151 } else {
152 tblR = tblG = tblB = tunetbl;
154 } else {
155 if (lcd) {
156 tblR = tunetblRS;
157 tblG = tunetblGS;
158 tblB = tunetblBS;
159 } else {
160 tblR = tblG = tblB = tunetblS;
165 void CAlphaBlend::init()
167 const CGdippSettings* pSettings = CGdippSettings::GetInstance();
168 const float gamma = pSettings->GammaValue();
169 const float weight = pSettings->RenderWeight();
170 const float contrast = pSettings->Contrast();
171 const int mode = pSettings->GammaMode();
173 int i;
174 float temp, alpha;
176 for (i = 0; i < 256; ++i) {
177 temp = pow((1.0f / 255.0f) * i, 1.0f / weight);
179 if (temp < 0.5f) {
180 alpha = pow(temp * 2, contrast) / 2.0f;
181 } else {
182 alpha = 1.0f - pow((1.0f - temp) * 2, contrast) / 2.0f;
184 alphatbl[i] = (int)(alpha * BASE);
186 if (mode < 0) {
187 temp = (1.0f / 255.0f) * i;
188 } else {
189 if (mode == 1) {
190 if (i <= 10) {
191 temp = (float)i / (12.92f * 255.0f);
192 } else {
193 temp = pow(((1.0f / 255.0f) * i + 0.055f) / 1.055f, 2.4f);
195 } else if (mode == 2) {
196 if (i <= 10) {
197 temp = ((float)i / (12.92f * 255.0f) + (float)i / 255.0f) / 2;
198 } else {
199 temp = (pow(((1.0f / 255.0f) * i + 0.055f) / 1.055f, 2.4f) + (float)i / 255.0f) / 2;
201 } else {
202 temp = pow((1.0f / 255.0f) * i, gamma);
205 tbl1[i] = (int)(temp * BASE);
208 tbl1[i] = BASE;
210 for (i = 0; i <= sizeof tbl2 - 1; ++i) {
211 tbl2[i] = rconv1(i * (BASE / (sizeof tbl2 - 1)));
214 const int* table = pSettings->GetTuneTable();
215 const int* tableR = pSettings->GetTuneTableR();
216 const int* tableG = pSettings->GetTuneTableG();
217 const int* tableB = pSettings->GetTuneTableB();
218 const int* shadow = pSettings->GetShadowParams();
219 const int paramalpha = Max(shadow[2], 1);
221 for (i = 0; i < 256; ++i) {
222 tunetbl[i] = alphatbl[Bound(table[i], 0, 255)];
223 tunetblR[i] = alphatbl[Bound(tableR[i], 0, 255)];
224 tunetblG[i] = alphatbl[Bound(tableG[i], 0, 255)];
225 tunetblB[i] = alphatbl[Bound(tableB[i], 0, 255)];
226 tunetblS[i] = alphatbl[Bound(table[i] / paramalpha, 0, 255)];
227 tunetblRS[i] = alphatbl[Bound(tableR[i] / paramalpha, 0, 255)];
228 tunetblGS[i] = alphatbl[Bound(tableG[i] / paramalpha, 0, 255)];
229 tunetblBS[i] = alphatbl[Bound(tableB[i] / paramalpha, 0, 255)];
233 BYTE CAlphaBlend::rconv1(int n)
235 int pos = 0x80;
236 int i = pos >> 1;
237 while (i > 0) {
238 if (n >= tbl1[pos]) {
239 pos += i;
240 } else {
241 pos -= i;
243 i >>= 1;
245 if (n >= tbl1[pos]) {
246 ++pos;
248 return (BYTE)(pos - 1);
251 class CAlphaBlendColorOne
253 private:
254 BYTE fg;
255 int temp_fg;
256 const int *tunetbl;
257 BYTE bg0;
258 int alpha0;
259 BYTE c0;
260 public:
261 CAlphaBlendColorOne()
262 : fg(0), temp_fg(0), tunetbl(NULL), bg0(0), alpha0(0), c0(0) {}
263 void init(BYTE f, const int *tbl);
264 ~CAlphaBlendColorOne() {};
265 BYTE doAB(BYTE bg, int alpha);
268 FORCEINLINE void CAlphaBlendColorOne::init(BYTE f, const int *tbl)
270 fg = f;
271 temp_fg = s_AlphaBlendTable.conv1(fg);
272 tunetbl = tbl;
275 FORCEINLINE BYTE CAlphaBlendColorOne::doAB(BYTE bg, int alpha)
277 if (bg0 == bg && alpha0 == alpha) return c0;
278 int temp_alpha = tunetbl[alpha];
279 if (fg == bg || temp_alpha <= 0) return bg;
280 if (temp_alpha >= s_AlphaBlendTable.BASE) return fg;
281 int temp_bg = s_AlphaBlendTable.conv1(bg);
282 int temp = temp_bg * (s_AlphaBlendTable.BASE - temp_alpha) +
283 temp_fg * temp_alpha;
284 bg0 = bg;
285 alpha0 = alpha;
286 return c0 = s_AlphaBlendTable.conv2(temp);
289 class CAlphaBlendColor
291 private:
292 CAlphaBlendColorOne r;
293 CAlphaBlendColorOne g;
294 CAlphaBlendColorOne b;
295 public:
296 CAlphaBlendColor(COLORREF newColor, int paramalpha, bool lcd, bool gbr = false);
297 ~CAlphaBlendColor() { }
298 BYTE doABsub(BYTE fg, int temp_fg, BYTE bg, int temp_alpha) const;
299 COLORREF doAB(COLORREF baseColor, int alphaR, int alphaG, int alphaB);
300 COLORREF doAB(COLORREF baseColor, int alpha) {
301 return doAB(baseColor, alpha, alpha, alpha);
303 private:
304 CAlphaBlendColor() { }
307 FORCEINLINE CAlphaBlendColor::CAlphaBlendColor(COLORREF newColor, int paramalpha, bool lcd, bool gbr)
309 const int *tblR;
310 const int *tblG;
311 const int *tblB;
312 s_AlphaBlendTable.gettunetbl(paramalpha, lcd, tblR, tblG, tblB);
313 if (!gbr) {
314 r.init(GetRValue(newColor), tblR);
315 b.init(GetBValue(newColor), tblB);
316 } else {
317 r.init(GetBValue(newColor), tblB);
318 b.init(GetRValue(newColor), tblR);
320 g.init(GetGValue(newColor), tblG);
323 FORCEINLINE COLORREF CAlphaBlendColor::doAB(COLORREF baseColor, int alphaR, int alphaG, int alphaB)
325 return RGB( r.doAB(GetRValue(baseColor), alphaR),
326 g.doAB(GetGValue(baseColor), alphaG),
327 b.doAB(GetBValue(baseColor), alphaB));
330 FORCEINLINE BYTE CAlphaBlend::doAB(BYTE fg, BYTE bg, int alpha)
332 if (fg == bg || alpha <= 0) return bg;
333 if (alpha >= 255) return fg;
334 int temp_alpha = convalpha(alpha);
335 int temp_bg = conv1(bg);
336 int temp_fg = conv1(fg);
337 int temp = temp_bg * (BASE - temp_alpha) +
338 temp_fg * temp_alpha;
339 return conv2(temp);
342 FORCEINLINE BYTE DoAlphaBlend(BYTE fg, BYTE bg, int alpha)
344 return s_AlphaBlendTable.doAB(fg, bg, alpha);
347 // LCD(‰t�»)—p‚̃Aƒ‹ƒtƒ@ƒuƒŒƒ“ƒh(ƒTƒuƒsƒNƒZƒ‹ƒŒƒ“ƒ_ƒŠƒ“ƒO)
348 static FORCEINLINE
349 COLORREF AlphaBlendColorLCD(
350 COLORREF baseColor,
351 COLORREF newColor,
352 int alphaR, int alphaG, int alphaB,
353 const int* tableR, const int* tableG, const int* tableB,
354 const FreeTypeDrawInfo& ftdi)
356 const BYTE rs = GetRValue(baseColor);
357 const BYTE gs = GetGValue(baseColor);
358 const BYTE bs = GetBValue(baseColor);
359 BYTE rd = GetRValue(newColor);
360 BYTE gd = GetGValue(newColor);
361 BYTE bd = GetBValue(newColor);
362 // ƒAƒ‹ƒtƒ@’l‚ð•â�³
363 alphaR = tableR[alphaR] / ftdi.params.alpha;
364 alphaG = tableG[alphaG] / ftdi.params.alpha;
365 alphaB = tableB[alphaB] / ftdi.params.alpha;
366 // rd = (((rd - rs) * alphaR) / 255) + rs;
367 // gd = (((gd - gs) * alphaG) / 255) + gs;
368 // bd = (((bd - bs) * alphaB) / 255) + bs;
369 rd = DoAlphaBlend(rd, rs, alphaR);
370 gd = DoAlphaBlend(gd, gs, alphaG);
371 bd = DoAlphaBlend(bd, bs, alphaB);
372 return RGB(rd, gd, bd);
375 // ƒAƒ‹ƒtƒ@ƒuƒŒƒ“ƒh(256ŠK’²)
376 static FORCEINLINE
377 COLORREF AlphaBlendColor(
378 COLORREF baseColor,
379 COLORREF newColor,
380 int alpha, const int* table,
381 const FreeTypeDrawInfo& ftdi)
383 const BYTE rs = GetRValue(baseColor);
384 const BYTE gs = GetGValue(baseColor);
385 const BYTE bs = GetBValue(baseColor);
386 BYTE rd = GetRValue(newColor);
387 BYTE gd = GetGValue(newColor);
388 BYTE bd = GetBValue(newColor);
389 // ƒAƒ‹ƒtƒ@’l‚ð•â�³
390 alpha = table[alpha] / ftdi.params.alpha;
391 // rd = (rs * (255 - alpha) + rd * alpha) / 255;
392 // gd = (gs * (255 - alpha) + gd * alpha) / 255;
393 // bd = (bs * (255 - alpha) + bd * alpha) / 255;
395 // rd = (((rd - rs) * alpha) / 255) + rs;
396 // gd = (((gd - gs) * alpha) / 255) + gs;
397 // bd = (((bd - bs) * alpha) / 255) + bs;
398 rd = DoAlphaBlend(rd, rs, alpha);
399 gd = DoAlphaBlend(gd, gs, alpha);
400 bd = DoAlphaBlend(bd, bs, alpha);
401 return RGB(rd, gd, bd);
404 // 2ŠK’²
405 static void FreeTypeDrawBitmapPixelModeMono(
406 CBitmapCache& cache,
407 const FT_Bitmap *bitmap,
408 int x, int y,
409 const FreeTypeDrawInfo& ftdi)
411 int i, j;
412 int dx, dy; // display
413 FT_Bytes p;
415 if(bitmap->pixel_mode != FT_PIXEL_MODE_MONO){
416 return;
419 const COLORREF color = RGB2DIB(ftdi.Color());
421 const SIZE cachebufsize = cache.Size();
422 DWORD * const cachebufp = (DWORD *)cache.GetPixels();
423 DWORD * cachebufrowp;
425 int left, top, width, height;
426 if (x < 0) {
427 left = -x;
428 x = 0;
429 } else {
430 left = 0;
432 width = Min(bitmap->width, (int)(cachebufsize.cx - x));
433 top = 0;
434 height = bitmap->rows;
436 for(j = top, dy = y; j < height; ++j, ++dy){
437 if ((unsigned int)dy >= (unsigned int)cachebufsize.cy) continue;
438 p = bitmap->pitch < 0 ?
439 &bitmap->buffer[(-bitmap->pitch * bitmap->rows) - bitmap->pitch * j] : // up-flow
440 &bitmap->buffer[bitmap->pitch * j]; // down-flow
441 cachebufrowp = &cachebufp[dy * cachebufsize.cx];
442 for(i = left, dx = x; i < width; ++i, ++dx){
443 if((p[i / 8] & (1 << (7 - (i % 8)))) != 0){
444 cachebufrowp[dx] = color;
450 // LCD(‰t�»)—p•`‰æ(ƒTƒuƒsƒNƒZƒ‹ƒŒƒ“ƒ_ƒŠƒ“ƒO)
451 // RGB�‡(‚Ì‚Í‚¸)
452 static void FreeTypeDrawBitmapPixelModeLCD(
453 CBitmapCache& cache,
454 const FT_Bitmap *bitmap,
455 int x, int y,
456 const FreeTypeDrawInfo& ftdi)
458 int i, j;
459 int dx, dy; // display
460 COLORREF c;
461 FT_Bytes p;
463 if(bitmap->pixel_mode != FT_PIXEL_MODE_LCD){
464 return;
467 const COLORREF color = ftdi.Color();
468 const int AAMode = ftdi.pfs->GetAntiAliasMode();
470 const SIZE cachebufsize = cache.Size();
471 DWORD * const cachebufp = (DWORD *)cache.GetPixels();
472 DWORD * cachebufrowp;
474 // LCD‚Í3ƒTƒuƒsƒNƒZƒ‹•ª‚ ‚é
475 int left, top, width, height;
476 if (x < 0) {
477 left = -x * 3;
478 x = 0;
479 } else {
480 left = 0;
482 width = Min(bitmap->width, (int)(cachebufsize.cx - x) * 3);
483 top = 0;
484 height = bitmap->rows;
486 CAlphaBlendColor ab(color, ftdi.params.alpha, true, true);
488 COLORREF backColor;
489 int alphaR, alphaG, alphaB;
491 for(j = 0, dy = y; j < height; ++j, ++dy){
492 if ((unsigned int)dy >= (unsigned int)cachebufsize.cy) continue;
494 p = bitmap->pitch < 0 ?
495 &bitmap->buffer[(-bitmap->pitch * bitmap->rows) - bitmap->pitch * j] : // up-flow
496 &bitmap->buffer[bitmap->pitch * j]; // down-flow
498 cachebufrowp = &cachebufp[dy * cachebufsize.cx];
500 for(i = left, dx = x; i < width; i += 3, ++dx){
501 if(AAMode == 2 || AAMode == 4){
502 // ‚±‚ê‚ÍRGB‚Ì�‡‚ɃTƒuƒsƒNƒZƒ‹‚ª‚ ‚éƒfƒBƒXƒvƒŒƒC—p
503 alphaR = p[i + 0];
504 alphaG = p[i + 1];
505 alphaB = p[i + 2];
506 }else{
507 // BGR
508 alphaR = p[i + 2];
509 alphaG = p[i + 1];
510 alphaB = p[i + 0];
512 backColor = cachebufrowp[dx];
513 c = ab.doAB(backColor, alphaB, alphaG, alphaR);
514 cachebufrowp[dx] = c;
519 // ƒOƒŠƒtƒrƒbƒgƒ}ƒbƒv‚̃Œƒ“ƒ_ƒŠƒ“ƒO
520 static void FreeTypeDrawBitmap(
521 CBitmapCache& cache,
522 const FT_Bitmap *bitmap,
523 int x, int y,
524 const FreeTypeDrawInfo& ftdi)
526 int i, j;
527 int dx, dy; // display
528 COLORREF c;
529 FT_Bytes p;
531 if(bitmap->pixel_mode != FT_PIXEL_MODE_GRAY){
532 // ‚±‚ÌŠÖ�”Ž©‘Ì‚ÍFT_PIXEL_MODE_GRAY‚ɂ̂ݑΉž‚µ‘¼‚ɈÏ�÷‚·‚é
533 switch(bitmap->pixel_mode){
534 case FT_PIXEL_MODE_MONO:
535 FreeTypeDrawBitmapPixelModeMono(
536 cache, bitmap, x, y, ftdi);
537 break;
538 case FT_PIXEL_MODE_LCD:
539 FreeTypeDrawBitmapPixelModeLCD(
540 cache, bitmap, x, y, ftdi);
541 break;
542 default:
543 return; // –¢‘Ήž
545 return;
548 const COLORREF color = ftdi.Color();
549 const SIZE cachebufsize = cache.Size();
550 DWORD * const cachebufp = (DWORD *)cache.GetPixels();
551 DWORD * cachebufrowp;
553 int left, top, width, height;
554 if (x < 0) {
555 left = -x;
556 x = 0;
557 } else {
558 left = 0;
560 width = Min(bitmap->width, (int)(cachebufsize.cx - x));
561 top = 0;
562 height = bitmap->rows;
564 CAlphaBlendColor ab(color, ftdi.params.alpha, false, true);
566 COLORREF backColor;
567 int alpha;
569 for(j = top, dy = y; j < height; ++j, ++dy){
570 if ((unsigned int)dy >= (unsigned int)cachebufsize.cy) continue;
571 p = bitmap->pitch < 0 ?
572 &bitmap->buffer[(-bitmap->pitch * bitmap->rows) - bitmap->pitch * j] : // up-flow
573 &bitmap->buffer[bitmap->pitch * j]; // down-flow
574 cachebufrowp = &cachebufp[dy * cachebufsize.cx];
575 for(i = left, dx = x; i < width; ++i, ++dx){
576 alpha = p[i];
577 backColor = cachebufrowp[dx];
578 c = ab.doAB(backColor, alpha);
579 cachebufrowp[dx] = c;
584 // �c�‘‚«—p‚̃Œƒ“ƒ_ƒŠƒ“ƒO(ƒRƒsƒyŽè”²‚«)
585 // 2ŠK’²
586 static void FreeTypeDrawBitmapPixelModeMonoV(
587 CBitmapCache& cache,
588 const FT_Bitmap *bitmap,
589 const int x, const int y,
590 const FreeTypeDrawInfo& ftdi)
592 int i, j;
593 int dx, dy; // display
594 FT_Bytes p;
596 if(bitmap->pixel_mode != FT_PIXEL_MODE_MONO){
597 return;
600 const COLORREF color = ftdi.Color();
602 const int width = bitmap->width;
603 const int height = bitmap->rows;
605 for(j = 0, dy = x; j < height; ++j, ++dy){
606 p = bitmap->pitch < 0 ?
607 &bitmap->buffer[(-bitmap->pitch * bitmap->rows) - bitmap->pitch * j] : // up-flow
608 &bitmap->buffer[bitmap->pitch * j]; // down-flow
609 for(i = 0, dx = y+width; i < width; ++i, --dx){
610 if((p[i / 8] & (1 << (7 - (i % 8)))) != 0){
611 if (cache.GetPixel(dx, dy) != CLR_INVALID) { // dx dy ƒGƒ‰�[ƒ`ƒFƒbƒN
612 cache.SetCurrentPixel(color);
619 // LCD(‰t�»)—p•`‰æ(ƒTƒuƒsƒNƒZƒ‹ƒŒƒ“ƒ_ƒŠƒ“ƒO)
620 // RGB�‡(‚Ì‚Í‚¸)
621 static void FreeTypeDrawBitmapPixelModeLCDV(
622 CBitmapCache& cache,
623 const FT_Bitmap *bitmap,
624 const int x, const int y,
625 const FreeTypeDrawInfo& ftdi)
627 int i, j;
628 int dx, dy; // display
629 COLORREF c;
630 FT_Bytes p;
632 if(bitmap->pixel_mode != FT_PIXEL_MODE_LCD_V){
633 return;
636 const COLORREF color = ftdi.Color();
637 const int AAMode = ftdi.pfs->GetAntiAliasMode();
639 // LCD‚Í3ƒTƒuƒsƒNƒZƒ‹•ª‚ ‚é
640 const int width = bitmap->width;
641 const int height = bitmap->rows;
642 const int pitch = bitmap->pitch;
643 const int pitchabs = pitch < 0 ? -pitch : pitch;
645 CAlphaBlendColor ab(color, ftdi.params.alpha, true);
647 for(j = 0, dy = x; j < height; j += 3, ++dy){
648 p = pitch < 0 ?
649 &bitmap->buffer[(pitchabs * bitmap->rows) + pitchabs * j] : // up-flow
650 &bitmap->buffer[pitchabs * j]; // down-flow
652 int alphaR, alphaG, alphaB;
653 for(i = 0, dx = y+width; i < width; ++i, --dx){
654 const COLORREF backColor = cache.GetPixel(dy, dx);
656 if (backColor == color || backColor == CLR_INVALID) continue;
657 if(AAMode == 2 || AAMode == 4){
658 // ‚±‚ê‚ÍRGB‚Ì�‡‚ɃTƒuƒsƒNƒZƒ‹‚ª‚ ‚éƒfƒBƒXƒvƒŒƒC—p
659 alphaR = p[i + 0];
660 alphaG = p[i + pitch];
661 alphaB = p[i + pitch * 2];
662 }else{
663 // BGR
664 alphaR = p[i + pitch * 2];
665 alphaG = p[i + pitch];
666 alphaB = p[i + 0];
668 c = ab.doAB(backColor, alphaR, alphaG, alphaB);
669 cache.SetCurrentPixel(c);
672 if (i >= width)
673 continue;
677 static void FreeTypeDrawBitmapV(
678 CBitmapCache& cache,
679 const FT_Bitmap *bitmap,
680 const int x, const int y,
681 const FreeTypeDrawInfo& ftdi)
683 int i, j;
684 int dx, dy; // display
685 int width, height;
686 COLORREF c;
687 FT_Bytes p;
689 if(bitmap->pixel_mode != FT_PIXEL_MODE_GRAY){
690 // ‚±‚ÌŠÖ�”Ž©‘Ì‚ÍFT_PIXEL_MODE_GRAY‚ɂ̂ݑΉž‚µ‘¼‚ɈÏ�÷‚·‚é
691 switch(bitmap->pixel_mode){
692 case FT_PIXEL_MODE_MONO:
693 FreeTypeDrawBitmapPixelModeMonoV(
694 cache, bitmap, x, y, ftdi);
695 break;
696 case FT_PIXEL_MODE_LCD_V:
697 FreeTypeDrawBitmapPixelModeLCDV(
698 cache, bitmap, x, y, ftdi);
699 break;
700 default:
701 return; // –¢‘Ήž
703 return;
706 const COLORREF color = ftdi.Color();
707 const CGdippSettings* pSettings = CGdippSettings::GetInstance();
708 const int* table = pSettings->GetTuneTable();
709 width = bitmap->width;
710 height = bitmap->rows;
712 CAlphaBlendColor ab(color, ftdi.params.alpha, false);
714 for(j = 0, dy = x; j < height; ++j, ++dy){
715 p = bitmap->pitch < 0 ?
716 &bitmap->buffer[(-bitmap->pitch * bitmap->rows) - bitmap->pitch * j] : // up-flow
717 &bitmap->buffer[bitmap->pitch * j]; // down-flow
718 for(i = 0, dx = y+width; i < width; ++i, --dx){
719 const COLORREF backColor = cache.GetPixel(dy, dx);
720 if (backColor == color || backColor == CLR_INVALID) continue;
721 c = ab.doAB(backColor, p[i]);
722 cache.SetPixelV(dy, dx, c);
727 class CGGOGlyphLoader
729 private:
730 FT_Library m_lib;
731 const FT_Glyph_Class *m_clazz;
732 BYTE bgtbl[0x41];
733 static int CALLBACK EnumFontFamProc(const LOGFONT* lplf, const TEXTMETRIC* lptm, DWORD FontType, LPARAM lParam);
734 public:
735 CGGOGlyphLoader() : m_lib(NULL), m_clazz(NULL) {}
736 ~CGGOGlyphLoader() {}
737 bool init(FT_Library freetype_library);
738 FT_Library getlib() { return m_lib; }
739 const FT_Glyph_Class * getclazz() { return m_clazz; }
740 BYTE convbgpixel(BYTE val) { return bgtbl[val]; }
742 static CGGOGlyphLoader s_GGOGlyphLoader;
744 int CALLBACK CGGOGlyphLoader::EnumFontFamProc(const LOGFONT* lplf, const TEXTMETRIC* lptm, DWORD FontType, LPARAM lParam)
746 CGGOGlyphLoader* pThis = reinterpret_cast<CGGOGlyphLoader*>(lParam);
747 if (FontType != TRUETYPE_FONTTYPE /*|| lplf->lfCharSet == SYMBOL_CHARSET*/) {
748 return TRUE;
751 FreeTypeSysFontData* pFont = FreeTypeSysFontData::CreateInstance(lplf->lfFaceName, 0, false);
752 if (!pFont) {
753 return TRUE;
756 const FT_Glyph_Class *clazz = NULL;
757 FT_Face face = pFont->GetFace();
758 FT_Error err = FT_Set_Pixel_Sizes(face, 0, 12);
759 if (!err) {
760 err = FT_Load_Char(face, lptm->tmDefaultChar, FT_LOAD_DEFAULT);
761 if (!err) {
762 FT_Glyph glyph;
763 err = FT_Get_Glyph(face->glyph, &glyph);
764 if (!err) {
765 if (glyph->format == FT_GLYPH_FORMAT_OUTLINE) {
766 clazz = glyph->clazz;
768 FT_Done_Glyph(glyph);
773 FT_Done_Face(face);
775 if (clazz) {
776 pThis->m_clazz = clazz;
777 //—ñ‹“’†Ž~
778 return FALSE;
780 return TRUE;
783 bool
784 CGGOGlyphLoader::init(FT_Library freetype_library)
786 if (m_lib) {
787 return true;
790 if (!freetype_library) {
791 return false;
794 for (BYTE val = 0; val <= 0x40; ++val) {
795 BYTE t = (BYTE)(((DWORD)val * 256) / 65);
796 bgtbl[val] = t + (t >> 6);
799 m_lib = freetype_library;
800 m_clazz = NULL;
802 //‘O‚Ì•û–@‚¾‚Æ�Aarial.ttf‚ª–³‚¢‚Æ‚Ü‚¸‚»‚¤‚È‚Ì‚Å
803 //“K“–‚ÉŽg‚¦‚éƒAƒEƒgƒ‰ƒCƒ“ƒtƒHƒ“ƒg‚ð’T‚·
804 HDC hdc = CreateCompatibleDC(NULL);
805 EnumFontFamilies(hdc, NULL, EnumFontFamProc, reinterpret_cast<LPARAM>(this));
806 DeleteDC(hdc);
808 if (m_clazz != NULL) {
809 return true;
811 m_lib = NULL;
812 return false;
815 class CGGOOutlineGlyph
817 private:
818 FT_OutlineGlyph m_ptr;
819 static FT_F26Dot6 toF26Dot6(const FIXED& fx) {
820 return *(LONG *)(&fx) >> 10;
822 static FT_Fixed toFixed(const short n) {
823 return (FT_Fixed)n << 16;
825 static char getTag(char tag, const FT_Vector& point) {
826 if ((point.x & 0x0f) != 0) {
827 tag |= FT_CURVE_TAG_TOUCH_X;
829 if ((point.y & 0x0f) != 0) {
830 tag |= FT_CURVE_TAG_TOUCH_Y;
832 return tag;
834 public:
835 CGGOOutlineGlyph() : m_ptr(NULL) { _ASSERTE(s_GGOGlyphLoader.getlib()); }
836 ~CGGOOutlineGlyph() { done(); };
837 bool init(DWORD bufsize, PVOID bufp, const GLYPHMETRICS& gm);
838 void done();
839 operator FT_Glyph () { return (FT_Glyph)m_ptr; }
842 void
843 CGGOOutlineGlyph::done()
845 if (m_ptr) {
846 free(m_ptr->outline.points);
847 free(m_ptr->outline.tags);
848 free(m_ptr->outline.contours);
850 free(m_ptr);
851 m_ptr = NULL;
854 bool
855 CGGOOutlineGlyph::init(DWORD bufsize, PVOID bufp, const GLYPHMETRICS& gm)
857 done();
858 m_ptr = (FT_OutlineGlyph)calloc(1, sizeof *m_ptr);
859 if (!m_ptr) {
860 return false;
863 FT_GlyphRec& root = m_ptr->root;
864 FT_Outline& outline = m_ptr->outline;
866 root.library = s_GGOGlyphLoader.getlib();
867 root.clazz = s_GGOGlyphLoader.getclazz();
868 root.format = FT_GLYPH_FORMAT_OUTLINE;
869 root.advance.x = toFixed(gm.gmCellIncX);
870 root.advance.y = toFixed(gm.gmCellIncY);
872 outline.n_contours = 0;
873 outline.n_points = 0;
874 outline.flags = 0; //FT_OUTLINE_HIGH_PRECISION;
876 LPTTPOLYGONHEADER ttphp = (LPTTPOLYGONHEADER)bufp;
877 LPTTPOLYGONHEADER ttphpend = (LPTTPOLYGONHEADER)((PBYTE)ttphp + bufsize);
879 while (ttphp < ttphpend) {
880 LPTTPOLYCURVE ttpcp = (LPTTPOLYCURVE)(ttphp + 1);
881 LPTTPOLYCURVE ttpcpend = (LPTTPOLYCURVE)((PBYTE)ttphp + ttphp->cb);
882 if ((PVOID)ttpcpend > (PVOID)ttphpend) {
883 break;
885 ++outline.n_points;
886 ++outline.n_contours;
887 while (ttpcp < ttpcpend) {
888 LPPOINTFX pfxp = &ttpcp->apfx[0];
889 outline.n_points += ttpcp->cpfx;
890 ttpcp = (LPTTPOLYCURVE)(pfxp + ttpcp->cpfx);
892 ttphp = (LPTTPOLYGONHEADER)ttpcp;
895 if (ttphp != ttphpend) {
896 return false;
898 outline.points = (FT_Vector *)calloc(outline.n_points, sizeof *outline.points);
899 outline.tags = (char *)calloc(outline.n_points, sizeof *outline.tags);
900 outline.contours = (short *)calloc(outline.n_contours, sizeof *outline.contours);
901 if (!outline.points || !outline.tags || !outline.contours) {
902 done();
903 return false;
906 short *cp = outline.contours;
907 short ppos = 0;
909 ttphp = (LPTTPOLYGONHEADER)bufp;
910 while (ttphp < ttphpend) {
911 LPTTPOLYCURVE ttpcp = (LPTTPOLYCURVE)(ttphp + 1);
912 LPTTPOLYCURVE ttpcpend = (LPTTPOLYCURVE)((PBYTE)ttphp + ttphp->cb);
914 LPPOINTFX pfxp0 = &ttpcp->apfx[0];
915 while (ttpcp < ttpcpend) {
916 LPPOINTFX pfxp = &ttpcp->apfx[0];
917 pfxp0 = pfxp + (ttpcp->cpfx - 1);
918 ttpcp = (LPTTPOLYCURVE)(pfxp + ttpcp->cpfx);
920 ttpcp = (LPTTPOLYCURVE)(ttphp + 1);
922 if (pfxp0->x.value != ttphp->pfxStart.x.value || pfxp0->x.fract != ttphp->pfxStart.x.fract ||
923 pfxp0->y.value != ttphp->pfxStart.y.value || pfxp0->y.fract != ttphp->pfxStart.y.fract) {
924 outline.points[ppos].x = toF26Dot6(ttphp->pfxStart.x);
925 outline.points[ppos].y = toF26Dot6(ttphp->pfxStart.y);
926 outline.tags[ppos] = getTag(FT_CURVE_TAG_ON, outline.points[ppos]);
927 ++ppos;
929 while (ttpcp < ttpcpend) {
930 char tag;
931 switch (ttpcp->wType) {
932 case TT_PRIM_LINE:
933 tag = FT_CURVE_TAG_ON;
934 break;
935 case TT_PRIM_QSPLINE:
936 tag = FT_CURVE_TAG_CONIC;
937 break;
938 case TT_PRIM_CSPLINE:
939 tag = FT_CURVE_TAG_CONIC;
940 break;
941 default:
942 tag = 0;
945 LPPOINTFX pfxp = &ttpcp->apfx[0];
946 for (WORD cnt = 0; cnt < ttpcp->cpfx; ++cnt) {
947 outline.points[ppos].x = toF26Dot6(pfxp->x);
948 outline.points[ppos].y = toF26Dot6(pfxp->y);
949 outline.tags[ppos] = tag;
950 ++ppos;
951 ++pfxp;
953 outline.tags[ppos - 1] = getTag(FT_CURVE_TAG_ON, outline.points[ppos - 1]);
954 ttpcp = (LPTTPOLYCURVE)pfxp;
956 *cp++ = ppos - 1;
957 ttphp = (LPTTPOLYGONHEADER)ttpcp;
959 outline.n_points = ppos;
960 return true;
963 template<typename T>
964 class CTempMem
966 private:
967 char m_localbuf[0x0f80];
968 DWORD m_size;
969 T m_ptr;
970 public:
971 CTempMem() : m_size(sizeof m_localbuf), m_ptr((T)m_localbuf) {
973 ~CTempMem() {
974 done();
976 T init(DWORD size) {
977 done();
978 if (m_size > size) {
979 m_size = size;
980 m_ptr = (T)malloc(m_size);
982 return m_ptr;
984 void done() {
985 if (m_ptr != (T)m_localbuf) {
986 free(m_ptr);
988 m_size = sizeof m_localbuf;
989 m_ptr = (T)m_localbuf;
991 operator T () { return m_ptr; }
992 bool operator ! () { return !m_ptr; }
993 DWORD getsize() { return m_size; }
996 BOOL FreeTypeSetDrawSettings(FreeTypeDrawInfo& FTInfo, FTC_FaceID face_id);
998 BOOL FreeTypePrepare(FreeTypeDrawInfo& FTInfo)
1000 FT_Face& freetype_face = FTInfo.freetype_face;
1001 FT_Render_Mode& render_mode = FTInfo.render_mode;
1002 FTC_ImageTypeRec& font_type = FTInfo.font_type;
1003 FreeTypeFontInfo*& pfi = FTInfo.pfi;
1004 const CFontSettings*& pfs = FTInfo.pfs;
1005 FreeTypeFontCache*& pftCache = FTInfo.pftCache;
1007 FTC_FaceID face_id = NULL;
1008 int height = 0;
1010 const LOGFONTW& lf = FTInfo.LogFont();
1011 if (lf.lfFaceName == NULL)
1012 return FALSE;
1014 render_mode = FT_RENDER_MODE_NORMAL;
1015 if (FTInfo.params.alpha < 1)
1016 FTInfo.params.alpha = 1;
1018 if (! (pfi = g_pFTEngine->FindFont(lf.lfFaceName, lf.lfWeight, !!lf.lfItalic)) )
1019 return FALSE;
1021 face_id = (FTC_FaceID)pfi->GetId();
1022 FTInfo.face_id_list[0] = face_id;
1023 FTInfo.face_id_list_num = 1;
1025 if(FTC_Manager_LookupFace(cache_man, face_id, &freetype_face)) {
1026 //Assert(false);
1027 return FALSE;
1030 FTInfo.cmap_list[0] = FT_Get_Charmap_Index(freetype_face->charmap);
1032 if (freetype_face->charmap->encoding != FT_ENCODING_MS_SYMBOL) {
1033 CFontFaceNamesEnumerator fn(lf.lfFaceName);
1034 for (; !fn.atend(); fn.next()) {
1035 FreeTypeFontInfo* pfitemp = g_pFTEngine->FindFont(fn, lf.lfWeight, !!lf.lfItalic);
1036 if (!pfitemp) {
1037 Assert(false);
1038 continue;
1041 FTInfo.face_id_list[FTInfo.face_id_list_num] = (FTC_FaceID)pfitemp->GetId();
1042 FTInfo.cmap_list[FTInfo.face_id_list_num] = -1;
1043 ++FTInfo.face_id_list_num;
1047 const CGdippSettings* pSettings = CGdippSettings::GetInstance();
1048 pfs = &pfi->GetFontSettings();
1049 switch (pSettings->FontLoader()) {
1050 case SETTING_FONTLOADER_FREETYPE:
1052 FTC_ScalerRec scaler = { 0 };
1053 scaler.face_id = face_id;
1054 // scaler.width = lf.lfWidth;
1055 TT_OS2 *os2_table = (TT_OS2 *)FT_Get_Sfnt_Table(freetype_face, ft_sfnt_os2);
1056 scaler.width = FT_MulDiv(lf.lfWidth, freetype_face->units_per_EM, os2_table->xAvgCharWidth);
1058 if(lf.lfHeight > 0){
1059 // ƒZƒ‹�‚‚³
1060 scaler.height = FT_MulDiv(lf.lfHeight, freetype_face->units_per_EM, freetype_face->height);
1062 else{
1063 // •¶Žš�‚‚³
1064 scaler.height = -lf.lfHeight;
1066 scaler.pixel = 1;
1067 scaler.x_res = 0;
1068 scaler.y_res = 0;
1070 FT_Size font_size;
1071 if(FTC_Manager_LookupSize(cache_man, &scaler, &font_size))
1072 return FALSE;
1073 height = scaler.height;
1074 break;
1076 case SETTING_FONTLOADER_WIN32:
1078 OUTLINETEXTMETRIC otm;
1079 if (GetOutlineTextMetrics(FTInfo.hdc, sizeof otm, &otm) != sizeof otm) {
1080 return FALSE;
1082 height = lf.lfHeight;
1084 break;
1085 default:
1086 return FALSE;
1089 pftCache = pfi->GetCache(height, lf);
1090 if(!pftCache)
1091 return FALSE;
1093 return FreeTypeSetDrawSettings(FTInfo, face_id);
1096 BOOL FreeTypeSetDrawSettings(FreeTypeDrawInfo& FTInfo, FTC_FaceID face_id)
1098 FT_Face& freetype_face = FTInfo.freetype_face;
1099 FT_Render_Mode& render_mode = FTInfo.render_mode;
1100 FTC_ImageTypeRec& font_type = FTInfo.font_type;
1102 FreeTypeFontInfo* pfi = g_pFTEngine->FindFont((int)face_id);
1103 if (!pfi)
1104 return FALSE;
1106 const CFontSettings* pfs = &pfi->GetFontSettings();
1107 if (!pfs)
1108 return FALSE;
1110 const CGdippSettings* pSettings = CGdippSettings::GetInstance();
1112 /*FT_Size_RequestRec size_request;
1113 size_request.width = lf.lfWidth;
1114 size_request.horiResolution = 0;
1115 size_request.vertResolution = 0;
1116 if(lf.lfHeight > 0){
1117 // ƒZƒ‹�‚‚³
1118 size_request.type = FT_SIZE_REQUEST_TYPE_CELL;
1119 size_request.height = lf.lfHeight * 64;
1121 else{
1122 // •¶Žš�‚‚³
1123 size_request.type = FT_SIZE_REQUEST_TYPE_NOMINAL;
1124 size_request.height = (-lf.lfHeight) * 64;
1126 if(FT_Request_Size(freetype_face, &size_request))
1127 goto Exit2;*/
1129 switch (pSettings->FontLoader()) {
1130 case SETTING_FONTLOADER_FREETYPE:
1131 // font_type‚ð�Ý’è
1132 font_type.face_id = face_id;
1133 font_type.width = freetype_face->size->metrics.x_ppem;
1134 font_type.height = freetype_face->size->metrics.y_ppem;
1136 /* ƒrƒbƒgƒ}ƒbƒv‚܂ŃLƒƒƒbƒVƒ…‚·‚é�ê�‡‚ÍFT_LOAD_RENDER | FT_LOAD_TARGET_*
1137 * ‚Æ‚·‚é�B‚½‚¾‚µ“r’†‚ÅTARGET‚ð•Ï�X‚µ‚½�ê�‡“™‚̓LƒƒƒbƒVƒ…‚ªŽ×–‚‚·‚é�B
1138 * ‚»‚¤‚¢‚¤Žž‚ÍFT_LOAD_DEFAULT‚É‚µ‚ÄFTC_ImageCache_LookupŒã‚É
1139 * FT_Glyph_To_Bitmap‚µ‚½‚Ù‚¤‚ª“s�‡‚ª‚¢‚¢‚ÆŽv‚¤�B
1141 // Bold‚Í‘¾‚è‹ï�‡‚Æ‚¢‚¤‚à‚Ì‚ª‚ ‚é‚Ì‚Å–{“–‚Í‚±‚ꂾ‚¯‚Å‚Í‘«‚è‚È‚¢‹C‚ª‚·‚é�B
1142 /*if(IsFontBold(lf) && !(freetype_face->style_flags & FT_STYLE_FLAG_BOLD) ||
1143 lf.lfItalic && !(freetype_face->style_flags & FT_STYLE_FLAG_ITALIC)){
1144 // ƒ{�[ƒ‹ƒh�AƒCƒ^ƒŠƒbƒN‚ÍŒã‚ŃŒƒ“ƒ_ƒŠƒ“ƒO‚·‚é
1145 // ‘½�­‘¬“x‚Í—ò‰»‚·‚邾‚낤‚¯‚ÇŽd•û‚È‚¢�B
1146 font_type.flags = FT_LOAD_NO_BITMAP;
1148 else{
1149 font_type.flags = FT_LOAD_RENDER | FT_LOAD_NO_BITMAP;
1151 break;
1152 case SETTING_FONTLOADER_WIN32:
1153 font_type.face_id = (FTC_FaceID) - 1;
1154 font_type.width = -1;
1155 font_type.height = -1;
1156 break;
1158 DEFAULT_UNREACHABLE;
1160 font_type.flags = FT_LOAD_NO_BITMAP | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
1162 // ƒqƒ“ƒeƒBƒ“ƒO
1163 switch (pfs->GetHintingMode()) {
1164 case 0:
1165 // ignore.
1166 break;
1167 case 1:
1168 font_type.flags |= FT_LOAD_NO_HINTING;
1169 break;
1170 case 2:
1171 font_type.flags |= FT_LOAD_FORCE_AUTOHINT;
1172 break;
1174 // ƒAƒ“ƒ`ƒGƒCƒŠƒAƒX
1175 if (FTInfo.IsMono()) {
1176 font_type.flags |= FT_LOAD_TARGET_MONO;
1177 render_mode = FT_RENDER_MODE_MONO;
1178 } else {
1179 switch (pfs->GetAntiAliasMode()) {
1180 case -1:
1181 font_type.flags |= FT_LOAD_TARGET_MONO;
1182 render_mode = FT_RENDER_MODE_MONO;
1183 break;
1184 case 0:
1185 font_type.flags |= FT_LOAD_TARGET_NORMAL;
1186 render_mode = FT_RENDER_MODE_NORMAL;
1187 break;
1188 case 1:
1189 font_type.flags |= FT_LOAD_TARGET_LIGHT;
1190 render_mode = FT_RENDER_MODE_LIGHT;
1191 break;
1192 case 2:
1193 case 3:
1194 font_type.flags |= FT_LOAD_TARGET_LCD;
1195 render_mode = FT_RENDER_MODE_LCD;
1196 break;
1197 case 4:
1198 case 5:
1199 font_type.flags |= FT_LOAD_TARGET_LIGHT;
1200 render_mode = FT_RENDER_MODE_LCD;
1201 break;
1205 FTInfo.useKerning = FALSE;
1206 if (pfs->GetKerning()) {
1207 switch (pSettings->FontLoader()) {
1208 case SETTING_FONTLOADER_FREETYPE:
1209 FTInfo.useKerning = !!FT_HAS_KERNING(freetype_face);
1210 break;
1211 case SETTING_FONTLOADER_WIN32:
1213 DWORD rc = GetFontLanguageInfo(FTInfo.hdc);
1214 if (rc != GCP_ERROR) {
1215 FTInfo.useKerning = !!(rc & GCP_USEKERNING);
1216 FTInfo.ggokerning.init(FTInfo.hdc);
1219 break;
1221 DEFAULT_UNREACHABLE;
1224 return TRUE;
1227 // �c‚É‚·‚é‚â‚‚Ítrue(ASCII‚Æ”¼ŠpƒJƒi‚Ífalse)
1228 inline bool IsVerticalChar(WCHAR wch){
1229 if(wch < 0x80)
1230 return false;
1231 if(0xFF61 <= wch && wch <= 0xFF9F)
1232 return false;
1233 // –{“–‚Í‚à‚Á‚Æ�^–Ê–Ú‚É‚â‚ç‚È‚¢‚Æ‚Ü‚¸‚¢‚ª�B
1234 return true;
1237 struct CGGOFont
1239 HDC m_hdc;
1240 HFONT m_hfont;
1241 HFONT m_hprevfont;
1242 CGGOFont(HDC hdc, const LOGFONT& olf) : m_hdc(hdc), m_hfont(NULL), m_hprevfont(NULL) {
1243 LOGFONT lf = olf;
1244 lf.lfWeight = FW_REGULAR;
1245 lf.lfItalic = FALSE;
1246 lf.lfStrikeOut = FALSE;
1247 m_hfont = CreateFontIndirect(&lf);
1249 ~CGGOFont() {
1250 if (m_hprevfont) {
1251 SelectFont(m_hdc, m_hprevfont);
1253 DeleteFont(m_hfont);
1255 void change() {
1256 m_hprevfont = SelectFont(m_hdc, m_hfont);
1258 void restore() {
1259 SelectFont(m_hdc, m_hprevfont);
1260 m_hprevfont = NULL;
1262 operator HFONT () { return m_hfont; }
1265 class ClpDx
1267 private:
1268 const INT *p;
1269 const INT step;
1270 public:
1271 ClpDx(const INT *lpDx, UINT etoOptions) : p(lpDx), step((etoOptions & ETO_PDY) ? 2 : 1) {
1273 ~ClpDx() {
1275 int get(int val) {
1276 int result;
1277 if (p) {
1278 result = *p;
1279 p += step;
1280 } else {
1281 result = val;
1283 return result;
1287 BOOL ForEachGetGlyph(FreeTypeDrawInfo& FTInfo, LPCTSTR lpString, int cbString, BOOL (CALLBACK *pfnCallback)(FreeTypeDrawInfo&, const WCHAR wch, const FT_BitmapGlyph))
1289 const CGdippSettings* pSettings = CGdippSettings::GetInstance();
1290 const FT_Face freetype_face = FTInfo.freetype_face;
1291 const FT_Bool useKerning = FTInfo.useKerning;
1292 FT_Render_Mode render_mode = FTInfo.render_mode;
1293 const int AAMode = FTInfo.pfs->GetAntiAliasMode();
1294 const LOGFONTW& lf = FTInfo.LogFont();
1295 FreeTypeFontCache* pftCache = FTInfo.pftCache;
1296 const bool bGlyphIndex = FTInfo.IsGlyphIndex();
1297 const bool bSizeOnly = FTInfo.IsSizeOnly();
1298 //const bool bOwnCache = !(FTInfo.font_type.flags & FT_LOAD_RENDER);
1299 const LPCTSTR lpStart = lpString;
1300 const LPCTSTR lpEnd = lpString + cbString;
1301 FT_UInt previous = 0;
1302 WCHAR previouswch = 0;
1303 const bool bVertical = lf.lfFaceName[0] == _T('@');
1304 const bool bLcdMode = render_mode == FT_RENDER_MODE_LCD;
1305 const bool bLightLcdMode = (AAMode == 4) || (AAMode == 5);
1306 ClpDx clpdx(FTInfo.lpDx, FTInfo.params.etoOptions);
1307 const bool bWidthGDI32 = pSettings->WidthMode() == SETTING_WIDTHMODE_GDI32;
1308 const int ggoformatbase = (FTInfo.font_type.flags & FT_LOAD_NO_HINTING) ? GGO_UNHINTED | GGO_NATIVE : GGO_NATIVE;
1310 if (!s_GGOGlyphLoader.init(freetype_library)) {
1311 return FALSE;
1314 for ( ; lpString < lpEnd; ++lpString){
1315 const WCHAR wch = *lpString;
1317 int gdi32x;
1318 if (!ORIG_GetCharWidth32W(FTInfo.hdc, wch, wch, &gdi32x)) return FALSE;
1320 FTInfo.font_type.face_id = FTInfo.face_id_list[0];
1322 FreeTypeCharData* chData = NULL;
1323 FT_BitmapGlyph glyph_bitmap = NULL;
1324 FT_Glyph copy_glyph = NULL;
1325 FT_UInt glyph_index = 0;
1327 //if (bSizeOnly || bOwnCache) {
1328 chData = bGlyphIndex
1329 ? pftCache->FindGlyphIndex(wch)
1330 : pftCache->FindChar(wch);
1333 if (chData) {
1334 if (bSizeOnly) {
1335 int cx = chData->GetWidth();
1336 FTInfo.x += (bWidthGDI32 ? gdi32x : cx) + FTInfo.params.charExtra;
1337 continue;
1339 glyph_bitmap = (FT_BitmapGlyph)chData->GetGlyph(render_mode);
1341 if (!glyph_bitmap) {
1342 FT_Glyph glyph = NULL;
1344 // �‡�¬‚âBMPŠO‚Ì•¶Žš‚ÍUniscribe‚ª�ˆ—�‚·‚é‚Ì‚Å‚±‚±‚Å�l—¶‚·‚é•K—v‚Í‚È‚¢�B
1345 bool f_glyph = false;
1346 GLYPHMETRICS gm;
1347 const MAT2 mat2 = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
1348 UINT ggoformat = ggoformatbase;
1349 CTempMem<PVOID> ggobuf;
1350 DWORD outlinesize = 0;
1352 switch (pSettings->FontLoader()) {
1353 case SETTING_FONTLOADER_FREETYPE:
1354 if (bGlyphIndex) {
1355 f_glyph = true;
1356 glyph_index = wch;
1357 } else if (wch) {
1358 for (int i = 0; i < FTInfo.face_id_list_num; ++i) {
1359 if (-1 == FTInfo.cmap_list[i]) {
1360 FT_Face temp_face;
1361 if(FTC_Manager_LookupFace(cache_man, FTInfo.face_id_list[i], &temp_face))
1362 break;
1363 FTInfo.cmap_list[i] = FT_Get_Charmap_Index(temp_face->charmap);
1366 glyph_index = FTC_CMapCache_Lookup(
1367 cmap_cache,
1368 FTInfo.face_id_list[i],
1369 FTInfo.cmap_list[i],
1370 wch);
1371 if (glyph_index != 0) {
1372 f_glyph = true;
1373 FTInfo.font_type.face_id = FTInfo.face_id_list[i];
1374 FreeTypeSetDrawSettings(FTInfo, FTInfo.font_type.face_id);
1375 break;
1379 break;
1380 case SETTING_FONTLOADER_WIN32:
1381 if (bGlyphIndex) {
1382 f_glyph = true;
1383 glyph_index = wch;
1384 ggoformat |= GGO_GLYPH_INDEX;
1385 } else {
1386 // ƒOƒŠƒtƒCƒ“ƒfƒbƒNƒXŽæ“¾
1387 WORD gi = 0;
1388 if (GetGlyphIndices(FTInfo.hdc, &wch, 1, &gi, GGI_MARK_NONEXISTING_GLYPHS) == 1) {
1389 if (gi != 0xffff) {
1390 glyph_index = gi;
1391 f_glyph = true;
1395 if (lpString == lpStart && FTInfo.font_type.flags & FT_LOAD_FORCE_AUTOHINT) {
1396 // FORCE_AUTOHINT ‚ÆŠÖŒW‚È‚¢•¶Žš‰»‚¯‘Î�ô
1397 GetGlyphOutline(FTInfo.hdc, 0, GGO_METRICS | GGO_GLYPH_INDEX | GGO_NATIVE | GGO_UNHINTED, &gm, 0, NULL, &mat2);
1399 outlinesize = GetGlyphOutline(FTInfo.hdc, wch, ggoformat, &gm, ggobuf.getsize(), ggobuf, &mat2);
1400 if (outlinesize == GDI_ERROR || outlinesize == 0) {
1401 glyph_index = 0;
1402 f_glyph = false;
1403 } else {
1404 // ƒOƒŠƒtƒCƒ“ƒfƒbƒNƒX‚ªŽæ‚ê‚È‚¢‚̂ɃAƒEƒgƒ‰ƒCƒ“‚ªŽæ‚ꂽ
1405 f_glyph = true;
1407 break;
1410 if (!f_glyph) {
1411 int cx = gdi32x;
1412 if (bSizeOnly) {
1413 FTInfo.x += cx;
1414 } else {
1415 if (wch && FTInfo.params.alpha == 1) {
1416 ORIG_ExtTextOutW(FTInfo.hdc, FTInfo.x, FTInfo.yTop, FTInfo.GetETO(), NULL, &wch, 1, NULL);
1418 if (lpString < lpEnd - 1) {
1419 FTInfo.x += clpdx.get(cx);
1420 } else {
1421 ABC abc = {0, gdi32x, 0};
1422 GetCharABCWidths(FTInfo.hdc, wch, wch, &abc);
1423 FTInfo.x += Max(clpdx.get(cx), abc.abcA + (int)abc.abcB);
1426 FTInfo.x += FTInfo.params.charExtra;
1427 continue;
1430 switch (pSettings->FontLoader()) {
1431 case SETTING_FONTLOADER_FREETYPE:
1432 // �c�‘‚«
1433 if(bVertical){
1434 glyph_index = ft2vert_get_gid(
1435 (struct ft2vert_st *)freetype_face->generic.data,
1436 glyph_index);
1439 // ƒJ�[ƒjƒ“ƒO
1440 if(useKerning){
1441 if(previous != 0 && glyph_index){
1442 FT_Vector delta;
1443 FT_Get_Kerning(freetype_face,
1444 previous, glyph_index,
1445 ft_kerning_default, &delta);
1446 FTInfo.x += FT_PosToInt(delta.x);
1448 previous = glyph_index;
1450 break;
1451 case SETTING_FONTLOADER_WIN32:
1452 if(useKerning && !bGlyphIndex){
1453 if (previouswch && wch) {
1454 FTInfo.x += FTInfo.ggokerning.get(previouswch, wch);
1456 previouswch = wch;
1458 break;
1461 // �c‰¡
1462 if(bVertical && IsVerticalChar(wch)){
1463 FTInfo.font_type.flags |= FT_LOAD_VERTICAL_LAYOUT;
1464 if(bLcdMode){
1465 if(!bLightLcdMode){
1466 FTInfo.font_type.flags &= ~FT_LOAD_TARGET_LCD;
1467 FTInfo.font_type.flags |= FT_LOAD_TARGET_LCD_V;
1469 render_mode = FT_RENDER_MODE_LCD_V;
1471 }else{
1472 FTInfo.font_type.flags &=~FT_LOAD_VERTICAL_LAYOUT;
1473 if(bLcdMode){
1474 if(!bLightLcdMode){
1475 FTInfo.font_type.flags &= ~FT_LOAD_TARGET_LCD_V;
1476 FTInfo.font_type.flags |= FT_LOAD_TARGET_LCD;
1478 render_mode = FT_RENDER_MODE_LCD;
1482 CGGOOutlineGlyph ggoog;
1483 switch (pSettings->FontLoader()) {
1484 case SETTING_FONTLOADER_FREETYPE:
1485 if(FTC_ImageCache_Lookup(
1486 image_cache,
1487 &FTInfo.font_type,
1488 glyph_index,
1489 &glyph,
1490 NULL)) {
1491 return FALSE;
1493 break;
1494 case SETTING_FONTLOADER_WIN32:
1495 if (outlinesize > ggobuf.getsize()) {
1496 if (!ggobuf.init(outlinesize)) {
1497 return FALSE;
1499 //ggofont.change();
1500 outlinesize = GetGlyphOutline(FTInfo.hdc, wch, ggoformat, &gm, ggobuf.getsize(), ggobuf, &mat2);
1501 //ggofont.restore();
1503 if (outlinesize > ggobuf.getsize()) {
1504 return FALSE;
1506 if (!ggoog.init(outlinesize, ggobuf, gm)) {
1507 return FALSE;
1509 glyph = ggoog;
1510 break;
1512 /* font_type.flags‚ÅFT_LOAD_RENDER‚ð‘I‘ð‚µ‚È‚¢‚Æ
1513 * ƒOƒŠƒtƒCƒ��[ƒW‚ðŽæ“¾‚µ‚Ä‚­‚é‚̂Ńrƒbƒgƒ}ƒbƒv‚É•ÏŠ·‚·‚é�B
1515 if(glyph->format == FT_GLYPH_FORMAT_BITMAP){
1516 glyph_bitmap = (FT_BitmapGlyph)glyph;
1518 else{
1519 //FT_Glyph copy_glyph = NULL;
1520 if(FT_Glyph_Copy(glyph, &copy_glyph))
1521 return FALSE;
1523 // ƒAƒEƒgƒ‰ƒCƒ“‚ð•ÏŒ`‚³‚¹‚é(�ã‹LƒTƒCƒg‚©‚ç)�B
1524 int str_h;
1525 int str_v;
1526 bool fbold = false;
1527 str_h = str_v = FTInfo.pfi->CalcNormalWeight();
1528 if (IsFontBold(lf) &&
1529 pSettings->FontLoader() == SETTING_FONTLOADER_FREETYPE &&
1530 !(freetype_face->style_flags & FT_STYLE_FLAG_BOLD)) {
1531 fbold = true;
1532 str_h = FTInfo.pfi->GetFTWeight();
1534 if((str_h || str_v) && New_FT_Outline_Embolden(
1535 &((FT_OutlineGlyph)copy_glyph)->outline,
1536 str_h, str_v))
1538 FT_Done_Glyph(copy_glyph);
1539 return FALSE; // •ÏŠ·Ž¸”s
1541 /*if (copy_glyph->advance.x) {
1542 FT_Matrix matrix;
1543 matrix.xx = (1 << 16) + (0x80000000 / (copy_glyph->advance.x >> 1));
1544 matrix.xy = 0;
1545 matrix.yx = 0;
1546 matrix.yy = 1 << 16;
1547 FT_Outline_Transform(
1548 &((FT_OutlineGlyph)copy_glyph)->outline,
1549 &matrix);
1551 if (fbold) {
1552 ((FT_BitmapGlyph)copy_glyph)->root.advance.x += 0x10000;
1554 if(lf.lfItalic &&
1555 pSettings->FontLoader() == SETTING_FONTLOADER_FREETYPE &&
1556 !(freetype_face->style_flags & FT_STYLE_FLAG_ITALIC)){
1557 // ŽÎ‘Ì
1558 FT_Matrix matrix;
1559 // •ÏŠ·
1560 FTInfo.pfi->CalcItalicSlant(matrix);
1561 FT_Outline_Transform(
1562 &((FT_OutlineGlyph)copy_glyph)->outline,
1563 &matrix);
1566 //// •¶Žš‚Ì•�‚ðGDI32‚É�‡‚킹‚é
1567 //FT_Fixed& ftx = (bVertical && IsVerticalChar(wch)) ?
1568 // copy_glyph->advance.y : copy_glyph->advance.x;
1569 //FT_Fixed targetx = gdi32x << 16;
1570 //if (ftx != targetx) {
1571 // if (ftx > targetx) {
1572 // // ‘å‚«‚¢‚Ȃ當Žš�k�¬ (�¬‚³‚­‚Ä‚àŠg‘å‚Í‚µ‚È‚¢)
1573 // FT_Matrix matrix = {FT_DivFix(targetx, ftx) , 0, 0, 1 << 16};
1574 // FT_Outline_Transform(&((FT_OutlineGlyph)copy_glyph)->outline, &matrix);
1576 // }
1577 // ftx = targetx; // ‘å‚«‚­‚Ä‚à�¬‚³‚­‚Ä‚àƒTƒCƒY‚ ‚킹
1580 /* FT_RENDER_MODE_NORMAL‚Å•�’Ê‚Ì(256ŠK’²)ƒAƒ“ƒ`ƒGƒCƒŠƒAƒX
1581 * FT_RENDER_MODE_LCD‚ʼnt�»—pƒAƒ“ƒ`ƒGƒCƒŠƒAƒX(ƒTƒuƒsƒNƒZƒ‹ƒŒƒ“ƒ_ƒŠƒ“ƒO)
1584 if(FT_Glyph_To_Bitmap(&copy_glyph, render_mode, 0, 1)){
1585 FT_Done_Glyph(copy_glyph);
1586 return FALSE;
1588 glyph_bitmap = (FT_BitmapGlyph)copy_glyph;
1592 int cx = (bVertical && IsVerticalChar(wch)) ?
1593 FT_FixedToInt(glyph_bitmap->root.advance.y) :
1594 FT_FixedToInt(glyph_bitmap->root.advance.x);
1595 pfnCallback(FTInfo, wch, glyph_bitmap);
1596 if (bSizeOnly) {
1597 FTInfo.x += bWidthGDI32 ? gdi32x : cx;
1598 } else {
1599 int dx = clpdx.get(bWidthGDI32 ? gdi32x : cx);
1600 if (lpString < lpEnd - 1) {
1601 FTInfo.x += dx;
1602 } else {
1603 int bx = glyph_bitmap->bitmap.width;
1604 if (render_mode == FT_RENDER_MODE_LCD) bx /= 3;
1605 bx += glyph_bitmap->left;
1606 FTInfo.x += Max(Max(dx, bx), cx);
1609 FTInfo.x += FTInfo.params.charExtra;
1611 //if (bSizeOnly || bOwnCache) {
1612 //ƒLƒƒƒbƒVƒ…‰»
1613 if (glyph_index) {
1614 if (bGlyphIndex) {
1615 pftCache->AddGlyphData(glyph_index, cx, glyph_bitmap, render_mode);
1616 } else {
1617 pftCache->AddCharData(wch, glyph_index, cx, glyph_bitmap, render_mode);
1622 if(copy_glyph){
1623 FT_Done_Glyph(copy_glyph);
1626 return TRUE;
1629 BOOL GetLogFontFromDC(HDC hdc, LOGFONT& lf)
1631 LOGFONTW lfForce = { 0 };
1632 HFONT hf = GetCurrentFont(hdc);
1633 if (!GetObject(hf, sizeof(LOGFONTW), &lf))
1634 return FALSE;
1636 const CGdippSettings* pSettings = CGdippSettings::GetInstance();
1637 if (pSettings->CopyForceFont(lfForce, lf))
1638 lf = lfForce;
1640 if(pSettings->LoadOnDemand()) {
1641 AddFontToFT(lf.lfFaceName, lf.lfWeight, !!lf.lfItalic);
1643 return TRUE;
1646 BOOL CALLBACK TextOutCallback(FreeTypeDrawInfo& FTInfo, const WCHAR wch, const FT_BitmapGlyph glyph_bitmap)
1648 const bool bVertical = FTInfo.LogFont().lfFaceName[0] == _T('@');
1650 if (!glyph_bitmap->bitmap.buffer) {
1651 if (FTInfo.params.alpha == 1) {
1652 ORIG_ExtTextOutW(FTInfo.hdc, FTInfo.x, FTInfo.yTop, FTInfo.GetETO(), NULL, &wch, 1, NULL);
1654 } else {
1655 const CGdippSettings* pSettings = CGdippSettings::GetInstance();
1656 if (bVertical && IsVerticalChar(wch) &&
1657 pSettings->FontLoader() == SETTING_FONTLOADER_FREETYPE) {
1658 FreeTypeDrawBitmapV(*FTInfo.pCache,
1659 &glyph_bitmap->bitmap,
1660 FTInfo.x + FTInfo.yBase - glyph_bitmap->top,
1661 FTInfo.yTop + FT_PosToInt(FTInfo.freetype_face->size->metrics.height) -
1662 (glyph_bitmap->left+glyph_bitmap->bitmap.width) - 1,
1663 FTInfo);
1664 }else{
1665 FreeTypeDrawBitmap(*FTInfo.pCache,
1666 &glyph_bitmap->bitmap,
1667 FTInfo.x + glyph_bitmap->left,
1668 FTInfo.yBase - glyph_bitmap->top,
1669 FTInfo);
1673 //if (FTInfo.lpDx) {
1674 // FTInfo.x += *FTInfo.lpDx++;
1675 // return FALSE;
1677 return TRUE;
1680 BOOL CALLBACK GetTextExtentCallback(FreeTypeDrawInfo& /*FTInfo*/, const WCHAR /*wch*/, const FT_BitmapGlyph /*glyph_bitmap*/)
1682 return TRUE;
1685 // FreeType‚ð—p‚¢‚½TextOut API‚à‚Ç‚«
1686 BOOL FreeTypeTextOut(
1687 const HDC hdc, // ƒfƒoƒCƒXƒRƒ“ƒeƒLƒXƒg‚̃nƒ“ƒhƒ‹
1688 CBitmapCache& cache,
1689 const int nXStart, // ŠJŽnˆÊ’u�iŠî�€“_�j‚Ì x �À•W
1690 const int nYStart, // ŠJŽnˆÊ’u�iŠî�€“_�j‚Ì y �À•W
1691 LPCWSTR lpString, // •¶Žš—ñ
1692 int cbString, // •¶Žš�”
1693 const int* lpDx, // •`‰æˆÊ’u
1694 const FREETYPE_PARAMS* params,
1695 int& width
1698 CCriticalSectionLock __lock;
1700 // Unicode‚Å“n‚·‚悤‚É‚·‚é(FT_Select_Charmap‚Å•Ï�X‰Â”\)
1701 if(cbString <= 0 || lpString == NULL)
1702 return FALSE;
1704 LOGFONTW* lplf = NULL;
1705 LOGFONTW lfForce = { 0 };
1706 const CGdippSettings* pSettings = CGdippSettings::GetInstance();
1707 if (!(params->etoOptions & ETO_GLYPH_INDEX))
1709 if (pSettings->CopyForceFont(lfForce, *params->lplf))
1710 lplf = &lfForce;
1713 FreeTypeDrawInfo FTInfo(*params, hdc, lplf, &cache, lpDx);
1714 if(!FreeTypePrepare(FTInfo))
1715 return FALSE;
1717 FT_Face freetype_face = FTInfo.freetype_face;
1718 const LOGFONT& lf = FTInfo.LogFont();
1720 FTInfo.x = nXStart;
1721 FTInfo.yTop = nYStart;
1723 const TEXTMETRIC& tm = FTInfo.pftCache->GetTextMetric(hdc);
1724 FTInfo.yBase = nYStart + tm.tmAscent;
1725 if(!ForEachGetGlyph(FTInfo, lpString, cbString, TextOutCallback))
1726 return FALSE;
1727 width = FTInfo.x;
1729 const int x = FTInfo.x;
1730 const int y = FTInfo.yBase;
1732 // ‰º�ü‚ð(‚ ‚ê‚Î)ˆø‚­
1733 if(lf.lfUnderline || lf.lfStrikeOut) {
1734 OUTLINETEXTMETRIC otm = { sizeof(OUTLINETEXTMETRIC) };
1735 GetOutlineTextMetrics(hdc, otm.otmSize, &otm);
1736 if(lf.lfUnderline){
1737 int yPos = 0; //‰º�ü‚̈ʒu
1738 int height = 0;
1739 int thickness = 0; // “K“–‚È‘¾‚³
1740 switch (pSettings->FontLoader()) {
1741 case SETTING_FONTLOADER_FREETYPE:
1742 yPos = y + 1;
1743 height = FT_PosToInt(freetype_face->size->metrics.height);
1744 thickness =
1745 FT_MulDiv(freetype_face->underline_thickness,
1746 freetype_face->size->metrics.y_ppem,
1747 freetype_face->units_per_EM);
1748 break;
1749 case SETTING_FONTLOADER_WIN32:
1750 yPos = y - otm.otmsUnderscorePosition;
1751 height = otm.otmTextMetrics.tmHeight;
1752 thickness = otm.otmsUnderscoreSize;
1753 break;
1755 if (yPos >= height) {
1756 yPos = height - 1;
1758 cache.DrawHorizontalLine(nXStart, yPos, x, FTInfo.Color(), thickness);
1761 // Žæ�Á�ü‚ð(‚ ‚ê‚Î)ˆø‚­
1762 if(lf.lfStrikeOut){
1763 // Žæ�Á�ü‚̈ʒu(FreeType‚Ŏ擾‚Å‚«‚»‚¤‚É‚È‚¢‚Ì‚ÅWin32API—˜—p)
1764 int yPos = y - otm.otmsStrikeoutPosition; //Žæ�Á�ü‚̈ʒu
1765 int thickness = 0; // “K“–‚È‘¾‚³
1766 switch (pSettings->FontLoader()) {
1767 case SETTING_FONTLOADER_FREETYPE:
1768 thickness =
1769 MulDiv(freetype_face->underline_thickness,
1770 freetype_face->size->metrics.y_ppem,
1771 freetype_face->units_per_EM);
1772 break;
1773 case SETTING_FONTLOADER_WIN32:
1774 thickness = otm.otmsStrikeoutSize;
1775 break;
1777 cache.DrawHorizontalLine(nXStart, yPos, x, FTInfo.Color(), thickness);
1781 //PatBlt(hdc, 0, y, 9999, y + 1, DSTINVERT);
1782 //PatBlt(hdc, 0, 0, 9999, 0 + 1, DSTINVERT);
1783 return TRUE;
1786 BOOL FreeTypeGetTextExtentPoint(
1787 const HDC hdc,
1788 LPCWSTR lpString,
1789 int cbString,
1790 LPSIZE lpSize,
1791 const FREETYPE_PARAMS* params
1795 * FIXME: there should be a replaced version of GetTextExtentPointI for WidthMode=1
1796 * but there isn't now, so we call the original one when GLYPH_INDEX is specified
1797 * and obviously calling GetTextExtentPoint32W in this circumstance is wrong
1799 if (params->etoOptions & ETO_GLYPH_INDEX)
1800 return GetTextExtentPointI(hdc, (LPWORD)lpString, cbString, lpSize);
1802 const CGdippSettings* pSettings = CGdippSettings::GetInstance();
1803 if (pSettings->WidthMode() == SETTING_WIDTHMODE_GDI32) {
1804 return ORIG_GetTextExtentPoint32W(hdc, lpString, cbString, lpSize);
1807 CCriticalSectionLock __lock;
1809 //‚Æ‚è‚ ‚¦‚¸0–„‚ß
1810 if (lpSize) {
1811 lpSize->cx = lpSize->cy = 0;
1814 // Unicode‚Å“n‚·‚悤‚É‚·‚é(FT_Select_Charmap‚Å•Ï�X‰Â”\)
1815 if(cbString <= 0 || lpString == NULL || lpSize == NULL) {
1816 return FALSE;
1819 Assert(params != NULL);
1820 LOGFONT lf;
1821 if (!GetLogFontFromDC(hdc, lf))
1822 return FALSE;
1824 FreeTypeDrawInfo FTInfo(*params, hdc, &lf);
1825 if(!FreeTypePrepare(FTInfo))
1826 return FALSE;
1828 FTInfo.x = 0;
1829 if(!ForEachGetGlyph(FTInfo, lpString, cbString, GetTextExtentCallback)) {
1830 lpSize->cx = 0;
1831 lpSize->cy = 0;
1832 return FALSE;
1835 lpSize->cx = FTInfo.x;
1836 lpSize->cy = FTInfo.pftCache->GetTextMetric(hdc).tmHeight;
1837 return TRUE;
1840 BOOL FreeTypeGetCharWidth(const HDC hdc, UINT iFirstChar, UINT iLastChar, LPINT lpBuffer)
1842 const CGdippSettings* pSettings = CGdippSettings::GetInstance();
1843 if (pSettings->WidthMode() == SETTING_WIDTHMODE_GDI32) {
1844 return ORIG_GetCharWidth32W(hdc, iFirstChar, iLastChar, lpBuffer);
1847 CCriticalSectionLock __lock;
1849 if (!lpBuffer || iFirstChar > iLastChar || iFirstChar > 0xffff || iLastChar > 0xffff) {
1850 SetLastError(ERROR_INVALID_PARAMETER);
1851 return FALSE;
1854 //‚Æ‚è‚ ‚¦‚¸0–„‚ß
1855 ZeroMemory(lpBuffer, sizeof(INT) * (iLastChar - iFirstChar));
1857 LOGFONT lf;
1858 if (!GetLogFontFromDC(hdc, lf))
1859 return FALSE;
1861 FREETYPE_PARAMS params(0, hdc);
1862 FreeTypeDrawInfo FTInfo(params, hdc, &lf);
1863 if(!FreeTypePrepare(FTInfo))
1864 return FALSE;
1866 WCHAR wch = (WORD)iFirstChar;
1867 const WCHAR wend = (WORD)iLastChar;
1869 while (wch <= wend) {
1870 FTInfo.x = 0;
1871 if(!ForEachGetGlyph(FTInfo, &wch, 1, GetTextExtentCallback))
1872 return FALSE;
1873 *lpBuffer++ = FTInfo.x;
1874 wch++;
1876 return TRUE;
1879 void VertFinalizer(void *object){
1880 FT_Face face = (FT_Face)object;
1881 ft2vert_final(face, (struct ft2vert_st *)face->generic.data);
1884 FT_Error face_requester(
1885 FTC_FaceID face_id,
1886 FT_Library /*library*/,
1887 FT_Pointer /*request_data*/,
1888 FT_Face* aface)
1890 FT_Error ret;
1891 FT_Face face;
1893 FreeTypeFontInfo* pfi = g_pFTEngine->FindFont((int)face_id);
1894 Assert(pfi);
1895 if (!pfi) {
1896 return FT_Err_Invalid_Argument;
1898 LPCTSTR fontname = pfi->GetName();
1900 // –¼�Ì‚ðŽw’肵‚ătƒHƒ“ƒg‚ðŽæ“¾
1901 FreeTypeSysFontData* pData = FreeTypeSysFontData::CreateInstance(fontname, pfi->GetFontWeight(), pfi->IsItalic());
1902 if(pData == NULL){
1903 return FT_Err_Cannot_Open_Resource;
1906 face = pData->GetFace();
1907 Assert(face != NULL);
1909 // Charmap‚ð�ݒ肵‚Ä‚¨‚­
1910 ret = FT_Select_Charmap(face, FT_ENCODING_UNICODE);
1911 if(ret != FT_Err_Ok){
1912 ret = FT_Select_Charmap(face, FT_ENCODING_MS_SYMBOL);
1913 if(ret != FT_Err_Ok)
1915 FT_Done_Face(face);
1916 return ret;
1920 if(fontname[0] == _T('@')){
1921 struct ft2vert_st *vert = ft2vert_init(face);
1922 face->generic.data = vert;
1923 face->generic.finalizer = VertFinalizer;
1926 // ƒOƒŠƒt’uŠ·‚Ì‚½‚ß�í‚É•K—v
1927 struct ft2vert_st *vert = ft2vert_init(face);
1928 face->generic.data = vert;
1929 face->generic.finalizer = VertFinalizer;
1931 *aface = face;
1932 return 0;
1937 DWORD FreeTypeGetVersion()
1939 int major = 0, minor = 0, patch = 0;
1940 FT_Library_Version(freetype_library, &major, &minor, &patch);
1941 //–Ê“|‚È‚Ì‚ÅRGBƒ}ƒNƒ�Žg—p
1942 return RGB(major, minor, patch);
1946 //�V‘¾ŽšƒAƒ‹ƒSƒŠƒYƒ€
1947 FT_Error New_FT_Outline_Embolden( FT_Outline* outline, FT_Pos str_h, FT_Pos str_v )
1949 const CGdippSettings* pSettings = CGdippSettings::GetInstance();
1950 int orientation = 0;
1951 switch (pSettings->BolderMode()) {
1952 case 1:
1953 return Old_FT_Outline_Embolden( outline, str_h );
1955 case 2:
1956 return FT_Outline_Embolden( outline, str_h );
1958 default:
1960 if ( !outline ) return FT_Err_Invalid_Argument;
1961 orientation = FT_Outline_Get_Orientation( outline );
1962 if ( orientation == FT_ORIENTATION_NONE )
1963 if ( outline->n_contours ) return FT_Err_Invalid_Argument;
1964 Vert_FT_Outline_Embolden( outline, str_v );
1965 Old_FT_Outline_Embolden( outline, str_h );
1966 return FT_Err_Ok;
1971 //‰¡•ûŒü‚¾‚¯‘¾‚点‚éFT_Outline_Embolden
1972 FT_Error Old_FT_Outline_Embolden( FT_Outline* outline, FT_Pos strength )
1974 FT_Vector* points;
1975 FT_Vector v_prev, v_first, v_next, v_cur;
1976 FT_Angle rotate, angle_in, angle_out;
1977 FT_Int c, n, first;
1978 FT_Int orientation;
1980 if ( !outline )
1981 return FT_Err_Invalid_Argument;
1983 strength /= 2;
1984 if ( strength == 0 )
1985 return FT_Err_Ok;
1987 orientation = FT_Outline_Get_Orientation( outline );
1988 if ( orientation == FT_ORIENTATION_NONE )
1990 if ( outline->n_contours )
1991 return FT_Err_Invalid_Argument;
1992 else
1993 return FT_Err_Ok;
1996 if ( orientation == FT_ORIENTATION_TRUETYPE )
1997 rotate = -FT_ANGLE_PI2;
1998 else
1999 rotate = FT_ANGLE_PI2;
2001 points = outline->points;
2003 first = 0;
2004 for ( c = 0; c < outline->n_contours; c++ )
2006 int last = outline->contours[c];
2008 v_first = points[first];
2009 v_prev = points[last];
2010 v_cur = v_first;
2012 for ( n = first; n <= last; n++ )
2014 FT_Vector in, out;
2015 FT_Angle angle_diff;
2016 FT_Pos d;
2017 FT_Fixed scale;
2019 if ( n < last )
2020 v_next = points[n + 1];
2021 else
2022 v_next = v_first;
2024 /* compute the in and out vectors */
2025 in.x = v_cur.x - v_prev.x;
2026 in.y = v_cur.y - v_prev.y;
2028 out.x = v_next.x - v_cur.x;
2029 out.y = v_next.y - v_cur.y;
2031 angle_in = FT_Atan2( in.x, in.y );
2032 angle_out = FT_Atan2( out.x, out.y );
2033 angle_diff = FT_Angle_Diff( angle_in, angle_out );
2034 scale = FT_Cos( angle_diff / 2 );
2036 if ( scale < 0x4000L && scale > -0x4000L )
2037 in.x = in.y = 0;
2038 else
2040 d = FT_DivFix( strength, scale );
2042 FT_Vector_From_Polar( &in, d, angle_in + angle_diff / 2 - rotate );
2045 outline->points[n].x = v_cur.x + strength + in.x;
2046 //�«‚±‚ê‚ðƒRƒ�ƒ“ƒgƒAƒEƒg‚µ‚½‚¾‚¯
2047 //outline->points[n].y = v_cur.y + strength + in.y;
2049 v_prev = v_cur;
2050 v_cur = v_next;
2053 first = last + 1;
2056 return FT_Err_Ok;
2059 //‚±‚Á‚¿‚Í�c•ûŒü
2060 FT_Error Vert_FT_Outline_Embolden( FT_Outline* outline, FT_Pos strength )
2062 FT_Vector* points;
2063 FT_Vector v_prev, v_first, v_next, v_cur;
2064 FT_Angle rotate, angle_in, angle_out;
2065 FT_Int c, n, first;
2066 FT_Int orientation;
2068 if ( !outline )
2069 return FT_Err_Invalid_Argument;
2071 strength /= 2;
2072 if ( strength == 0 )
2073 return FT_Err_Ok;
2075 orientation = FT_Outline_Get_Orientation( outline );
2076 if ( orientation == FT_ORIENTATION_NONE )
2078 if ( outline->n_contours )
2079 return FT_Err_Invalid_Argument;
2080 else
2081 return FT_Err_Ok;
2084 if ( orientation == FT_ORIENTATION_TRUETYPE )
2085 rotate = -FT_ANGLE_PI2;
2086 else
2087 rotate = FT_ANGLE_PI2;
2089 points = outline->points;
2091 first = 0;
2092 for ( c = 0; c < outline->n_contours; c++ )
2094 int last = outline->contours[c];
2096 v_first = points[first];
2097 v_prev = points[last];
2098 v_cur = v_first;
2100 for ( n = first; n <= last; n++ )
2102 FT_Vector in, out;
2103 FT_Angle angle_diff;
2104 FT_Pos d;
2105 FT_Fixed scale;
2107 if ( n < last )
2108 v_next = points[n + 1];
2109 else
2110 v_next = v_first;
2112 /* compute the in and out vectors */
2113 in.x = v_cur.x - v_prev.x;
2114 in.y = v_cur.y - v_prev.y;
2116 out.x = v_next.x - v_cur.x;
2117 out.y = v_next.y - v_cur.y;
2119 angle_in = FT_Atan2( in.x, in.y );
2120 angle_out = FT_Atan2( out.x, out.y );
2121 angle_diff = FT_Angle_Diff( angle_in, angle_out );
2122 scale = FT_Cos( angle_diff / 2 );
2124 if ( scale < 0x4000L && scale > -0x4000L )
2125 in.x = in.y = 0;
2126 else
2128 d = FT_DivFix( strength, scale );
2130 FT_Vector_From_Polar( &in, d, angle_in + angle_diff / 2 - rotate );
2133 //outline->points[n].x = v_cur.x + strength + in.x;
2134 //�ª‚±‚ê‚ðƒRƒ�ƒ“ƒgƒAƒEƒg‚µ‚½‚¾‚¯
2135 outline->points[n].y = v_cur.y + strength + in.y;
2137 v_prev = v_cur;
2138 v_cur = v_next;
2141 first = last + 1;
2144 return FT_Err_Ok;
2147 //ƒ_ƒ~�[
2148 FT_EXPORT( FT_Error )
2149 FT_Library_SetLcdFilter_Dummy( FT_Library /*library*/,
2150 FT_LcdFilter /*filter*/ )
2152 return 0;
2155 BOOL FontLInit(void){
2156 CCriticalSectionLock __lock;
2158 if(FT_Init_FreeType(&freetype_library)){
2159 return FALSE;
2161 const CGdippSettings* pSettings = CGdippSettings::GetInstance();
2162 if(FTC_Manager_New(freetype_library,
2163 pSettings->CacheMaxFaces(),
2164 pSettings->CacheMaxSizes(),
2165 pSettings->CacheMaxBytes(),
2166 face_requester, NULL,
2167 &cache_man))
2169 FontLFree();
2170 return FALSE;
2172 if(FTC_CMapCache_New(cache_man, &cmap_cache)){
2173 FontLFree();
2174 return FALSE;
2176 if(FTC_ImageCache_New(cache_man, &image_cache)){
2177 FontLFree();
2178 return FALSE;
2181 const int nLcdFilter = pSettings->LcdFilter();
2182 if ((int)FT_LCD_FILTER_NONE < nLcdFilter && nLcdFilter < (int)FT_LCD_FILTER_MAX) {
2183 FT_Library_SetLcdFilter(freetype_library, (FT_LcdFilter)nLcdFilter);
2186 s_AlphaBlendTable.init();
2187 return TRUE;
2190 void FontLFree(void){
2191 CCriticalSectionLock __lock;
2193 if(cache_man != NULL)
2194 FTC_Manager_Done(cache_man);
2195 if(freetype_library != NULL)
2196 FT_Done_FreeType(freetype_library);
2197 cache_man = NULL;
2198 freetype_library = NULL;