1 #ifdef USEFREETYPE
2 
3 #include <unordered_map>
4 
5 namespace FTU
6 {
7 
8 	Mutex mutex;
9 	static int libState = -1;
10 	static FT_Library  library = 0;
11 
CheckLib()12 	inline bool CheckLib()
13 	{
14 		if ( libState < 0 )
15 		{
16 			libState = FT_Init_FreeType( &library ) ? 1 : 0;
17 		}
18 
19 		return libState == 0;
20 	}
21 
22 	struct CharInfo
23 	{
24 		bool isSpace;
25 		int pxWidth;
26 
CharInfoCharInfo27 		CharInfo( FT_GlyphSlotRec* p )
28 		{
29 			pxWidth = ( ( p->metrics.horiAdvance + 0x3F ) >> 6 );
30 			isSpace = !p->bitmap.buffer || p->bitmap.width <= 0 || p->bitmap.rows <= 0;
31 		};
CharInfoCharInfo32 		CharInfo() {}
33 	};
34 
35 
36 	//кэш изображений (битмапов)
37 	class ImCache
38 	{
39 		enum CONST { MAX_IMAGE_WIDTH = 640, MAX_IMAGE_HEIGHT = 480 };
40 
41 		struct NK
42 		{
43 			unsigned bg; //цвет фона
44 			unsigned fg; //цвет символа
45 			unicode_t ch; //символ
46 
operatorNK47 			std::size_t operator()( const NK& k ) const { return k.bg + k.fg + k.ch; }
48 
49 			bool operator == ( const NK& a ) const { return ch == a.ch && bg == a.bg && fg == a.fg; }
50 		};
51 
52 		struct XYWH
53 		{
54 			int x, y, w, h;
XYWHXYWH55 			XYWH() {}
XYWHXYWH56 			XYWH( int _x, int _y, int _w, int _h ): x( _x ), y( _y ), w( _w ), h( _h ) {}
SetXYWH57 			void Set( int _x, int _y, int _w, int _h ) { x = _x; y = _y; w = _w; h = _h; }
58 		};
59 
60 		struct Node
61 		{
62 			NK k;
63 			XYWH place;
64 		};
65 
66 		std::unordered_map<NK, Node, NK> nodesHash;
67 
68 		SCImage image;
69 		int xPos;
70 		int yPos;
71 		int cHeight;
72 
73 		Node* Alloc( unicode_t ch, unsigned bg, unsigned fg, int charW, int charH );
74 		void CopyArea( wal::GC& gc, Node* node, int x, int y );
75 
76 		void DrawImage( wal::GC& gc,  Image32& im, int x, int y );
77 
78 	public:
79 		ImCache();
80 		void Clear();
81 
82 		//нарисовать если есть в кэше
83 		bool DrawIfExist( wal::GC& gc, int x, int y, unicode_t ch, unsigned bg, unsigned fg );
84 
85 		//нарисовать и поместить в кэш если получится
86 		void Draw( wal::GC& gc, int x, int y, unicode_t ch, unsigned bg, unsigned fg, Image32& im );
87 
88 		~ImCache();
89 	};
90 
91 	struct ColorData   //чтоб не считать постоянно наложения цветов фона и текста
92 	{
93 		bool changed;
94 		unsigned bg;
95 		unsigned fg;
96 		unsigned colors[0x100];
97 		char bools[0x100];
98 
ColorDataColorData99 		ColorData(): changed( true ), bg( 0 ), fg( 0xFFFFFF ) {}
SetBgColorData100 		void SetBg( unsigned c ) { if ( c != bg ) { bg = c; changed = true; } }
SetFgColorData101 		void SetFg( unsigned c ) { if ( c != fg ) { fg = c; changed = true; } }
PrepareColorData102 		void Prepare() { if ( changed ) { memset( bools, 0, 0x100 ); changed = false;  } }
IsSetColorData103 		bool IsSet( int n ) { return bools[n]; }
GetColorData104 		unsigned Get( int n ) { return colors[n]; }
SetColorData105 		void Set( int n, unsigned c ) { bools[n] = 1; colors[n] = c; }
106 	};
107 
108 
109 	class FFace
110 	{
111 		FT_Face face;
112 		ColorData cData;
113 		ImCache imCache;
114 
115 		int pxAscender;
116 		int pxHeight;
117 		int _size;
118 
119 		std::unordered_map<unicode_t, CharInfo> ciHash;
120 
Clear()121 		void Clear() { if ( face )  { FT_Done_Face( face ); face = 0; imCache.Clear(); ciHash.clear(); } }
122 
123 		int SetSize( int size, int xRes, int yRes );
124 		bool MkImage( Image32& im, FT_GlyphSlot slot );
125 		void OutChar( wal::GC& gc, int* px, int* py, unicode_t c );
126 		void OutCharF( wal::GC& gc, int* px, int* py, unicode_t c );
127 
128 	public:
129 		FFace();
130 		int Load( const char* fileName, int index, int size, int xRes = 100, int yRes = 100 );
131 		void OutText( wal::GC& gc, int x, int y, const unicode_t* text, int count );
132 		void OutTextF( wal::GC& gc, int x, int y, const unicode_t* text, int count );
133 		cpoint GetTextExtents( const unicode_t* text, int count );
134 
Name()135 		const char* Name() { return face ? face->family_name : nullptr; }
StyleName()136 		const char* StyleName() { return face ? face->style_name : nullptr; }
FaceFlags()137 		unsigned FaceFlags() { return face ? face->face_flags : 0; }
StyleFlags()138 		unsigned StyleFlags() { return face ? face->style_flags : 0; }
Size()139 		int Size() { return _size; }
140 
PxHeight()141 		int PxHeight() { return pxHeight; }
142 		~FFace();
143 	};
144 
145 
146 
147 ////////////////////// ImCache //////////////////////////////////////////////////////////////////
148 
ImCache()149 	ImCache::ImCache(): xPos( 0 ), yPos( 0 ), cHeight( 0 ) {}
Clear()150 	void ImCache::Clear() { nodesHash.clear(); xPos = 0; yPos = 0; cHeight = 0; }
151 
CopyArea(wal::GC & gc,Node * p,int x,int y)152 	inline void  ImCache::CopyArea( wal::GC& gc, Node* p, int x, int y )
153 	{
154 		XCopyArea( display, image.GetXDrawable(), gc.GetXDrawable(), gc.XHandle(), p->place.x, p->place.y, p->place.w, p->place.h,  x, y );
155 	}
156 
DrawIfExist(wal::GC & gc,int x,int y,unicode_t ch,unsigned bg,unsigned fg)157 	bool ImCache::DrawIfExist( wal::GC& gc, int x, int y, unicode_t ch, unsigned bg, unsigned fg )
158 	{
159 		NK k;
160 		k.bg = bg;
161 		k.fg = fg;
162 		k.ch = ch;
163 
164 		const auto& i = nodesHash.find( k );
165 
166 		Node* p = ( i == nodesHash.end() ) ? nullptr : &(i->second);
167 
168 		if ( !p ) { return false; }
169 
170 		CopyArea( gc, p, x, y );
171 
172 		return true;
173 	}
174 
Alloc(unicode_t ch,unsigned bg,unsigned fg,int charW,int charH)175 	ImCache::Node* ImCache::Alloc( unicode_t ch, unsigned bg, unsigned fg, int charW, int charH )
176 	{
177 //return 0;
178 
179 		if ( charW >  MAX_IMAGE_WIDTH || charH > MAX_IMAGE_HEIGHT ) { return 0; }
180 
181 		if ( image.Width() - xPos < charW )
182 		{
183 			xPos = 0;
184 			yPos += cHeight;
185 			cHeight = 0;
186 		}
187 
188 		Node node;
189 		node.k.bg = bg;
190 		node.k.fg = fg;
191 		node.k.ch = ch;
192 
193 		if ( image.Width() - xPos >= charW && image.Height() - yPos >= charH )
194 		{
195 			node.place.Set( xPos, yPos, charW, charH );
196 			xPos += charW;
197 
198 			if ( cHeight < charH ) { cHeight = charH; }
199 
200 			return &(nodesHash[ node.k ] = node);
201 		}
202 
203 		nodesHash.clear();
204 
205 		int w = image.Width();
206 		int h = image.Height();
207 
208 		w = ( w ? ( w * 2 ) : ( 16 * charW ) );
209 		h = ( h ? ( h * 2 ) : charH * 2 );
210 
211 		if ( w > MAX_IMAGE_WIDTH ) { w = MAX_IMAGE_WIDTH; }
212 
213 		if ( h > MAX_IMAGE_HEIGHT ) { h = MAX_IMAGE_HEIGHT; }
214 
215 		if ( image.Width() != w || image.Height() != h )
216 		{
217 			image.Create( w, h );
218 		}
219 
220 		node.place.Set( 0, 0, charW, charH );
221 
222 		xPos = charW;
223 		yPos = 0;
224 		cHeight = charH;
225 
226 		return &(nodesHash[ node.k ] = node);
227 	}
228 
DrawImage(wal::GC & gc,Image32 & im,int x,int y)229 	inline void ImCache::DrawImage( wal::GC& gc, Image32& im, int x, int y )
230 	{
231 		IntXImage ximage( im );
232 		ximage.Put( gc, 0, 0, x, y, im.width(), im.height() );
233 	}
234 
235 
Draw(wal::GC & gc,int x,int y,unicode_t ch,unsigned bg,unsigned fg,Image32 & im)236 	void ImCache::Draw( wal::GC& gc, int x, int y, unicode_t ch, unsigned bg, unsigned fg, Image32& im )
237 	{
238 		Node* node = Alloc( ch, bg, fg, im.width(), im.height() );
239 
240 		if ( node )
241 		{
242 			wal::GC imageGC( &image );
243 			imageGC.SetFillColor( bg );
244 			DrawImage( imageGC, im, node->place.x, node->place.y );
245 			CopyArea( gc, node, x, y );
246 			return;
247 		}
248 
249 		DrawImage( gc, im, x, y );
250 		return;
251 	}
252 
~ImCache()253 	ImCache::~ImCache() {}
254 
255 
256 ////////////////////// FFace ///////////////////////////////////////////////////////////
257 
258 
FFace()259 	FFace::FFace(): face( 0 ), pxAscender( 0 ), pxHeight( 0 ), _size( 1 ) {}
~FFace()260 	FFace::~FFace() { if ( face ) { FT_Done_Face( face ); } }
261 
Load(const char * fileName,int index,int size,int xRes,int yRes)262 	int FFace::Load( const char* fileName, int index, int size, int xRes, int yRes )
263 	{
264 		MutexLock lock( &mutex );
265 
266 		if ( !CheckLib() ) { return 1; }
267 
268 		Clear();
269 		int e = FT_New_Face( library, fileName, index, &face );
270 
271 		if ( e ) { return e; }
272 
273 		e = SetSize( size, xRes, yRes );
274 
275 		if ( e ) { Clear(); return e; }
276 
277 		return 0;
278 	}
279 
SetSize(int size,int xRes,int yRes)280 	int FFace::SetSize( int size, int xRes, int yRes )
281 	{
282 		imCache.Clear();
283 		_size = 1;
284 		int e = FT_Set_Char_Size(
285 		           face,    /* handle to face object           */
286 		           0,       /* char_width in 1/64th of points  */
287 		           size,   /* char_height in 1/64th of points */
288 		           xRes,     /* horizontal device resolution    */
289 		           yRes ) ;   /* vertical device resolution  */
290 
291 		if ( !e && face && face->size )
292 		{
293 			pxAscender =  face->size->metrics.ascender >> 6;
294 			pxHeight = ( face->size->metrics.height + 0x3F ) >> 6;
295 
296 		}
297 		else
298 		{
299 			pxAscender = 0;
300 			pxHeight = 1;
301 		}
302 
303 		if ( !e ) { _size = size; }
304 
305 		return e;
306 	}
307 
308 //bg(1-a)+fg*a
fff(int bg,int fg,int a,int a1)309 	inline unsigned fff( int bg, int fg, int a, int a1 )
310 	{
311 		return ( ( ( bg & 0xFF ) * a1 + ( fg & 0xFF ) * a ) / 256 ) & 0xFF;
312 	}
313 
MkImage(Image32 & im,FT_GlyphSlot slot)314 	bool FFace::MkImage( Image32& im, FT_GlyphSlot slot )
315 	{
316 		if ( !slot->bitmap.buffer ) { return false; }
317 
318 
319 		int h = pxHeight;
320 		int w = ( ( slot->metrics.horiAdvance + 0x3F ) >> 6 );
321 
322 
323 		if ( w <= 0 || h <= 0 ) { return false; }
324 
325 		im.alloc( w, h );
326 
327 		unsigned bg = cData.bg;
328 		unsigned fg = cData.fg;
329 		cData.Prepare();
330 
331 		int left = slot->bitmap_left;
332 		int top = pxAscender - slot->bitmap_top - 1;
333 
334 		if ( top < 0 ) { top = 0; }
335 
336 		int bottom = top + slot->bitmap.rows;
337 		int right = left + slot->bitmap.width;
338 
339 		if ( top >= h || bottom <= 0 || left >= w || right <= 0 )
340 		{
341 			uint32_t* p = im.line( 0 );
342 
343 			for ( int cnt = w * h; cnt > 0; cnt--, p++ )
344 			{
345 				*p = bg;
346 			}
347 
348 			return true;
349 		}
350 
351 		int leftBgCount = ( left > 0 ) ? ( left > w ? w : left ) : 0;
352 		int rightBgCount = ( right < w ) ? w - right : 0;
353 		int bitmapOffset = left < 0 ? -left : 0;
354 
355 		if ( left < 0 ) { left = 0; }
356 
357 		if ( right > w ) { right = w; }
358 
359 		int bitmapN = right - left;
360 
361 
362 
363 
364 		for ( int i = 0; i < h; i++ )
365 		{
366 			uint32_t* dest = im.line( i );
367 
368 			if ( i < top || i >= bottom )
369 			{
370 				for ( int cnt = w; cnt > 0; cnt--, dest++ ) { *dest = bg; }
371 			}
372 			else
373 			{
374 				int n;
375 
376 				for ( n = leftBgCount ; n > 0; n--, dest++ ) { *dest = bg; }
377 
378 				unsigned char* s = slot->bitmap.buffer + ( i - top ) * slot->bitmap.width + bitmapOffset;
379 
380 				for ( n = bitmapN; n > 0; n--, dest++, s++ )
381 				{
382 					unsigned c = *s;
383 
384 					unsigned color;
385 
386 					if ( c >= 0xFF )
387 					{
388 						color = fg;
389 					}
390 					else if ( c <= 0 )
391 					{
392 						color = bg;
393 					}
394 					else if ( cData.IsSet( c ) )
395 					{
396 						color = cData.Get( c );
397 					}
398 					else
399 					{
400 						// bg(1-a)+fg*a
401 
402 						unsigned c1 = 255 - c;
403 
404 						/*
405 						color = fff(bg, fg , c, c1) +
406 						(fff(bg>>8, fg>>8, c, c1)<<8)+
407 						(fff(bg>>16, fg>>16, c, c1)<<16);
408 						*/
409 
410 
411 						color =
412 						   ( ( ( ( bg & 0x0000FF ) * c1 + ( fg & 0x0000FF ) * c ) >> 8 ) & 0x0000FF ) +
413 						   ( ( ( ( bg & 0x00FF00 ) * c1 + ( fg & 0x00FF00 ) * c ) >> 8 ) & 0x00FF00 ) +
414 						   ( ( ( ( bg & 0xFF0000 ) * c1 + ( fg & 0xFF0000 ) * c ) >> 8 ) & 0xFF0000 );
415 
416 
417 
418 						cData.Set( c, color );
419 					};
420 
421 					*dest = color;
422 				}
423 
424 				for ( n = rightBgCount ; n > 0; n--, dest++ ) { *dest = bg; }
425 			}
426 		}
427 
428 		return true;
429 	}
430 
431 
OutTextF(wal::GC & gc,int x,int y,const unicode_t * text,int count)432 	void FFace::OutTextF( wal::GC& gc, int x, int y, const  unicode_t* text, int count )
433 	{
434 		MutexLock lock( &mutex );
435 
436 		if ( !CheckLib() ) { return; }
437 
438 		if ( !face ) { return; }
439 
440 		if ( count < 0 ) { count = unicode_strlen( text ); }
441 
442 		for ( int i = 0; i < count; i++ )
443 		{
444 			OutCharF( gc, &x, &y, text[i] );
445 		}
446 	}
447 
OutText(wal::GC & gc,int x,int y,const unicode_t * text,int count)448 	void FFace::OutText( wal::GC& gc, int x, int y, const  unicode_t* text, int count )
449 	{
450 		MutexLock lock( &mutex );
451 
452 		if ( !CheckLib() ) { return; }
453 
454 		if ( !face ) { return; }
455 
456 		if ( count < 0 ) { count = unicode_strlen( text ); }
457 
458 		for ( int i = 0; i < count; i++ )
459 		{
460 			OutChar( gc, &x, &y, text[i] );
461 		}
462 	}
463 
GetSlot(FT_Face face,unicode_t * pc)464 	inline FT_GlyphSlot GetSlot( FT_Face face, unicode_t* pc )
465 	{
466 		if ( !face ) { return 0; }
467 
468 		FT_UInt  glyph_index = FT_Get_Char_Index( face, *pc );
469 
470 		if ( !glyph_index )
471 		{
472 			glyph_index = FT_Get_Char_Index( face, '.' );
473 
474 			if ( !glyph_index ) { return 0; }
475 
476 			*pc = '.';
477 		}
478 
479 		if ( FT_Load_Glyph( face, glyph_index, FT_LOAD_DEFAULT /*| FT_LOAD_TARGET_LIGHT*/ ) ) { return 0; }
480 
481 		if ( FT_Render_Glyph( face->glyph, /*FT_RENDER_MODE_LCD*/ FT_RENDER_MODE_NORMAL ) ) { return 0; }
482 
483 		return face->glyph;
484 	}
485 
486 
GetTextExtents(const unicode_t * text,int count)487 	cpoint FFace::GetTextExtents( const unicode_t* text, int count )
488 	{
489 		MutexLock lock( &mutex );
490 
491 		if ( !CheckLib() ) { return cpoint( 0, 0 ); }
492 
493 		if ( !face ) { return cpoint( 0, 0 ); }
494 
495 		if ( count < 0 ) { count = unicode_strlen( text ); }
496 
497 		int w = 0;
498 
499 		for ( int i = 0; i < count; i++, text++ )
500 		{
501 			auto iter = ciHash.find( *text );
502 
503 			CharInfo* pInfo = ( iter == ciHash.end() ) ? nullptr : &( iter->second );
504 
505 			if ( !pInfo )
506 			{
507 				unicode_t c = *text;
508 				FT_GlyphSlot  slot = GetSlot( face, &c );
509 
510 				if ( !slot ) { continue; }
511 
512 				CharInfo info( slot );
513 				ciHash[c] = info;
514 				pInfo = &( ciHash[c] );
515 			}
516 
517 			w += pInfo->pxWidth;
518 		};
519 
520 		return cpoint( w, PxHeight() );
521 	}
522 
OutCharF(wal::GC & gc,int * px,int * py,unicode_t c)523 	void FFace::OutCharF( wal::GC& gc, int* px, int* py, unicode_t c )
524 	{
525 		int bg = gc.FillRgb();
526 		int fg = gc.TextRgb();
527 
528 		auto i = ciHash.find( c );
529 
530 		CharInfo* pInfo = ( i == ciHash.end() ) ? nullptr : &( i->second );
531 
532 		if ( pInfo )
533 		{
534 			if ( imCache.DrawIfExist( gc, *px, *py , c, bg, fg ) )
535 			{
536 				*px += pInfo->pxWidth;
537 				return;
538 			}
539 		};
540 
541 		FT_GlyphSlot  slot = GetSlot( face, &c );
542 
543 		if ( !slot ) { return; }
544 
545 		if ( !pInfo )
546 		{
547 			CharInfo info( slot );
548 			pInfo = &( ciHash[c] = info );
549 		}
550 
551 		Image32 im;
552 		cData.SetBg( bg );
553 		cData.SetFg( fg );
554 
555 		if ( !MkImage( im, slot ) )
556 		{
557 			gc.FillRect( crect( *px, *py, *px + pInfo->pxWidth, *py + pxHeight ) );
558 			*px += pInfo->pxWidth;
559 			return;
560 		}
561 
562 		imCache.Draw( gc, *px, *py, c, bg, fg, im );
563 		*px += pInfo->pxWidth;
564 	}
565 
566 
OutChar(wal::GC & gc,int * px,int * py,unicode_t c)567 	void FFace::OutChar( wal::GC& gc, int* px, int* py, unicode_t c )
568 	{
569 		FT_GlyphSlot  slot = GetSlot( face, &c );
570 
571 		if ( !slot ) { return; }
572 
573 		int x = *px;
574 		int y = *py;
575 
576 		auto i = ciHash.find( c );
577 
578 		CharInfo* pInfo = ( i == ciHash.end() ) ? nullptr : &( i->second );
579 
580 		if ( !pInfo )
581 		{
582 			CharInfo info( slot );
583 			pInfo = &( ciHash[c] = info );
584 		}
585 
586 		*px += pInfo->pxWidth;
587 
588 		if ( !slot->bitmap.buffer )
589 		{
590 			return;
591 		}
592 
593 		int h = slot->bitmap.rows;
594 		int w = slot->bitmap.width;
595 		unsigned char* p = slot->bitmap.buffer;
596 
597 		int fg = gc.TextRgb();
598 
599 		int left = slot->bitmap_left;
600 		int top = pxAscender - slot->bitmap_top - 1;
601 
602 		if ( top < 0 ) { top = 0; }
603 
604 		for ( int i = 0; i < h; i++ )
605 			for ( int j = 0; j < w; j++, p++ )
606 			{
607 				unsigned c = *p;
608 
609 				if ( c >= 0x80 )
610 				{
611 					gc.SetPixel( x + j + left, y + i + top, fg );
612 				}
613 			}
614 	}
615 
616 
617 }; //namespace FTU
618 
GetFTFileInfo(const char * path)619 clPtr<cfont::FTInfo> cfont::GetFTFileInfo( const char* path )
620 {
621 	FTU::FFace f;
622 
623 	if ( f.Load( path, 0, 100 ) ) { return 0; }
624 
625 	clPtr<cfont::FTInfo> node = new cfont::FTInfo;
626 	node->name = f.Name();
627 	node->styleName = f.StyleName();
628 
629 	node->flags = 0;
630 
631 	if ( f.FaceFlags() & FT_FACE_FLAG_FIXED_WIDTH ) { node->flags |= cfont::FTInfo::FIXED_WIDTH; }
632 
633 
634 	return node;
635 }
636 
637 #endif
638