1 /*$
2 Copyright (C) 2013-2020 Azel.
3
4 This file is part of AzPainter.
5
6 AzPainter is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 AzPainter is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
18 $*/
19
20 /*****************************************
21 * mFont (freetype)
22 *****************************************/
23
24 #include <string.h>
25
26 #include <ft2build.h>
27 #include FT_CONFIG_CONFIG_H
28 #include FT_FREETYPE_H
29 #include FT_GLYPH_H
30 #include FT_BITMAP_H
31 #include FT_LCD_FILTER_H
32
33 #include "mDef.h"
34
35 #include "mFont.h"
36 #include "mFontConfig.h"
37 #include "mFreeType.h"
38 #include "mPixbuf.h"
39 #include "mGui.h"
40 #include "mUtilCharCode.h"
41
42
43 //------------------------
44
45 typedef struct
46 {
47 mFont b;
48
49 FT_Face face;
50 int baseline,
51 underline;
52
53 mFreeTypeInfo info;
54 }__mFontFt;
55
56 #define _FONT(p) ((__mFontFt *)(p))
57
58 //------------------------
59
60
61 /**
62 @defgroup font mFont
63 @brief フォント
64
65 @ingroup group_system
66 @{
67
68 @file mFont.h
69 @struct _mFont
70 @struct mFontInfo
71 @enum MFONTINFO_MASK
72 @enum MFONTINFO_WEIGHT
73 @enum MFONTINFO_SLANT
74 @enum MFONTINFO_RENDER
75 */
76
77
78 //================================
79
80
81 /** 高さなどセット */
82
_set_font_info(__mFontFt * font)83 static void _set_font_info(__mFontFt *font)
84 {
85 mFreeTypeMetricsInfo info;
86
87 mFreeTypeGetMetricsInfo(mGetFreeTypeLib(), font->face, &font->info, &info);
88
89 font->b.height = info.height;
90 font->b.lineheight = info.lineheight;
91 font->baseline = info.baseline;
92 font->underline = info.underline;
93 }
94
95 /*
96 //セル高さで指定
97
98 static void _ft_set_cell_height(FT_Face face,double size)
99 {
100 FT_Size_RequestRec req;
101
102 req.type = FT_SIZE_REQUEST_TYPE_CELL;
103 req.width = 0;
104 req.height = (int)(size * 64 + 0.5);
105 req.horiResolution = 0;
106 req.vertResolution = 0;
107
108 FT_Request_Size(face, &req);
109 }
110 */
111
112
113 //================================
114
115
116 /** フォント解放 */
117
mFontFree(mFont * font)118 void mFontFree(mFont *font)
119 {
120 if(font)
121 {
122 FT_Done_Face(_FONT(font)->face);
123
124 mFree(font);
125 }
126 }
127
128 /** フォント作成 */
129
mFontCreate(mFontInfo * info)130 mFont *mFontCreate(mFontInfo *info)
131 {
132 mFcPattern *pat;
133 FT_Face face = NULL;
134 char *file;
135 int index;
136 __mFontFt *font;
137 double size;
138
139 //マッチするパターン
140
141 pat = mFontConfigMatch(info);
142 if(!pat) return NULL;
143
144 //フォントファイル読み込み
145 /* file は UTF-8 だが、フォントファイル名が ASCII 文字以外の場合は
146 * ほとんどないと思われるのでそのまま使う */
147
148 if(mFontConfigGetFileInfo(pat, &file, &index))
149 goto ERR;
150
151 if(FT_New_Face(mGetFreeTypeLib(), file, index, &face))
152 goto ERR;
153
154 //mFont 確保
155
156 font = (__mFontFt *)mMalloc(sizeof(__mFontFt), TRUE);
157 if(!font) goto ERR;
158
159 font->face = face;
160
161 //FcPattern から情報取得
162
163 mFreeTypeGetInfoByFontConfig(&font->info, pat, info);
164
165 mFontConfigPatternFree(pat);
166
167 //文字高さセット (FreeType)
168
169 size = font->info.size;
170
171 if(size < 0)
172 FT_Set_Pixel_Sizes(face, 0, -size);
173 else
174 FT_Set_Char_Size(face, 0, (int)(size * 64 + 0.5), font->info.dpi, font->info.dpi);
175
176 //ほか情報セット
177
178 _set_font_info(font);
179
180 return (mFont *)font;
181
182 ERR:
183 if(face) FT_Done_Face(face);
184 mFontConfigPatternFree(pat);
185
186 return NULL;
187 }
188
189 /** フォントの実体を返す
190 *
191 * FreeType なら FT_Face */
192
mFontGetHandle(mFont * font)193 void *mFontGetHandle(mFont *font)
194 {
195 return (void *)_FONT(font)->face;
196 }
197
198
199 //===================================
200 // 文字描画
201 //===================================
202
203
204 /** 1文字描画 */
205
_draw_char(__mFontFt * font,mPixbuf * img,FT_BitmapGlyph glyph,int x,int y,mRgbCol col)206 static void _draw_char(__mFontFt *font,mPixbuf *img,
207 FT_BitmapGlyph glyph,int x,int y,mRgbCol col)
208 {
209 FT_Bitmap *bm;
210 uint8_t *pbuf,*pb,r,g,b,fBGR;
211 int ix,iy,w,h,pitch,pitch2,f;
212 uint32_t dcol;
213
214 bm = &glyph->bitmap;
215
216 w = bm->width;
217 h = bm->rows;
218 pbuf = bm->buffer;
219 pitch = bm->pitch;
220
221 if(pitch < 0) pbuf += -pitch * (h - 1);
222
223 fBGR = ((font->info.flags & MFTINFO_F_SUBPIXEL_BGR) != 0);
224
225 //
226
227 if(bm->pixel_mode == FT_PIXEL_MODE_MONO)
228 {
229 //1bit モノクロ
230
231 dcol = mRGBtoPix(col);
232
233 for(iy = 0; iy < h; iy++, pbuf += pitch)
234 {
235 for(ix = 0, f = 0x80, pb = pbuf; ix < w; ix++)
236 {
237 if(*pb & f)
238 mPixbufSetPixel(img, x + ix, y + iy, dcol);
239
240 f >>= 1;
241 if(!f) { f = 0x80; pb++; }
242 }
243 }
244 }
245 else if(bm->pixel_mode == FT_PIXEL_MODE_GRAY)
246 {
247 //8bit グレイスケール
248
249 pitch -= w;
250
251 for(iy = 0; iy < h; iy++, pbuf += pitch)
252 {
253 for(ix = 0; ix < w; ix++, pbuf++)
254 {
255 if(*pbuf)
256 {
257 dcol = mFreeTypeBlendColorGray(
258 mPixbufGetPixelRGB(img, x + ix, y + iy), col, *pbuf);
259
260 mPixbufSetPixel(img, x + ix, y + iy, mRGBtoPix(dcol));
261 }
262 }
263 }
264 }
265 else if(bm->pixel_mode == FT_PIXEL_MODE_LCD)
266 {
267 //LCD
268
269 pitch -= w;
270 w /= 3;
271
272 for(iy = 0; iy < h; iy++, pbuf += pitch)
273 {
274 for(ix = 0; ix < w; ix++, pbuf += 3)
275 {
276 if(fBGR)
277 r = pbuf[2], g = pbuf[1], b = pbuf[0];
278 else
279 r = pbuf[0], g = pbuf[1], b = pbuf[2];
280
281 if(r || g || b)
282 {
283 dcol = mFreeTypeBlendColorLCD(
284 mPixbufGetPixelRGB(img, x + ix, y + iy), col, r, g, b);
285
286 mPixbufSetPixel(img, x + ix, y + iy, mRGBtoPix(dcol));
287 }
288 }
289 }
290 }
291 else if(bm->pixel_mode == FT_PIXEL_MODE_LCD_V)
292 {
293 //LCD Vertical
294
295 pitch2 = pitch * 3 - w;
296 h /= 3;
297
298 for(iy = 0; iy < h; iy++, pbuf += pitch2)
299 {
300 for(ix = 0; ix < w; ix++, pbuf++)
301 {
302 if(fBGR)
303 r = pbuf[pitch << 1], g = pbuf[pitch], b = pbuf[0];
304 else
305 r = pbuf[0], g = pbuf[pitch], b = pbuf[pitch << 1];
306
307 if(r || g || b)
308 {
309 dcol = mFreeTypeBlendColorLCD(
310 mPixbufGetPixelRGB(img, x + ix, y + iy), col, r, g, b);
311
312 mPixbufSetPixel(img, x + ix, y + iy, mRGBtoPix(dcol));
313 }
314 }
315 }
316 }
317 }
318
319
320 //===================================
321 // テキスト描画
322 //===================================
323
324
325 /** mPixbuf にテキスト描画
326 *
327 * @param text UTF-8
328 * @param len text の最大長さ (負の値で NULL 文字まで)
329 * @param col RGB値 */
330
mFontDrawText(mFont * font,mPixbuf * img,int x,int y,const char * text,int len,mRgbCol col)331 void mFontDrawText(mFont *font,mPixbuf *img,int x,int y,
332 const char *text,int len,mRgbCol col)
333 {
334 __mFontFt *pfont;
335 const char *pc;
336 int ret;
337 uint32_t code;
338 FT_Library ftlib;
339 FT_BitmapGlyph glyph;
340
341 if(!text) return;
342
343 ftlib = mGetFreeTypeLib();
344 pfont = _FONT(font);
345
346 //LCD Filter
347
348 #ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
349 FT_Library_SetLcdFilter(ftlib, pfont->info.nLCDFilter);
350 #endif
351
352 //
353
354 y += pfont->baseline;
355
356 for(pc = text; *pc; )
357 {
358 if(len >= 0 && pc - text >= len) break;
359
360 ret = mUTF8ToUCS4Char(pc, 4, &code, &pc);
361 if(ret < 0) break;
362 if(ret > 0) continue;
363
364 glyph = mFreeTypeGetBitmapGlyph(ftlib, pfont->face, &pfont->info, code);
365
366 if(glyph)
367 {
368 _draw_char(pfont, img, glyph, x + glyph->left, y - glyph->top, col);
369
370 x += glyph->root.advance.x >> 16;
371
372 FT_Done_Glyph((FT_Glyph)glyph);
373 }
374 else
375 {
376 mPixbufBox(img, x, y - pfont->baseline, 8, pfont->baseline, mRGBtoPix(col));
377
378 x += 8;
379 }
380 }
381 }
382
383 /** mPixbuf にテキスト描画 (&でホットキー処理)
384 *
385 * @param text UTF-8
386 * @param len text の最大長さ (負の値で NULL 文字まで)
387 * @param col RGB値 */
388
mFontDrawTextHotkey(mFont * font,mPixbuf * img,int x,int y,const char * text,int len,mRgbCol col)389 void mFontDrawTextHotkey(mFont *font,mPixbuf *img,int x,int y,
390 const char *text,int len,mRgbCol col)
391 {
392 __mFontFt *pfont;
393 const char *pc;
394 int w,ret;
395 uint32_t code;
396 mBool bNextHotkey = FALSE;
397 FT_Library ftlib;
398 FT_BitmapGlyph glyph;
399
400 if(!text) return;
401
402 ftlib = mGetFreeTypeLib();
403 pfont = _FONT(font);
404
405 //LCD Filter
406
407 #ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
408 FT_Library_SetLcdFilter(ftlib, pfont->info.nLCDFilter);
409 #endif
410
411 //
412
413 y += pfont->baseline;
414
415 for(pc = text; *pc; )
416 {
417 if(len >= 0 && pc - text >= len) break;
418
419 if(*pc == '&')
420 {
421 pc++;
422
423 if(bNextHotkey)
424 {
425 //&&
426 code = '&';
427 bNextHotkey = FALSE;
428 }
429 else
430 {
431 bNextHotkey = TRUE;
432 continue;
433 }
434 }
435 else
436 {
437 ret = mUTF8ToUCS4Char(pc, 4, &code, &pc);
438 if(ret < 0) break;
439 if(ret > 0) continue;
440 }
441
442 //グリフ
443
444 glyph = mFreeTypeGetBitmapGlyph(ftlib, pfont->face, &pfont->info, code);
445
446 if(glyph)
447 {
448 _draw_char(pfont, img, glyph, x + glyph->left, y - glyph->top, col);
449
450 w = glyph->root.advance.x >> 16;
451
452 FT_Done_Glyph((FT_Glyph)glyph);
453 }
454 else
455 {
456 mPixbufBox(img, x, y - pfont->baseline, 8, pfont->baseline, mRGBtoPix(col));
457
458 w = 8;
459 }
460
461 //下線
462
463 if(bNextHotkey)
464 {
465 mPixbufLineH(img, x, y + pfont->underline, w, mRGBtoPix(col));
466
467 bNextHotkey = FALSE;
468 }
469
470 x += w;
471 }
472 }
473
474 /** mPixbuf にテキスト描画
475 *
476 * @param text UCS-4
477 * @param len text の最大長さ (負の値で NULL 文字まで) */
478
mFontDrawTextUCS4(mFont * font,mPixbuf * img,int x,int y,const uint32_t * text,int len,mRgbCol col)479 void mFontDrawTextUCS4(mFont *font,mPixbuf *img,int x,int y,
480 const uint32_t *text,int len,mRgbCol col)
481 {
482 __mFontFt *pfont;
483 FT_Library ftlib;
484 FT_BitmapGlyph glyph;
485 int i;
486
487 if(!text) return;
488
489 ftlib = mGetFreeTypeLib();
490 pfont = _FONT(font);
491
492 //LCD Filter
493
494 #ifdef FT_CONFIG_OPTION_SUBPIXEL_RENDERING
495 FT_Library_SetLcdFilter(ftlib, pfont->info.nLCDFilter);
496 #endif
497
498 //
499
500 y += pfont->baseline;
501
502 for(i = 0; *text; text++, i++)
503 {
504 if(len >= 0 && i >= len) break;
505
506 glyph = mFreeTypeGetBitmapGlyph(ftlib, pfont->face, &pfont->info, *text);
507
508 if(glyph)
509 {
510 _draw_char(pfont, img, glyph, x + glyph->left, y - glyph->top, col);
511
512 x += glyph->root.advance.x >> 16;
513
514 FT_Done_Glyph((FT_Glyph)glyph);
515 }
516 else
517 {
518 mPixbufBox(img, x, y - pfont->baseline, 8, pfont->baseline, mRGBtoPix(col));
519
520 x += 8;
521 }
522 }
523 }
524
525
526 //============================
527 // 幅取得
528 //============================
529
530
531 /** テキストの幅取得 (UTF-8) */
532
mFontGetTextWidth(mFont * font,const char * text,int len)533 int mFontGetTextWidth(mFont *font,const char *text,int len)
534 {
535 __mFontFt *pfont;
536 const char *pc;
537 int ret,w = 0;
538 uint32_t code;
539 FT_Library ftlib;
540 FT_BitmapGlyph glyph;
541
542 if(!text) return 0;
543
544 ftlib = mGetFreeTypeLib();
545 pfont = _FONT(font);
546
547 for(pc = text; *pc; )
548 {
549 if(len >= 0 && pc - text >= len) break;
550
551 ret = mUTF8ToUCS4Char(pc, 4, &code, &pc);
552 if(ret < 0) break;
553 if(ret > 0) continue;
554
555 glyph = mFreeTypeGetBitmapGlyph(ftlib, pfont->face, &pfont->info, code);
556
557 if(glyph)
558 {
559 w += glyph->root.advance.x >> 16;
560
561 FT_Done_Glyph((FT_Glyph)glyph);
562 }
563 else
564 w += 8;
565 }
566
567 return w;
568 }
569
570 /** テキストの幅取得
571 *
572 * ホットキー '&' の処理を行う。 */
573
mFontGetTextWidthHotkey(mFont * font,const char * text,int len)574 int mFontGetTextWidthHotkey(mFont *font,const char *text,int len)
575 {
576 __mFontFt *pfont;
577 const char *pc;
578 int ret,w = 0;
579 uint32_t code;
580 mBool bNextHotkey = FALSE;
581 FT_Library ftlib;
582 FT_BitmapGlyph glyph;
583
584 if(!text) return 0;
585
586 ftlib = mGetFreeTypeLib();
587 pfont = _FONT(font);
588
589 for(pc = text; *pc; )
590 {
591 if(len >= 0 && pc - text >= len) break;
592
593 if(*pc == '&')
594 {
595 pc++;
596
597 if(bNextHotkey)
598 {
599 //&&
600 code = '&';
601 bNextHotkey = FALSE;
602 }
603 else
604 {
605 bNextHotkey = TRUE;
606 continue;
607 }
608 }
609 else
610 {
611 ret = mUTF8ToUCS4Char(pc, 4, &code, &pc);
612 if(ret < 0) break;
613 if(ret > 0) continue;
614 }
615
616 //
617
618 glyph = mFreeTypeGetBitmapGlyph(ftlib, pfont->face, &pfont->info, code);
619
620 if(glyph)
621 {
622 w += glyph->root.advance.x >> 16;
623
624 FT_Done_Glyph((FT_Glyph)glyph);
625 }
626 else
627 w += 8;
628 }
629
630 return w;
631 }
632
633 /** テキストの幅取得 (UCS-4) */
634
mFontGetTextWidthUCS4(mFont * font,const uint32_t * text,int len)635 int mFontGetTextWidthUCS4(mFont *font,const uint32_t *text,int len)
636 {
637 __mFontFt *pfont;
638 int i,w = 0;
639 FT_Library ftlib;
640 FT_BitmapGlyph glyph;
641
642 if(!text) return 0;
643
644 ftlib = mGetFreeTypeLib();
645 pfont = _FONT(font);
646
647 for(i = 0; *text; text++, i++)
648 {
649 if(len >= 0 && i >= len) break;
650
651 glyph = mFreeTypeGetBitmapGlyph(ftlib, pfont->face, &pfont->info, *text);
652
653 if(glyph)
654 {
655 w += glyph->root.advance.x >> 16;
656
657 FT_Done_Glyph((FT_Glyph)glyph);
658 }
659 else
660 w += 8;
661 }
662
663 return w;
664 }
665
666 /** UCS-4 の1文字の幅取得 */
667
mFontGetCharWidthUCS4(mFont * font,uint32_t ucs)668 int mFontGetCharWidthUCS4(mFont *font,uint32_t ucs)
669 {
670 FT_BitmapGlyph glyph;
671 int w;
672
673 glyph = mFreeTypeGetBitmapGlyph(mGetFreeTypeLib(), _FONT(font)->face, &_FONT(font)->info, ucs);
674
675 if(glyph)
676 {
677 w = glyph->root.advance.x >> 16;
678
679 FT_Done_Glyph((FT_Glyph)glyph);
680 }
681 else
682 w = 8;
683
684 return w;
685 }
686
687
688 /** @} */
689