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