1 /*
2  * Copyright (c) 2001 Sasha Vasko <sasha at aftercode.net>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  */
18 #undef LOCAL_DEBUG
19 #undef DO_CLOCKING
20 
21 #ifdef _WIN32
22 #include "win32/config.h"
23 #else
24 #include "config.h"
25 #endif
26 
27 
28 #define DO_X11_ANTIALIASING
29 #define DO_2STEP_X11_ANTIALIASING
30 #define DO_3STEP_X11_ANTIALIASING
31 #define X11_AA_HEIGHT_THRESHOLD 10
32 #define X11_2STEP_AA_HEIGHT_THRESHOLD 15
33 #define X11_3STEP_AA_HEIGHT_THRESHOLD 15
34 
35 
36 #ifdef HAVE_UNISTD_H
37 #include <unistd.h>
38 #endif
39 #ifdef HAVE_STDLIB_H
40 #include <stdlib.h>
41 #endif
42 #ifdef HAVE_STDARG_H
43 #include <stdarg.h>
44 #endif
45 #include <ctype.h>
46 #include <string.h>
47 #include <stdio.h>
48 #ifdef DO_CLOCKING
49 #if TIME_WITH_SYS_TIME
50 # include <sys/time.h>
51 # include <time.h>
52 #else
53 # if HAVE_SYS_TIME_H
54 #  include <sys/time.h>
55 # else
56 #  include <time.h>
57 # endif
58 #endif
59 #endif
60 
61 #ifdef HAVE_FREETYPE
62 # ifdef HAVE_FT2BUILD_H
63 #  include <ft2build.h>
64 #  include FT_FREETYPE_H
65 # endif
66 # ifdef HAVE_FREETYPE_FREETYPE
67 #  include <freetype/freetype.h>
68 # else
69 #  include <freetype.h>
70 # endif
71 # if (FREETYPE_MAJOR == 2) && ((FREETYPE_MINOR == 0) || ((FREETYPE_MINOR == 1) && (FREETYPE_PATCH < 3)))
72 #  define FT_KERNING_DEFAULT ft_kerning_default
73 # endif
74 #endif
75 
76 #define INCLUDE_ASFONT_PRIVATE
77 
78 #ifdef _WIN32
79 # include "win32/afterbase.h"
80 #else
81 # include "afterbase.h"
82 #endif
83 #include "asfont.h"
84 #include "asimage.h"
85 #include "asvisual.h"
86 
87 #ifdef HAVE_XRENDER
88 #include <X11/extensions/Xrender.h>
89 #endif
90 
91 #undef MAX_GLYPHS_PER_FONT
92 
93 
94 /*********************************************************************************/
95 /* TrueType and X11 font management functions :   								 */
96 /*********************************************************************************/
97 
98 /*********************************************************************************/
99 /* construction destruction miscelanea:			   								 */
100 /*********************************************************************************/
101 
102 void asfont_destroy (ASHashableValue value, void *data);
103 
104 ASFontManager *
create_font_manager(Display * dpy,const char * font_path,ASFontManager * reusable_memory)105 create_font_manager( Display *dpy, const char * font_path, ASFontManager *reusable_memory )
106 {
107 	ASFontManager *fontman = reusable_memory;
108 	if( fontman == NULL )
109 		fontman = safecalloc( 1, sizeof(ASFontManager));
110 	else
111 		memset( fontman, 0x00, sizeof(ASFontManager));
112 
113 	fontman->dpy = dpy ;
114 	if( font_path )
115 		fontman->font_path = mystrdup( font_path );
116 
117 #ifdef HAVE_FREETYPE
118 	if( !FT_Init_FreeType( &(fontman->ft_library)) )
119 		fontman->ft_ok = True ;
120 	else
121 		show_error( "Failed to initialize FreeType library - TrueType Fonts support will be disabled!");
122 LOCAL_DEBUG_OUT( "Freetype library is %p", fontman->ft_library );
123 #endif
124 
125 	fontman->fonts_hash = create_ashash( 7, string_hash_value, string_compare, asfont_destroy );
126 
127 	return fontman;
128 }
129 
130 void
destroy_font_manager(ASFontManager * fontman,Bool reusable)131 destroy_font_manager( ASFontManager *fontman, Bool reusable )
132 {
133 	if( fontman )
134 	{
135 
136         destroy_ashash( &(fontman->fonts_hash) );
137 
138 #ifdef HAVE_FREETYPE
139 		FT_Done_FreeType( fontman->ft_library);
140 		fontman->ft_ok = False ;
141 #endif
142 		if( fontman->font_path )
143 			free( fontman->font_path );
144 
145 		if( !reusable )
146 			free( fontman );
147 		else
148 			memset( fontman, 0x00, sizeof(ASFontManager));
149 	}
150 }
151 
152 #ifdef HAVE_FREETYPE
153 static int load_freetype_glyphs( ASFont *font );
154 #endif
155 #ifndef X_DISPLAY_MISSING
156 static int load_X11_glyphs( Display *dpy, ASFont *font, XFontStruct *xfs );
157 #endif
158 
159 
160 static ASFont*
open_freetype_font_int(ASFontManager * fontman,const char * font_string,int face_no,int size,Bool verbose,ASFlagType flags)161 open_freetype_font_int( ASFontManager *fontman, const char *font_string, int face_no, int size, Bool verbose, ASFlagType flags)
162 {
163 	ASFont *font = NULL ;
164 #ifdef HAVE_FREETYPE
165 	if( fontman && fontman->ft_ok )
166 	{
167 		char *realfilename;
168 		FT_Face face ;
169 		LOCAL_DEBUG_OUT( "looking for \"%s\" in \"%s\"", font_string, fontman->font_path );
170 		if( (realfilename = find_file( font_string, fontman->font_path, R_OK )) == NULL )
171 		{/* we might have face index specifier at the end of the filename */
172 			char *tmp = mystrdup( font_string );
173 			register int i = 0;
174 			while(tmp[i] != '\0' ) ++i ;
175 			while( --i >= 0 )
176 				if( !isdigit( tmp[i] ) )
177 				{
178 					if( tmp[i] == '.' )
179 					{
180 						face_no = atoi( &tmp[i+1] );
181 						tmp[i] = '\0' ;
182 					}
183 					break;
184 				}
185 			if( i >= 0 && font_string[i] != '\0' )
186 				realfilename = find_file( tmp, fontman->font_path, R_OK );
187 			free( tmp );
188 		}
189 
190 		if( realfilename )
191 		{
192 			face = NULL ;
193 LOCAL_DEBUG_OUT( "font file found : \"%s\", trying to load face #%d, using library %p", realfilename, face_no, fontman->ft_library );
194 			if( FT_New_Face( fontman->ft_library, realfilename, face_no, &face ) )
195 			{
196 LOCAL_DEBUG_OUT( "face load failed.%s", "" );
197 
198 				if( face_no  > 0  )
199 				{
200 					show_warning( "face %d is not available in font \"%s\" - falling back to first available.", face_no, realfilename );
201 					FT_New_Face( fontman->ft_library, realfilename, 0, &face );
202 				}
203 			}
204 LOCAL_DEBUG_OUT( "face found : %p", face );
205 			if( face != NULL )
206 			{
207 #ifdef MAX_GLYPHS_PER_FONT
208 				if( face->num_glyphs >  MAX_GLYPHS_PER_FONT )
209 					show_error( "Font \"%s\" contains too many glyphs - %d. Max allowed is %d", realfilename, face->num_glyphs, MAX_GLYPHS_PER_FONT );
210 				else
211 #endif
212 				{
213 					font = safecalloc( 1, sizeof(ASFont));
214 					font->magic = MAGIC_ASFONT ;
215 					font->fontman = fontman;
216 					font->type = ASF_Freetype ;
217 					font->flags = flags ;
218 					font->ft_face = face ;
219 					if( FT_HAS_KERNING( face ) )
220 					{
221 						set_flags( font->flags, ASF_HasKerning );
222 						/* fprintf( stderr, "@@@@@@@font %s has kerning!!!\n", realfilename );*/
223 					}/*else
224 						fprintf( stderr, "@@@@@@@font %s don't have kerning!!!\n", realfilename ); */
225 					/* lets confine the font to square cell */
226 					FT_Set_Pixel_Sizes( font->ft_face, size, size );
227 					/* but let make our own cell width smaller then height */
228 					font->space_size = size*2/3 ;
229 	   				load_freetype_glyphs( font );
230 				}
231 			}else if( verbose )
232 				show_error( "FreeType library failed to load font \"%s\"", realfilename );
233 
234 			if( realfilename != font_string )
235 				free( realfilename );
236 		}
237 	}
238 #endif
239 	return font;
240 }
241 
242 ASFont*
open_freetype_font(ASFontManager * fontman,const char * font_string,int face_no,int size,Bool verbose)243 open_freetype_font( ASFontManager *fontman, const char *font_string, int face_no, int size, Bool verbose)
244 {
245 	return open_freetype_font_int( fontman, font_string, face_no, size, verbose, 0);
246 }
247 
248 static ASFont*
open_X11_font_int(ASFontManager * fontman,const char * font_string,ASFlagType flags)249 open_X11_font_int( ASFontManager *fontman, const char *font_string, ASFlagType flags)
250 {
251 	ASFont *font = NULL ;
252 #ifndef X_DISPLAY_MISSING
253 /*
254     #ifdef I18N
255      TODO: we have to use FontSet and loop through fonts instead filling
256            up 2 bytes per character table with glyphs
257     #else
258 */
259     /* for now assume ISO Latin 1 encoding */
260 	XFontStruct *xfs ;
261 	if( fontman->dpy == NULL )
262 		return NULL;
263 	if( (xfs = XLoadQueryFont( fontman->dpy, font_string )) == NULL )
264 	{
265 		show_warning( "failed to load X11 font \"%s\". Sorry about that.", font_string );
266 		return NULL;
267 	}
268 	font = safecalloc( 1, sizeof(ASFont));
269 	font->magic = MAGIC_ASFONT ;
270 	font->fontman = fontman;
271 	font->type = ASF_X11 ;
272 	font->flags = flags ;
273 	load_X11_glyphs( fontman->dpy, font, xfs );
274 	XFreeFont( fontman->dpy, xfs );
275 #endif /* #ifndef X_DISPLAY_MISSING */
276 	return font;
277 }
278 
279 ASFont*
open_X11_font(ASFontManager * fontman,const char * font_string)280 open_X11_font( ASFontManager *fontman, const char *font_string)
281 {
282 	return open_X11_font_int( fontman, font_string, 0);
283 }
284 
285 ASFont*
get_asfont(ASFontManager * fontman,const char * font_string,int face_no,int size,ASFontType type_and_flags)286 get_asfont( ASFontManager *fontman, const char *font_string, int face_no, int size, ASFontType type_and_flags )
287 {
288 	ASFont *font = NULL ;
289 	Bool freetype = False ;
290 	int type = type_and_flags&ASF_TypeMask ;
291 	if( face_no >= 100 )
292 		face_no = 0 ;
293 	if( size >= 1000 )
294 		size = 999 ;
295 
296 	if( fontman && font_string )
297 	{
298 		ASHashData hdata = { 0 };
299 		if( get_hash_item( fontman->fonts_hash, AS_HASHABLE((char*)font_string), &hdata.vptr) != ASH_Success )
300 		{
301 			char *ff_name ;
302 			int len = strlen( font_string)+1 ;
303 			len += ((size>=100)?3:2)+1 ;
304 			len += ((face_no>=10)?2:1)+1 ;
305 			ff_name = safemalloc( len );
306 			sprintf( ff_name, "%s$%d$%d", font_string, size, face_no );
307 			if( get_hash_item( fontman->fonts_hash, AS_HASHABLE((char*)ff_name), &hdata.vptr) != ASH_Success )
308 			{	/* not loaded just yet - lets do it :*/
309 				if( type == ASF_Freetype || type == ASF_GuessWho )
310 					font = open_freetype_font_int( fontman, font_string, face_no, size, (type == ASF_Freetype), get_flags(type_and_flags,~ASF_TypeMask));
311 				if( font == NULL && type != ASF_Freetype )
312 				{/* don't want to try and load font as X11 unless requested to do so */
313 					font = open_X11_font_int( fontman, font_string, get_flags(type_and_flags,~ASF_TypeMask) );
314 				}else
315 					freetype = True ;
316 				if( font != NULL )
317 				{
318 					if( freetype )
319 					{
320 						font->name = ff_name ;
321 						ff_name = NULL ;
322 					}else
323 						font->name = mystrdup( font_string );
324 					add_hash_item( fontman->fonts_hash, AS_HASHABLE((char*)font->name), font);
325 				}
326 			}
327 			if( ff_name != NULL )
328 				free( ff_name );
329 		}
330 
331 		if( font == NULL )
332 			font = hdata.vptr ;
333 
334 		if( font )
335 			font->ref_count++ ;
336 	}
337 	return font;
338 }
339 
340 ASFont*
dup_asfont(ASFont * font)341 dup_asfont( ASFont *font )
342 {
343 	if( font && font->fontman )
344 		font->ref_count++ ;
345 	else
346 		font = NULL;
347 	return font;
348 }
349 
350 int
release_font(ASFont * font)351 release_font( ASFont *font )
352 {
353 	int res = -1 ;
354 	if( font )
355 	{
356 		if( font->magic == MAGIC_ASFONT )
357 		{
358 			if( --(font->ref_count) < 0 )
359 			{
360 				ASFontManager *fontman = font->fontman ;
361 				if( fontman )
362 					remove_hash_item(fontman->fonts_hash, (ASHashableValue)(char*)font->name, NULL, True);
363 			}else
364 				res = font->ref_count ;
365 		}
366 	}
367 	return res ;
368 }
369 
370 static inline void
free_glyph_data(register ASGlyph * asg)371 free_glyph_data( register ASGlyph *asg )
372 {
373     if( asg->pixmap )
374         free( asg->pixmap );
375 /*fprintf( stderr, "\t\t%p\n", asg->pixmap );*/
376     asg->pixmap = NULL ;
377 }
378 
379 static void
destroy_glyph_range(ASGlyphRange ** pgr)380 destroy_glyph_range( ASGlyphRange **pgr )
381 {
382 	ASGlyphRange *gr = *pgr;
383 	if( gr )
384 	{
385 		*pgr = gr->above ;
386         if( gr->below )
387 			gr->below->above = gr->above ;
388         if( gr->above )
389 			gr->above->below = gr->below ;
390         if( gr->glyphs )
391 		{
392             int max_i = ((int)gr->max_char-(int)gr->min_char)+1 ;
393             register int i = -1 ;
394 /*fprintf( stderr, " max_char = %d, min_char = %d, i = %d", gr->max_char, gr->min_char, max_i);*/
395             while( ++i < max_i )
396             {
397 /*fprintf( stderr, "%d >", i );*/
398 				free_glyph_data( &(gr->glyphs[i]) );
399             }
400             free( gr->glyphs );
401 			gr->glyphs = NULL ;
402 		}
403 		free( gr );
404 	}
405 }
406 
407 static void
destroy_font(ASFont * font)408 destroy_font( ASFont *font )
409 {
410 	if( font )
411 	{
412 #ifdef HAVE_FREETYPE
413         if( font->type == ASF_Freetype && font->ft_face )
414 			FT_Done_Face(font->ft_face);
415 #endif
416         if( font->name )
417 			free( font->name );
418         while( font->codemap )
419 			destroy_glyph_range( &(font->codemap) );
420         free_glyph_data( &(font->default_glyph) );
421         if( font->locale_glyphs )
422 			destroy_ashash( &(font->locale_glyphs) );
423         font->magic = 0 ;
424 		free( font );
425 	}
426 }
427 
428 void
asglyph_destroy(ASHashableValue value,void * data)429 asglyph_destroy (ASHashableValue value, void *data)
430 {
431 	if( data )
432 	{
433 		free_glyph_data( (ASGlyph*)data );
434 		free( data );
435 	}
436 }
437 
438 void
asfont_destroy(ASHashableValue value,void * data)439 asfont_destroy (ASHashableValue value, void *data)
440 {
441 	if( data )
442 	{
443 	    char* cval = (char*)value ;
444         if( ((ASMagic*)data)->magic == MAGIC_ASFONT )
445         {
446             if( cval == ((ASFont*)data)->name )
447                 cval = NULL ;          /* name is freed as part of destroy_font */
448 /*              fprintf( stderr,"freeing font \"%s\"...", (char*) value ); */
449               destroy_font( (ASFont*)data );
450 /*              fprintf( stderr,"   done.\n"); */
451         }
452         if( cval )
453             free( cval );
454     }
455 }
456 
457 /*************************************************************************/
458 /* Low level bitmap handling - compression and antialiasing              */
459 /*************************************************************************/
460 
461 static unsigned char *
compress_glyph_pixmap(unsigned char * src,unsigned char * buffer,unsigned int width,unsigned int height,int src_step)462 compress_glyph_pixmap( unsigned char *src, unsigned char *buffer,
463                        unsigned int width, unsigned int height,
464 					   int src_step )
465 {
466 	unsigned char *pixmap ;
467 	register unsigned char *dst = buffer ;
468 	register int k = 0, i = 0 ;
469 	int count = -1;
470 	unsigned char last = src[0];
471 /* new way: if its FF we encode it as 01rrrrrr where rrrrrr is repitition count
472  * if its 0 we encode it as 00rrrrrr. Any other symbol we bitshift right by 1
473  * and then store it as 1sssssss where sssssss are topmost sugnificant bits.
474  * Note  - single FFs and 00s are encoded as any other character. Its been noted
475  * that in 99% of cases 0 or FF repeats, and very seldom anything else repeats
476  */
477 	while ( height)
478 	{
479 		if( src[k] != last || (last != 0 && last != 0xFF) || count >= 63 )
480 		{
481 			if( count == 0 )
482 				dst[i++] = (last>>1)|0x80;
483 			else if( count > 0 )
484 			{
485 				if( last == 0xFF )
486 					count |= 0x40 ;
487 				dst[i++] = count;
488 				count = 0 ;
489 			}else
490 				count = 0 ;
491 			last = src[k] ;
492 		}else
493 		 	count++ ;
494 /*fprintf( stderr, "%2.2X ", src[k] ); */
495 		if( ++k >= (int)width )
496 		{
497 /*			fputc( '\n', stderr ); */
498 			--height ;
499 			k = 0 ;
500 			src += src_step ;
501 		}
502 	}
503 	if( count == 0 )
504 		dst[i++] = (last>>1)|0x80;
505 	else
506 	{
507 		if( last == 0xFF )
508 			count |= 0x40 ;
509 		dst[i++] = count;
510 	}
511     pixmap  = safemalloc( i/*+(32-(i&0x01F) )*/);
512 /*fprintf( stderr, "pixmap alloced %p size %d(%d)", pixmap, i, i+(32-(i&0x01F) )); */
513 	memcpy( pixmap, buffer, i );
514 
515 	return pixmap;
516 }
517 
518 #ifdef DO_X11_ANTIALIASING
519 void
antialias_glyph(unsigned char * buffer,unsigned int width,unsigned int height)520 antialias_glyph( unsigned char *buffer, unsigned int width, unsigned int height )
521 {
522 	unsigned char *row1, *row2 ;
523 	register unsigned char *row ;
524 	register int x;
525 	int y;
526 
527 	row1 = &(buffer[0]);
528 	row = &(buffer[width]);
529 	row2 = &(buffer[width+width]);
530 	for( x = 1 ; x < (int)width-1 ; x++ )
531 		if( row1[x] == 0 )
532 		{/* antialiasing here : */
533 			unsigned int c = (unsigned int)row[x]+
534 							(unsigned int)row1[x-1]+
535 							(unsigned int)row1[x+1];
536 			if( c >= 0x01FE )  /* we cut off secondary aliases */
537 				row1[x] = c>>2;
538 		}
539 	for( y = 1 ; y < (int)height-1 ; y++ )
540 	{
541 		if( row[0] == 0 )
542 		{/* antialiasing here : */
543 			unsigned int c = (unsigned int)row1[0]+
544 							(unsigned int)row[1]+
545 							(unsigned int)row2[0];
546 			if( c >= 0x01FE )  /* we cut off secondary aliases */
547 				row[0] = c>>2;
548 		}
549 		for( x = 1 ; x < (int)width-1 ; x++ )
550 		{
551 			if( row[x] == 0 )
552 			{/* antialiasing here : */
553 				unsigned int c = (unsigned int)row1[x]+
554 								(unsigned int)row[x-1]+
555 								(unsigned int)row[x+1]+
556 								(unsigned int)row2[x];
557 				if( row1[x] != 0 && row[x-1] != 0 && row[x+1] != 0 && row2[x] != 0 &&
558 					c >= 0x01FE )
559 					row[x] = c>>3;
560 				else if( c >= 0x01FE )  /* we cut off secondary aliases */
561 					row[x] = c>>2;
562 			}
563 		}
564 		if( row[x] == 0 )
565 		{/* antialiasing here : */
566 			unsigned int c = (unsigned int)row1[x]+
567 							(unsigned int)row[x-1]+
568 							(unsigned int)row2[x];
569 			if( c >= 0x01FE )  /* we cut off secondary aliases */
570 				row[x] = c>>2;
571 		}
572 		row  += width ;
573 		row1 += width ;
574 		row2 += width ;
575 	}
576 	for( x = 1 ; x < (int)width-1 ; x++ )
577 		if( row[x] == 0 )
578 		{/* antialiasing here : */
579 			unsigned int c = (unsigned int)row1[x]+
580 							(unsigned int)row[x-1]+
581 							(unsigned int)row[x+1];
582 			if( c >= 0x01FE )  /* we cut off secondary aliases */
583 				row[x] = c>>2;
584 		}
585 #ifdef DO_2STEP_X11_ANTIALIASING
586 	if( height  > X11_2STEP_AA_HEIGHT_THRESHOLD )
587 	{
588 		row1 = &(buffer[0]);
589 		row = &(buffer[width]);
590 		row2 = &(buffer[width+width]);
591 		for( y = 1 ; y < (int)height-1 ; y++ )
592 		{
593 			for( x = 1 ; x < (int)width-1 ; x++ )
594 			{
595 				if( row[x] == 0 )
596 				{/* antialiasing here : */
597 					unsigned int c = (unsigned int)row1[x]+
598 									(unsigned int)row[x-1]+
599 									(unsigned int)row[x+1]+
600 									(unsigned int)row2[x];
601 					if( row1[x] != 0 && row[x-1] != 0 && row[x+1] != 0 && row2[x] != 0
602 						&& c >= 0x00FF+0x007F)
603 						row[x] = c>>3;
604 					else if( (c >= 0x00FF+0x007F)|| c == 0x00FE )  /* we cut off secondary aliases */
605 						row[x] = c>>2;
606 				}
607 			}
608 			row  += width ;
609 			row1 += width ;
610 			row2 += width ;
611 		}
612 	}
613 #endif
614 #ifdef DO_3STEP_X11_ANTIALIASING
615 	if( height  > X11_3STEP_AA_HEIGHT_THRESHOLD )
616 	{
617 		row1 = &(buffer[0]);
618 		row = &(buffer[width]);
619 		row2 = &(buffer[width+width]);
620 		for( y = 1 ; y < (int)height-1 ; y++ )
621 		{
622 			for( x = 1 ; x < (int)width-1 ; x++ )
623 			{
624 				if( row[x] == 0xFF )
625 				{/* antialiasing here : */
626 					if( row1[x] < 0xFE || row2[x] < 0xFE )
627 						if( row[x+1] < 0xFE || row[x-1] < 0xFE )
628 							row[x] = 0xFE;
629 				}
630 			}
631 			row  += width ;
632 			row1 += width ;
633 			row2 += width ;
634 		}
635 		row = &(buffer[width]);
636 		for( y = 1 ; y < (int)height-1 ; y++ )
637 		{
638 			for( x = 1 ; x < (int)width-1 ; x++ )
639 				if( row[x] == 0xFE )
640 					row[x] = 0xBF ;
641 			row  += width ;
642 		}
643 	}
644 
645 #endif
646 }
647 #endif
648 
649 static void
scale_down_glyph_width(unsigned char * buffer,int from_width,int to_width,int height)650 scale_down_glyph_width( unsigned char *buffer, int from_width, int to_width, int height )
651 {
652     int smaller = to_width;
653     int bigger  = from_width;
654 	register int i = 0, k = 0, l;
655 	/*fprintf( stderr, "scaling glyph down from %d to %d\n", from_width, to_width );*/
656     /* LOCAL_DEBUG_OUT( "smaller %d, bigger %d, eps %d", smaller, bigger, eps ); */
657     /* now using Bresengham algoritm to fiill the scales :
658 	 * since scaling is merely transformation
659 	 * from 0:bigger space (x) to 0:smaller space(y)*/
660 	for( l = 0 ; l < height ; ++l )
661 	{
662 		unsigned char *ptr = &(buffer[l*from_width]) ;
663 		CARD32 sum = 0;
664 		int count = 0 ;
665 		int eps = -bigger/2;
666 
667 		k = 0 ;
668 		for ( i = 0 ; i < bigger ; i++ )
669 		{
670 			/* add next elem here */
671 			sum += (unsigned int)ptr[i] ;
672 			++count ;
673 			eps += smaller;
674 
675 			if( eps+eps >= bigger )
676 			{
677 				/* divide here */
678 				/*fprintf( stderr, "i=%d, k=%d, sum=%d, count=%d\n", i, k, sum, count );*/
679 				ptr[k] = ( count > 1 )?sum/count:sum ;
680 				sum = 0 ;
681 				count = 0 ;
682 				++k ;
683 				eps -= bigger ;
684 			}
685 		}
686 	}
687 	/* now we need to compress the pixmap */
688 
689 	l = to_width ;
690 	k = from_width ;
691 	do
692 	{
693 		for( i = 0 ; i < to_width; ++i )
694 			buffer[l+i] = buffer[k+i];
695 		l += to_width ;
696 		k += from_width ;
697 	}while( l < to_width*height );
698 }
699 
700 
701 
702 /*********************************************************************************/
703 /* encoding/locale handling						   								 */
704 /*********************************************************************************/
705 
706 /* Now, this is the mess, I know :
707  * Internally we store everything in current locale;
708  * WE then need to convert it into Unicode 4 byte codes
709  *
710  * TODO: think about incoming data - does it has to be made local friendly ???
711  * Definately
712  */
713 
714 #ifndef X_DISPLAY_MISSING
715 static ASGlyphRange*
split_X11_glyph_range(unsigned int min_char,unsigned int max_char,XCharStruct * chars)716 split_X11_glyph_range( unsigned int min_char, unsigned int max_char, XCharStruct *chars )
717 {
718 	ASGlyphRange *first = NULL, **r = &first;
719     int c = 0, delta = (max_char-min_char)+1;
720 LOCAL_DEBUG_CALLER_OUT( "min_char = %u, max_char = %u, chars = %p", min_char, max_char, chars );
721 	while( c < delta )
722 	{
723 		while( c < delta && chars[c].width == 0 ) ++c;
724 
725 		if( c < delta )
726 		{
727 			*r = safecalloc( 1, sizeof(ASGlyphRange));
728 			(*r)->min_char = c+min_char ;
729 			while( c < delta && chars[c].width  != 0 ) ++c ;
730 			(*r)->max_char = (c-1)+min_char;
731 LOCAL_DEBUG_OUT( "created glyph range from %lu to %lu", (*r)->min_char, (*r)->max_char );
732 			r = &((*r)->above);
733 		}
734 	}
735 	return first;
736 }
737 
738 void
load_X11_glyph_range(Display * dpy,ASFont * font,XFontStruct * xfs,size_t char_offset,unsigned char byte1,unsigned char min_byte2,unsigned char max_byte2,GC * gc)739 load_X11_glyph_range( Display *dpy, ASFont *font, XFontStruct *xfs, size_t char_offset,
740 													  unsigned char byte1,
741                                                       unsigned char min_byte2,
742 													  unsigned char max_byte2, GC *gc )
743 {
744 	ASGlyphRange  *all, *r ;
745 	unsigned long  min_char = (byte1<<8)|min_byte2;
746 	unsigned char *buffer, *compressed_buf ;
747 	unsigned int   height = xfs->ascent+xfs->descent ;
748 	static XGCValues gcv;
749 
750 	buffer = safemalloc( xfs->max_bounds.width*height*2);
751 	compressed_buf = safemalloc( xfs->max_bounds.width*height*4);
752 	all = split_X11_glyph_range( min_char, (byte1<<8)|max_byte2, &(xfs->per_char[char_offset]));
753 	for( r = all ; r != NULL ; r = r->above )
754 	{
755 		XCharStruct *chars = &(xfs->per_char[char_offset+r->min_char-min_char]);
756         int len = ((int)r->max_char-(int)r->min_char)+1;
757 		unsigned char char_base = r->min_char&0x00FF;
758 		register int i ;
759 		Pixmap p;
760 		XImage *xim;
761 		unsigned int total_width = 0 ;
762 		int pen_x = 0;
763 LOCAL_DEBUG_OUT( "loading glyph range of %lu-%lu", r->min_char, r->max_char );
764 		r->glyphs = safecalloc( len, sizeof(ASGlyph) );
765 		for( i = 0 ; i < len ; i++ )
766 		{
767 			int w = chars[i].rbearing - chars[i].lbearing ;
768 			r->glyphs[i].lead = chars[i].lbearing ;
769 			r->glyphs[i].width = MAX(w,(int)chars[i].width) ;
770 			r->glyphs[i].step = chars[i].width;
771 			total_width += r->glyphs[i].width ;
772 			if( chars[i].lbearing > 0 )
773 				total_width += chars[i].lbearing ;
774 		}
775 		p = XCreatePixmap( dpy, DefaultRootWindow(dpy), total_width, height, 1 );
776 		if( *gc == NULL )
777 		{
778 			gcv.font = xfs->fid;
779 			gcv.foreground = 1;
780 			*gc = XCreateGC( dpy, p, GCFont|GCForeground, &gcv);
781 		}else
782 			XSetForeground( dpy, *gc, 1 );
783 		XFillRectangle( dpy, p, *gc, 0, 0, total_width, height );
784 		XSetForeground( dpy, *gc, 0 );
785 
786 		for( i = 0 ; i < len ; i++ )
787 		{
788 			XChar2b test_char ;
789 			int offset = MIN(0,(int)chars[i].lbearing);
790 
791 			test_char.byte1 = byte1 ;
792 			test_char.byte2 = char_base+i ;
793 			/* we cannot draw string at once since in some fonts charcters may
794 			 * overlap each other : */
795 			XDrawImageString16( dpy, p, *gc, pen_x-offset, xfs->ascent, &test_char, 1 );
796 			pen_x += r->glyphs[i].width ;
797 			if( chars[i].lbearing > 0 )
798 				pen_x += chars[i].lbearing ;
799 		}
800 		/*XDrawImageString( dpy, p, *gc, 0, xfs->ascent, test_str_char, len );*/
801 		xim = XGetImage( dpy, p, 0, 0, total_width, height, 0xFFFFFFFF, ZPixmap );
802 		XFreePixmap( dpy, p );
803 		pen_x = 0 ;
804 		for( i = 0 ; i < len ; i++ )
805 		{
806 			register int x, y ;
807 			int width = r->glyphs[i].width;
808 			unsigned char *row = &(buffer[0]);
809 
810 			if( chars[i].lbearing > 0 )
811 				pen_x += chars[i].lbearing ;
812 			for( y = 0 ; y < height ; y++ )
813 			{
814 				for( x = 0 ; x < width ; x++ )
815 				{
816 /*					fprintf( stderr, "glyph %d (%c): (%d,%d) 0x%X\n", i, (char)(i+r->min_char), x, y, XGetPixel( xim, pen_x+x, y ));*/
817 					/* remember default GC colors are black on white - 0 on 1 - and we need
818 					* quite the opposite - 0xFF on 0x00 */
819 					row[x] = ( XGetPixel( xim, pen_x+x, y ) != 0 )? 0x00:0xFF;
820 				}
821 				row += width;
822 			}
823 
824 #ifdef DO_X11_ANTIALIASING
825 			if( height > X11_AA_HEIGHT_THRESHOLD )
826 				antialias_glyph( buffer, width, height );
827 #endif
828 			if( get_flags( font->flags, ASF_Monospaced ) )
829 			{
830 				if( r->glyphs[i].lead > 0 && (int)width + (int)r->glyphs[i].lead > (int)font->space_size )
831 					if( r->glyphs[i].lead > (int)font->space_size/8 )
832 						r->glyphs[i].lead = (int)font->space_size/8 ;
833 				if( (int)width + r->glyphs[i].lead > (int)font->space_size )
834 				{
835 					r->glyphs[i].width = (int)font->space_size - r->glyphs[i].lead ;
836 /*					fprintf(stderr, "lead = %d, space_size = %d, width = %d, to_width = %d\n",
837 							r->glyphs[i].lead, font->space_size, width, r->glyphs[i].width ); */
838 					scale_down_glyph_width( buffer, width, r->glyphs[i].width, height );
839 				}
840 				/*else
841 				{
842 					fprintf(stderr, "lead = %d, space_size = %d, width = %d\n",
843 							r->glyphs[i].lead, font->space_size, width );
844 				}	 */
845 				r->glyphs[i].step = font->space_size ;
846 			}
847 			r->glyphs[i].pixmap = compress_glyph_pixmap( buffer, compressed_buf, r->glyphs[i].width, height, r->glyphs[i].width );
848 			r->glyphs[i].height = height ;
849 			r->glyphs[i].ascend = xfs->ascent ;
850 			r->glyphs[i].descend = xfs->descent ;
851 LOCAL_DEBUG_OUT( "glyph %u(range %lu-%lu) (%c) is %dx%d ascend = %d, lead = %d",  i, r->min_char, r->max_char, (char)(i+r->min_char), r->glyphs[i].width, r->glyphs[i].height, r->glyphs[i].ascend, r->glyphs[i].lead );
852 			pen_x += width ;
853 		}
854 		if( xim )
855 			XDestroyImage( xim );
856 	}
857 LOCAL_DEBUG_OUT( "done loading glyphs. Attaching set of glyph ranges to the codemap...%s", "" );
858 	if( all != NULL )
859 	{
860 		if( font->codemap == NULL )
861 			font->codemap = all ;
862 		else
863 		{
864 			for( r = font->codemap ; r != NULL ; r = r->above )
865 			{
866 				if( r->min_char > all->min_char )
867 				{
868 					if( r->below )
869 						r->below->above = all ;
870 					r->below = all ;
871 					while ( all->above != NULL )
872 						all = all->above ;
873 					all->above = r ;
874 					r->below = all ;
875 					break;
876 				}
877 				all->below = r ;
878 			}
879 			if( r == NULL && all->below->above == NULL )
880 				all->below->above = all ;
881 		}
882 	}
883 	free( buffer ) ;
884 	free( compressed_buf ) ;
885 LOCAL_DEBUG_OUT( "all don%s", "" );
886 }
887 
888 
889 void
make_X11_default_glyph(ASFont * font,XFontStruct * xfs)890 make_X11_default_glyph( ASFont *font, XFontStruct *xfs )
891 {
892 	unsigned char *buf, *compressed_buf ;
893 	int width, height ;
894 	int x, y;
895 	unsigned char *row ;
896 
897 
898 	height = xfs->ascent+xfs->descent ;
899 	width = xfs->max_bounds.width ;
900 
901 	if( height <= 0 ) height = 4;
902 	if( width <= 0 ) width = 4;
903 	buf = safecalloc( height*width, sizeof(unsigned char) );
904 	compressed_buf = safemalloc( height*width*2 );
905 	row = buf;
906 	for( x = 0 ; x < width ; ++x )
907 		row[x] = 0xFF;
908 	for( y = 1 ; y < height-1 ; ++y )
909 	{
910 		row += width ;
911 		row[0] = 0xFF ; row[width-1] = 0xFF ;
912 	}
913 	for( x = 0 ; x < width ; ++x )
914 		row[x] = 0xFF;
915 	font->default_glyph.pixmap = compress_glyph_pixmap( buf, compressed_buf, width, height, width );
916 	font->default_glyph.width = width ;
917 	font->default_glyph.step = width ;
918 	font->default_glyph.height = height ;
919 	font->default_glyph.lead = 0 ;
920 	font->default_glyph.ascend = xfs->ascent ;
921 	font->default_glyph.descend = xfs->descent ;
922 
923 	free( buf ) ;
924 	free( compressed_buf ) ;
925 }
926 
927 static int
load_X11_glyphs(Display * dpy,ASFont * font,XFontStruct * xfs)928 load_X11_glyphs( Display *dpy, ASFont *font, XFontStruct *xfs )
929 {
930 	GC gc = NULL;
931 	font->max_height = xfs->ascent+xfs->descent;
932 	font->max_ascend = xfs->ascent;
933 	font->max_descend = xfs->descent;
934 	font->space_size = xfs->max_bounds.width ;
935 	if( !get_flags( font->flags, ASF_Monospaced) )
936 		font->space_size = font->space_size*2/3 ;
937 
938 #if 0 /*I18N*/
939 	if( xfs->max_byte1 > 0 && xfs->min_byte1 > 0 )
940 	{
941 
942 		char_num *= rows ;
943 	}else
944 	{
945 		int i;
946 		int min_byte1 = (xfs->min_char_or_byte2>>8)&0x00FF;
947 		int max_byte1 = (xfs->max_char_or_byte2>>8)&0x00FF;
948         size_t offset = MAX(0x00FF,(int)xfs->max_char_or_byte2-(int)(min_byte1<<8)) ;
949 
950 		load_X11_glyph_range( dpy, font, xfs, 0, min_byte1,
951 											xfs->min_char_or_byte2-(min_byte1<<8),
952 			                                offset, &gc );
953 		offset -= xfs->min_char_or_byte2-(min_byte1<<8);
954 		if( max_byte1 > min_byte1 )
955 		{
956 			for( i = min_byte1+1; i < max_byte1 ; i++ )
957 			{
958 				load_X11_glyph_range( dpy, font, xfs, offset, i, 0x00, 0xFF, &gc );
959 				offset += 256 ;
960 			}
961 			load_X11_glyph_range( dpy, font, xfs, offset, max_byte1,
962 				                                     0,
963                                                      (int)xfs->max_char_or_byte2-(int)(max_byte1<<8), &gc );
964 		}
965 	}
966 #else
967 	{
968 		/* we blame X consortium for the following mess : */
969 		int min_char, max_char, our_min_char = 0x0021, our_max_char = 0x00FF ;
970 		int byte1 = xfs->min_byte1;
971 		if( xfs->min_byte1 > 0 )
972 		{
973 			min_char = xfs->min_char_or_byte2 ;
974 			max_char = xfs->max_char_or_byte2 ;
975 			if( min_char > 0x00FF )
976 			{
977 				byte1 = (min_char>>8)&0x00FF;
978 				min_char &=  0x00FF;
979 				if( ((max_char>>8)&0x00FF) > byte1 )
980 					max_char =  0x00FF;
981 				else
982 					max_char &= 0x00FF;
983 			}
984 		}else
985 		{
986 			min_char = ((xfs->min_byte1<<8)&0x00FF00)|(xfs->min_char_or_byte2&0x00FF);
987 			max_char = ((xfs->min_byte1<<8)&0x00FF00)|(xfs->max_char_or_byte2&0x00FF);
988 			our_min_char |= ((xfs->min_byte1<<8)&0x00FF00) ;
989 			our_max_char |= ((xfs->min_byte1<<8)&0x00FF00) ;
990 		}
991 		our_min_char = MAX(our_min_char,min_char);
992 		our_max_char = MIN(our_max_char,max_char);
993 
994         load_X11_glyph_range( dpy, font, xfs, (int)our_min_char-(int)min_char, byte1, our_min_char&0x00FF, our_max_char&0x00FF, &gc );
995 	}
996 #endif
997 	if( font->default_glyph.pixmap == NULL )
998 		make_X11_default_glyph( font, xfs );
999 	if( gc )
1000 		XFreeGC( dpy, gc );
1001 	return xfs->ascent+xfs->descent;
1002 }
1003 #endif /* #ifndef X_DISPLAY_MISSING */
1004 
1005 #ifdef HAVE_FREETYPE
1006 static void
load_glyph_freetype(ASFont * font,ASGlyph * asg,int glyph,UNICODE_CHAR uc)1007 load_glyph_freetype( ASFont *font, ASGlyph *asg, int glyph, UNICODE_CHAR uc )
1008 {
1009 	register FT_Face face ;
1010 	static CARD8 *glyph_compress_buf = NULL, *glyph_scaling_buf = NULL ;
1011 	static int glyph_compress_buf_size = 0, glyph_scaling_buf_size = 0;
1012 
1013 	if( font == NULL )
1014 	{
1015 		if( glyph_compress_buf )
1016 		{
1017 			free( glyph_compress_buf );
1018 			glyph_compress_buf = NULL ;
1019 		}
1020 		if( glyph_scaling_buf )
1021 		{
1022 			free( glyph_scaling_buf );
1023 			glyph_scaling_buf = NULL ;
1024 		}
1025 		glyph_compress_buf_size = 0 ;
1026 		glyph_scaling_buf_size = 0 ;
1027 		return;
1028 	}
1029 
1030 	face = font->ft_face;
1031 	if( FT_Load_Glyph( face, glyph, FT_LOAD_DEFAULT ) )
1032 		return;
1033 
1034 	if( FT_Render_Glyph( face->glyph, ft_render_mode_normal ) )
1035 		return;
1036 
1037 	if( face->glyph->bitmap.buffer )
1038 	{
1039 		FT_Bitmap 	*bmap = &(face->glyph->bitmap) ;
1040 		register CARD8 *src = bmap->buffer ;
1041 		int src_step ;
1042 /* 		int hpad = (face->glyph->bitmap_left<0)? -face->glyph->bitmap_left: face->glyph->bitmap_left ;
1043 */
1044 		asg->font_gid = glyph ;
1045 		asg->width   = bmap->width ;
1046 		asg->height  = bmap->rows ;
1047 		/* Combining Diacritical Marks : */
1048 		if( uc >= 0x0300 && uc <= 0x0362 )
1049 			asg->step = 0 ;
1050 		else
1051 #if 0
1052 			asg->step = bmap->width+face->glyph->bitmap_left ;
1053 #else
1054 			asg->step = (short)face->glyph->advance.x>>6 ;
1055 #endif
1056 
1057 		/* we only want to keep lead if it was negative */
1058 		if( uc >= 0x0300 && uc <= 0x0362 && face->glyph->bitmap_left >= 0 )
1059 			asg->lead    = -((int)font->space_size - (int)face->glyph->bitmap_left) ;
1060 		else
1061 			asg->lead    = face->glyph->bitmap_left;
1062 
1063 		if( bmap->pitch < 0 )
1064 			src += -bmap->pitch*bmap->rows ;
1065 		src_step = bmap->pitch ;
1066 
1067 		/* TODO: insert monospaced adjastments here */
1068 		if( get_flags( font->flags, ASF_Monospaced ) && ( uc < 0x0300 || uc > 0x0362 ) )
1069 		{
1070 			if( asg->lead < 0 )
1071 			{
1072 				if( asg->lead < -(int)font->space_size/8 )
1073 					asg->lead = -(int)font->space_size/8 ;
1074 				if( (int)asg->width + asg->lead <= (int)font->space_size )
1075 				{
1076 					asg->lead = (int)font->space_size - (int)asg->width ;
1077 					if( asg->lead > 0 )
1078 						asg->lead /= 2 ;
1079 				}
1080 			}else
1081 			{
1082 			 	if( (int)asg->width + (int)asg->lead > (int)font->space_size )
1083 				{
1084 					if( asg->lead > (int)font->space_size/8 )
1085 						asg->lead = (int)font->space_size/8 ;
1086 				}else                          /* centering the glyph : */
1087 					asg->lead += ((int)font->space_size - ((int)asg->width+asg->lead))/2 ;
1088 			}
1089 			if( (int)asg->width + asg->lead > (int)font->space_size )
1090 			{
1091 				register CARD8 *buf ;
1092 				int i ;
1093 				asg->width = (int)font->space_size - asg->lead ;
1094 				if( glyph_scaling_buf_size  < bmap->width*bmap->rows*2 )
1095 				{
1096 					glyph_scaling_buf_size = bmap->width*bmap->rows*2;
1097 					glyph_scaling_buf = realloc( glyph_scaling_buf, glyph_scaling_buf_size );
1098 				}
1099 				buf = &(glyph_scaling_buf[0]);
1100 				for( i = 0 ; i < bmap->rows ; ++i )
1101 				{
1102 					int k = bmap->width;
1103 					while( --k >= 0 )
1104 						buf[k] = src[k] ;
1105 					buf += bmap->width ;
1106 					src += src_step ;
1107 				}
1108 				src = &(glyph_scaling_buf[0]);
1109 				scale_down_glyph_width( src, bmap->width, asg->width, asg->height );
1110 				src_step = asg->width ;
1111 /*					fprintf(stderr, "lead = %d, space_size = %d, width = %d, to_width = %d\n",
1112 						r->glyphs[i].lead, font->space_size, width, r->glyphs[i].width ); */
1113 			}
1114 			/*else
1115 			{
1116 				fprintf(stderr, "lead = %d, space_size = %d, width = %d\n",
1117 						r->glyphs[i].lead, font->space_size, width );
1118 			}	 */
1119 			asg->step = font->space_size ;
1120 		}
1121 
1122 
1123 		if( glyph_compress_buf_size  < asg->width*asg->height*3 )
1124 		{
1125 			glyph_compress_buf_size = asg->width*asg->height*3;
1126 			glyph_compress_buf = realloc( glyph_compress_buf, glyph_compress_buf_size );
1127 		}
1128 
1129 		/* we better do some RLE encoding in attempt to preserv memory */
1130 		asg->pixmap  = compress_glyph_pixmap( src, glyph_compress_buf, asg->width, asg->height, src_step );
1131 		asg->ascend  = face->glyph->bitmap_top;
1132 		asg->descend = bmap->rows - asg->ascend;
1133 		LOCAL_DEBUG_OUT( "glyph %p with FT index %u is %dx%d ascend = %d, lead = %d, bmap_top = %d",
1134 							asg, glyph, asg->width, asg->height, asg->ascend, asg->lead,
1135 							face->glyph->bitmap_top );
1136 	}
1137 }
1138 
1139 static ASGlyphRange*
split_freetype_glyph_range(unsigned long min_char,unsigned long max_char,FT_Face face)1140 split_freetype_glyph_range( unsigned long min_char, unsigned long max_char, FT_Face face )
1141 {
1142 	ASGlyphRange *first = NULL, **r = &first;
1143 LOCAL_DEBUG_CALLER_OUT( "min_char = %lu, max_char = %lu, face = %p", min_char, max_char, face );
1144 	while( min_char <= max_char )
1145 	{
1146 		register unsigned long i = min_char;
1147 		while( i <= max_char && FT_Get_Char_Index( face, CHAR2UNICODE(i)) == 0 ) i++ ;
1148 		if( i <= max_char )
1149 		{
1150 			*r = safecalloc( 1, sizeof(ASGlyphRange));
1151 			(*r)->min_char = i ;
1152 			while( i <= max_char && FT_Get_Char_Index( face, CHAR2UNICODE(i)) != 0 ) i++ ;
1153 			(*r)->max_char = i ;
1154 LOCAL_DEBUG_OUT( "created glyph range from %lu to %lu", (*r)->min_char, (*r)->max_char );
1155 			r = &((*r)->above);
1156 		}
1157 		min_char = i ;
1158 	}
1159 	return first;
1160 }
1161 
1162 static ASGlyph*
load_freetype_locale_glyph(ASFont * font,UNICODE_CHAR uc)1163 load_freetype_locale_glyph( ASFont *font, UNICODE_CHAR uc )
1164 {
1165 	ASGlyph *asg = NULL ;
1166 	if( FT_Get_Char_Index( font->ft_face, uc) != 0 )
1167 	{
1168 		asg = safecalloc( 1, sizeof(ASGlyph));
1169 		load_glyph_freetype( font, asg, FT_Get_Char_Index( font->ft_face, uc), uc);
1170 		if( add_hash_item( font->locale_glyphs, AS_HASHABLE(uc), asg ) != ASH_Success )
1171 		{
1172 			LOCAL_DEBUG_OUT( "Failed to add glyph %p for char %ld to hash", asg, uc );
1173 			asglyph_destroy( 0, asg);
1174 			asg = NULL ;
1175 		}else
1176 		{
1177 			LOCAL_DEBUG_OUT( "added glyph %p for char %ld to hash font attr(%d,%d,%d) glyph attr (%d,%d)", asg, uc, font->max_ascend, font->max_descend, font->max_height, asg->ascend, asg->descend );
1178 
1179 			if( asg->ascend > font->max_ascend )
1180 				font->max_ascend = asg->ascend ;
1181 			if( asg->descend > font->max_descend )
1182 				font->max_descend = asg->descend ;
1183 			font->max_height = font->max_ascend+font->max_descend ;
1184 			LOCAL_DEBUG_OUT( "font attr(%d,%d,%d) glyph attr (%d,%d)", font->max_ascend, font->max_descend, font->max_height, asg->ascend, asg->descend );
1185 		}
1186 	}else
1187 		add_hash_item( font->locale_glyphs, AS_HASHABLE(uc), NULL );
1188 	return asg;
1189 }
1190 
1191 static void
load_freetype_locale_glyphs(unsigned long min_char,unsigned long max_char,ASFont * font)1192 load_freetype_locale_glyphs( unsigned long min_char, unsigned long max_char, ASFont *font )
1193 {
1194 	register unsigned long i = min_char ;
1195 LOCAL_DEBUG_CALLER_OUT( "min_char = %lu, max_char = %lu, font = %p", min_char, max_char, font );
1196 	if( font->locale_glyphs == NULL )
1197 		font->locale_glyphs = create_ashash( 0, NULL, NULL, asglyph_destroy );
1198 	while( i <= max_char )
1199 	{
1200 		load_freetype_locale_glyph( font, CHAR2UNICODE(i));
1201 		++i;
1202 	}
1203 	LOCAL_DEBUG_OUT( "font attr(%d,%d,%d)", font->max_ascend, font->max_descend, font->max_height );
1204 }
1205 
1206 
1207 static int
load_freetype_glyphs(ASFont * font)1208 load_freetype_glyphs( ASFont *font )
1209 {
1210 	int max_ascend = 0, max_descend = 0;
1211 	ASGlyphRange *r ;
1212 
1213     /* we preload only codes in range 0x21-0xFF in current charset */
1214 	/* if draw_unicode_text is used and we need some other glyphs
1215 	 * we'll just need to add them on demand */
1216 	font->codemap = split_freetype_glyph_range( 0x0021, 0x007F, font->ft_face );
1217 
1218 	load_glyph_freetype( font, &(font->default_glyph), 0, 0);/* special no-symbol glyph */
1219     load_freetype_locale_glyphs( 0x0080, 0x00FF, font );
1220 	if( font->codemap == NULL )
1221 	{
1222 		font->max_height = font->default_glyph.ascend+font->default_glyph.descend;
1223 		if( font->max_height <= 0 )
1224 			font->max_height = 1 ;
1225 		font->max_ascend = MAX((int)font->default_glyph.ascend,1);
1226 		font->max_descend = MAX((int)font->default_glyph.descend,1);
1227 	}else
1228 	{
1229 		for( r = font->codemap ; r != NULL ; r = r->above )
1230 		{
1231 			long min_char = r->min_char ;
1232 			long max_char = r->max_char ;
1233 			long i ;
1234 			if( max_char < min_char )
1235 			{
1236 				i = max_char ;
1237 				max_char = min_char ;
1238 				min_char = i ;
1239 			}
1240             r->glyphs = safecalloc( (max_char - min_char) + 1, sizeof(ASGlyph));
1241 			for( i = min_char ; i < max_char ; ++i )
1242 			{
1243 				if( i != ' ' && i != '\t' && i!= '\n' )
1244 				{
1245 					ASGlyph *asg = &(r->glyphs[i-min_char]);
1246 					UNICODE_CHAR uc = CHAR2UNICODE(i);
1247 					load_glyph_freetype( font, asg, FT_Get_Char_Index( font->ft_face, uc), uc);
1248 /* Not needed ?
1249  * 					if( asg->lead >= 0 || asg->lead+asg->width > 3 )
1250  *						font->pen_move_dir = LEFT_TO_RIGHT ;
1251  */
1252 					if( asg->ascend > max_ascend )
1253 						max_ascend = asg->ascend ;
1254 					if( asg->descend > max_descend )
1255 						max_descend = asg->descend ;
1256 				}
1257 			}
1258 		}
1259 		if( (int)font->max_ascend <= max_ascend )
1260 			font->max_ascend = MAX(max_ascend,1);
1261 		if( (int)font->max_descend <= max_descend )
1262 			font->max_descend = MAX(max_descend,1);
1263 	 	font->max_height = font->max_ascend+font->max_descend;
1264 	}
1265 	/* flushing out compression buffer : */
1266 	load_glyph_freetype(NULL, NULL, 0, 0);
1267 	return max_ascend+max_descend;
1268 }
1269 #endif
1270 
get_unicode_glyph(const UNICODE_CHAR uc,ASFont * font)1271 static inline ASGlyph *get_unicode_glyph( const UNICODE_CHAR uc, ASFont *font )
1272 {
1273 	register ASGlyphRange *r;
1274 	ASGlyph *asg = NULL ;
1275 	ASHashData hdata = {0} ;
1276 	for( r = font->codemap ; r != NULL ; r = r->above )
1277 	{
1278 LOCAL_DEBUG_OUT( "looking for glyph for char %lu (%p) if range (%ld,%ld)", uc, asg, r->min_char, r->max_char);
1279 
1280 		if( r->max_char >= uc )
1281 			if( r->min_char <= uc )
1282 			{
1283 				asg = &(r->glyphs[uc - r->min_char]);
1284 LOCAL_DEBUG_OUT( "Found glyph for char %lu (%p)", uc, asg );
1285 				if( asg->width > 0 && asg->pixmap != NULL )
1286 					return asg;
1287 				break;
1288 			}
1289 	}
1290 	if( get_hash_item( font->locale_glyphs, AS_HASHABLE(uc), &hdata.vptr ) != ASH_Success )
1291 	{
1292 #ifdef HAVE_FREETYPE
1293 		asg = load_freetype_locale_glyph( font, uc );
1294 LOCAL_DEBUG_OUT( "glyph for char %lu  loaded as %p", uc, asg );
1295 #endif
1296 	}else
1297 		asg = hdata.vptr ;
1298 LOCAL_DEBUG_OUT( "%sFound glyph for char %lu ( %p )", asg?"":"Did not ", uc, asg );
1299 	return asg?asg:&(font->default_glyph) ;
1300 }
1301 
1302 
get_character_glyph(const unsigned char c,ASFont * font)1303 static inline ASGlyph *get_character_glyph( const unsigned char c, ASFont *font )
1304 {
1305 	return get_unicode_glyph( CHAR2UNICODE(c), font );
1306 }
1307 
1308 static UNICODE_CHAR
utf8_to_unicode(const unsigned char * s)1309 utf8_to_unicode ( const unsigned char *s )
1310 {
1311 	unsigned char c = s[0];
1312 
1313 	if (c < 0x80)
1314 	{
1315   		return (UNICODE_CHAR)c;
1316 	} else if (c < 0xc2)
1317 	{
1318   		return 0;
1319     } else if (c < 0xe0)
1320 	{
1321 	    if (!((s[1] ^ 0x80) < 0x40))
1322     		return 0;
1323 	    return ((UNICODE_CHAR) (c & 0x1f) << 6)
1324   		       |(UNICODE_CHAR) (s[1] ^ 0x80);
1325     } else if (c < 0xf0)
1326 	{
1327 	    if (!((s[1] ^ 0x80) < 0x40 && (s[2] ^ 0x80) < 0x40
1328   		      && (c >= 0xe1 || s[1] >= 0xa0)))
1329 	        return 0;
1330 		return ((UNICODE_CHAR) (c & 0x0f) << 12)
1331         	 | ((UNICODE_CHAR) (s[1] ^ 0x80) << 6)
1332           	 |  (UNICODE_CHAR) (s[2] ^ 0x80);
1333 	} else if (c < 0xf8 && sizeof(UNICODE_CHAR)*8 >= 32)
1334 	{
1335 	    if (!((s[1] ^ 0x80) < 0x40 && (s[2] ^ 0x80) < 0x40
1336   	        && (s[3] ^ 0x80) < 0x40
1337     	    && (c >= 0xf1 || s[1] >= 0x90)))
1338     		return 0;
1339 	    return ((UNICODE_CHAR) (c & 0x07) << 18)
1340              | ((UNICODE_CHAR) (s[1] ^ 0x80) << 12)
1341 	         | ((UNICODE_CHAR) (s[2] ^ 0x80) << 6)
1342   	         |  (UNICODE_CHAR) (s[3] ^ 0x80);
1343 	} else if (c < 0xfc && sizeof(UNICODE_CHAR)*8 >= 32)
1344 	{
1345 	    if (!((s[1] ^ 0x80) < 0x40 && (s[2] ^ 0x80) < 0x40
1346   	        && (s[3] ^ 0x80) < 0x40 && (s[4] ^ 0x80) < 0x40
1347     	    && (c >= 0xf9 || s[1] >= 0x88)))
1348 	        return 0;
1349 		return ((UNICODE_CHAR) (c & 0x03) << 24)
1350              | ((UNICODE_CHAR) (s[1] ^ 0x80) << 18)
1351 	         | ((UNICODE_CHAR) (s[2] ^ 0x80) << 12)
1352   	         | ((UNICODE_CHAR) (s[3] ^ 0x80) << 6)
1353     	     |  (UNICODE_CHAR) (s[4] ^ 0x80);
1354 	} else if (c < 0xfe && sizeof(UNICODE_CHAR)*8 >= 32)
1355 	{
1356 	    if (!((s[1] ^ 0x80) < 0x40 && (s[2] ^ 0x80) < 0x40
1357   		    && (s[3] ^ 0x80) < 0x40 && (s[4] ^ 0x80) < 0x40
1358       	    && (s[5] ^ 0x80) < 0x40
1359         	&& (c >= 0xfd || s[1] >= 0x84)))
1360 	  		return 0;
1361 		return ((UNICODE_CHAR) (c & 0x01) << 30)
1362       	     | ((UNICODE_CHAR) (s[1] ^ 0x80) << 24)
1363         	 | ((UNICODE_CHAR) (s[2] ^ 0x80) << 18)
1364              | ((UNICODE_CHAR) (s[3] ^ 0x80) << 12)
1365 	         | ((UNICODE_CHAR) (s[4] ^ 0x80) << 6)
1366   	    	 |  (UNICODE_CHAR) (s[5] ^ 0x80);
1367     }
1368     return 0;
1369 }
1370 
get_utf8_glyph(const char * utf8,ASFont * font)1371 static inline ASGlyph *get_utf8_glyph( const char *utf8, ASFont *font )
1372 {
1373 	UNICODE_CHAR uc = utf8_to_unicode ( (const unsigned char*)utf8 );
1374 	LOCAL_DEBUG_OUT( "translated to Unicode 0x%lX(%ld), UTF8 size = %d", uc, uc, UTF8_CHAR_SIZE(utf8[0]) );
1375 	return get_unicode_glyph( uc, font );
1376 }
1377 
1378 /*********************************************************************************/
1379 /* actuall rendering code :						   								 */
1380 /*********************************************************************************/
1381 
1382 typedef struct ASGlyphMap
1383 {
1384 	int  height, width ;
1385 	ASGlyph 	**glyphs;
1386 	int 		  glyphs_num;
1387 	short 		 *x_kerning ;
1388 }ASGlyphMap;
1389 
1390 
1391 static void
apply_text_3D_type(ASText3DType type,int * width,int * height)1392 apply_text_3D_type( ASText3DType type,
1393                     int *width, int *height )
1394 {
1395 	switch( type )
1396 	{
1397 		case AST_Embossed   :
1398 		case AST_Sunken     :
1399 				(*width) += 2; (*height) += 2 ;
1400 				break ;
1401 		case AST_ShadeAbove :
1402 		case AST_ShadeBelow :
1403 				(*width)+=3; (*height)+=3 ;
1404 				break ;
1405 		case AST_SunkenThick :
1406 		case AST_EmbossedThick :
1407 				(*width)+=3; (*height)+=3 ;
1408 				break ;
1409 		case AST_OutlineAbove :
1410 		case AST_OutlineBelow :
1411 				(*width) += 1; (*height) += 1 ;
1412 				break ;
1413 		case AST_OutlineFull :
1414 				(*width) += 2; (*height) += 2 ;
1415 				break ;
1416 		default  :
1417 				break ;
1418 	}
1419 }
1420 
1421 static unsigned int
goto_tab_stop(ASTextAttributes * attr,unsigned int space_size,unsigned int line_width)1422 goto_tab_stop( ASTextAttributes *attr, unsigned int space_size, unsigned int line_width )
1423 {
1424 	unsigned int tab_size = attr->tab_size*space_size ;
1425 	unsigned int tab_stop = (((attr->origin + line_width)/tab_size)+1)*tab_size ;
1426 	if( attr->tab_stops != NULL && attr->tab_stops_num > 0 )
1427 	{
1428 		unsigned int i ;
1429 		for( i = 0 ; i < attr->tab_stops_num ; ++i )
1430 		{
1431 			if( attr->tab_stops[i] < line_width )
1432 				continue;
1433 			if( attr->tab_stops[i] < tab_stop )
1434 				tab_stop = attr->tab_stops[i] ;
1435 			break;
1436 		}
1437 	}
1438 	return tab_stop;
1439 }
1440 
1441 #ifdef HAVE_FREETYPE
1442 #define GET_KERNING(var,prev_gid,this_gid)   \
1443 	do{ if( (prev_gid) != 0 && font->type == ASF_Freetype && get_flags(font->flags, ASF_Monospaced|ASF_HasKerning) == ASF_HasKerning ) { \
1444 		FT_Vector delta; \
1445 		FT_Get_Kerning( font->ft_face, (prev_gid), (this_gid), FT_KERNING_DEFAULT, &delta );\
1446 		(var) = (short)(delta.x >> 6); \
1447 	}}while(0)
1448 #else
1449 #define GET_KERNING(var,prev_gid,this_gid)	do{(var)=0;}while(0)
1450 #endif
1451 /*		fprintf( stderr, "####### pair %d ,%d 	has kerning = %d\n", prev_gid,this_gid, var ); */
1452 
1453 
1454 #define FILL_TEXT_GLYPH_MAP(name,type,getglyph,incr) \
1455 static unsigned int \
1456 name( const type *text, ASFont *font, ASGlyphMap *map, ASTextAttributes *attr, int space_size, unsigned int offset_3d_x ) \
1457 { \
1458 	int w = 0, line_count = 0, line_width = 0; \
1459 	int i = -1, g = 0 ; \
1460 	ASGlyph *last_asg = NULL ; unsigned int last_gid = 0 ; \
1461 	do \
1462 	{ \
1463 		++i ; \
1464 		LOCAL_DEBUG_OUT("begin_i=%d, char_code = 0x%2.2X",i,text[i]); \
1465 		if( text[i] == '\n' || g == map->glyphs_num-1 ) \
1466 		{ \
1467 			if( last_asg && last_asg->width+last_asg->lead > last_asg->step ) \
1468 				line_width += last_asg->width+last_asg->lead - last_asg->step ; \
1469 			last_asg = NULL; last_gid = 0 ; \
1470 			if( line_width > w ) \
1471 				w = line_width ; \
1472 			line_width = 0 ; \
1473 			++line_count ; \
1474 			map->glyphs[g] = (g == map->glyphs_num-1)?GLYPH_EOT:GLYPH_EOL; \
1475 			++g; \
1476 		}else \
1477 		{ \
1478 			last_asg = NULL ; \
1479 			if( text[i] == ' ' ) \
1480 			{   last_gid = 0 ; \
1481 				line_width += space_size ; \
1482 				map->glyphs[g++] = GLYPH_SPACE; \
1483 			}else if( text[i] == '\t' ) \
1484 			{   last_gid = 0 ; \
1485 				if( !get_flags(attr->rendition_flags, ASTA_UseTabStops) ) line_width += space_size*attr->tab_size ; \
1486 				else line_width = goto_tab_stop( attr, space_size, line_width ); \
1487 				map->glyphs[g++] = GLYPH_TAB; \
1488 			}else \
1489 			{ \
1490 				last_asg = getglyph; \
1491 				map->glyphs[g] = last_asg; \
1492 				GET_KERNING(map->x_kerning[g],last_gid,last_asg->font_gid); \
1493 				if( line_width < -last_asg->lead ) line_width -= (line_width+last_asg->lead);\
1494 				line_width += last_asg->step+offset_3d_x+map->x_kerning[g]; \
1495 				++g; last_gid = last_asg->font_gid ; \
1496 				LOCAL_DEBUG_OUT("pre_i=%d",i); \
1497 				incr; /* i+=CHAR_SIZE(text[i])-1; */ \
1498 				LOCAL_DEBUG_OUT("post_i=%d",i); \
1499 			} \
1500 		} \
1501 	}while( g < map->glyphs_num );  \
1502 	map->width = MAX( w, 1 ); \
1503 	return line_count ; \
1504 }
1505 
1506 #ifdef _MSC_VER
1507 FILL_TEXT_GLYPH_MAP(fill_text_glyph_map_Char,char,get_character_glyph(text[i],font),1)
1508 FILL_TEXT_GLYPH_MAP(fill_text_glyph_map_Unicode,UNICODE_CHAR,get_unicode_glyph(text[i],font),1)
1509 #else
1510 FILL_TEXT_GLYPH_MAP(fill_text_glyph_map_Char,char,get_character_glyph(text[i],font),/* */)
1511 FILL_TEXT_GLYPH_MAP(fill_text_glyph_map_Unicode,UNICODE_CHAR,get_unicode_glyph(text[i],font),/* */)
1512 #endif
1513 FILL_TEXT_GLYPH_MAP(fill_text_glyph_map_UTF8,char,get_utf8_glyph(&text[i],font),i+=(UTF8_CHAR_SIZE(text[i])-1))
1514 
1515 void
free_glyph_map(ASGlyphMap * map,Bool reusable)1516 free_glyph_map( ASGlyphMap *map, Bool reusable )
1517 {
1518     if( map )
1519     {
1520 		if( map->glyphs )
1521 	        free( map->glyphs );
1522 		if( map->x_kerning )
1523 	        free( map->x_kerning );
1524         if( !reusable )
1525             free( map );
1526     }
1527 }
1528 
1529 static int
get_text_length(ASCharType char_type,const char * text)1530 get_text_length (ASCharType char_type, const char *text)
1531 {
1532 	register int count = 0;
1533 	if( char_type == ASCT_Char )
1534 	{
1535 		register char *ptr = (char*)text ;
1536 		while( ptr[count] != 0 )++count;
1537 	}else if( char_type == ASCT_UTF8 )
1538 	{
1539 		register char *ptr = (char*)text ;
1540 		while( *ptr != 0 ){	++count; ptr += UTF8_CHAR_SIZE(*ptr); }
1541 	}else if( char_type == ASCT_Unicode )
1542 	{
1543 		register UNICODE_CHAR *uc_ptr = (UNICODE_CHAR*)text ;
1544 		while( uc_ptr[count] != 0 )	++count;
1545 	}
1546 	return count;
1547 }
1548 
1549 ASGlyph**
get_text_glyph_list(const char * text,ASFont * font,ASCharType char_type,int length)1550 get_text_glyph_list (const char *text, ASFont *font, ASCharType char_type, int length)
1551 {
1552 	ASGlyph** glyphs = NULL;
1553 	int i = 0;
1554 
1555 	if (text == NULL || font == NULL)
1556 		return NULL;
1557 	if (length <= 0)
1558 		if ((length = get_text_length (char_type, text)) <= 0)
1559 			return NULL;
1560 
1561 	glyphs = safecalloc( length+1, sizeof(ASGlyph*));
1562 	if (char_type == ASCT_Char)
1563 	{
1564 		register char *ptr = (char*)text;
1565 		for (i = 0 ; i < length ; ++i)
1566 			glyphs[i] = get_character_glyph (ptr[i], font);
1567 	}else if (char_type == ASCT_UTF8)
1568 	{
1569 		register char *ptr = (char*)text;
1570 		for (i = 0 ; i < length ; ++i)
1571 		{
1572 			glyphs[i] = get_utf8_glyph (ptr, font);
1573 			ptr += UTF8_CHAR_SIZE(*ptr);
1574 		}
1575 	}else if( char_type == ASCT_Unicode )
1576 	{
1577 		register UNICODE_CHAR *uc_ptr = (UNICODE_CHAR*)text ;
1578 		for (i = 0 ; i < length ; ++i)
1579 			glyphs[i] = get_unicode_glyph (uc_ptr[i], font);
1580 	}
1581 
1582 	return glyphs;
1583 }
1584 
1585 static Bool
get_text_glyph_map(const char * text,ASFont * font,ASGlyphMap * map,ASTextAttributes * attr,int length)1586 get_text_glyph_map (const char *text, ASFont *font, ASGlyphMap *map, ASTextAttributes *attr, int length  )
1587 {
1588 	unsigned int line_count = 0;
1589 	int offset_3d_x = 0, offset_3d_y = 0 ;
1590 	int space_size  = 0 ;
1591 
1592 	apply_text_3D_type( attr->type, &offset_3d_x, &offset_3d_y );
1593 
1594 	if( text == NULL || font == NULL || map == NULL)
1595 		return False;
1596 
1597 	offset_3d_x += font->spacing_x ;
1598 	offset_3d_y += font->spacing_y ;
1599 
1600 	space_size  = font->space_size ;
1601 	if( !get_flags( font->flags, ASF_Monospaced) )
1602 		space_size  = (space_size>>1)+1 ;
1603 	space_size += offset_3d_x;
1604 
1605 	map->glyphs_num = 1;
1606 	if( length <= 0 )
1607 		length = get_text_length (attr->char_type, text);
1608 
1609 	map->glyphs_num = 1 + length ;
1610 
1611 	map->glyphs = safecalloc( map->glyphs_num, sizeof(ASGlyph*));
1612 	map->x_kerning = safecalloc( map->glyphs_num, sizeof(short));
1613 
1614 	if( attr->char_type == ASCT_UTF8 )
1615 		line_count = fill_text_glyph_map_UTF8( text, font, map, attr, space_size, offset_3d_x );
1616 	else if( attr->char_type == ASCT_Unicode )
1617 		line_count = fill_text_glyph_map_Unicode( (UNICODE_CHAR*)text, font, map, attr, space_size, offset_3d_x );
1618 	else /* assuming attr->char_type == ASCT_Char by default */
1619 		line_count = fill_text_glyph_map_Char( text, font, map, attr, space_size, offset_3d_x );
1620 
1621     map->height = line_count * (font->max_height+offset_3d_y) - font->spacing_y;
1622 
1623 	if( map->height <= 0 )
1624 		map->height = 1 ;
1625 
1626 	return True;
1627 }
1628 
1629 #define GET_TEXT_SIZE_LOOP(getglyph,incr,len) \
1630 	do{ Bool terminated = True; ++i ;\
1631 		if( len == 0 || i < len )	\
1632 		{ 	terminated = ( text[i] == '\0' || text[i] == '\n' ); \
1633 			if( x_positions ) x_positions[i] = line_width ; \
1634 		} \
1635 		if( terminated ) { \
1636 			if( last_asg && last_asg->width+last_asg->lead > last_asg->step ) \
1637 				line_width += last_asg->width+last_asg->lead - last_asg->step ; \
1638 			last_asg = NULL; last_gid = 0 ; \
1639 			if( line_width > w ) \
1640 				w = line_width ; \
1641 			line_width = 0 ; \
1642             ++line_count ; \
1643 		}else { \
1644 			last_asg = NULL ; \
1645 			if( text[i] == ' ' ){ \
1646 				line_width += space_size ; last_gid = 0 ;\
1647 			}else if( text[i] == '\t' ){ last_gid = 0 ; \
1648 				if( !get_flags(attr->rendition_flags, ASTA_UseTabStops) ) line_width += space_size*attr->tab_size ; \
1649 				else line_width = goto_tab_stop( attr, space_size, line_width ); \
1650 			}else{ int kerning = 0 ;\
1651 				last_asg = getglyph; \
1652 				GET_KERNING(kerning,last_gid,last_asg->font_gid); \
1653 				if( line_width < -last_asg->lead ) line_width -= (line_width+last_asg->lead);\
1654 				line_width += last_asg->step+offset_3d_x +kerning ;  \
1655 				last_gid = last_asg->font_gid ; \
1656 				incr ; \
1657 			} \
1658 		} \
1659 	}while( (len <= 0 || len > i) && text[i] != '\0' )
1660 
1661 static Bool
get_text_size_internal(const char * src_text,ASFont * font,ASTextAttributes * attr,unsigned int * width,unsigned int * height,int length,int * x_positions)1662 get_text_size_internal( const char *src_text, ASFont *font, ASTextAttributes *attr, unsigned int *width, unsigned int *height, int length, int *x_positions )
1663 {
1664     int w = 0, h = 0, line_count = 0;
1665 	int line_width = 0;
1666     int i = -1;
1667 	ASGlyph *last_asg = NULL ;
1668 	int space_size = 0;
1669 	int offset_3d_x = 0, offset_3d_y = 0 ;
1670 	int last_gid = 0 ;
1671 
1672 
1673 	apply_text_3D_type( attr->type, &offset_3d_x, &offset_3d_y );
1674 	if( src_text == NULL || font == NULL )
1675 		return False;
1676 
1677 	offset_3d_x += font->spacing_x ;
1678 	offset_3d_y += font->spacing_y ;
1679 
1680 	space_size  = font->space_size ;
1681 	if( !get_flags( font->flags, ASF_Monospaced) )
1682 		space_size  = (space_size>>1)+1 ;
1683 	space_size += offset_3d_x ;
1684 
1685 	LOCAL_DEBUG_OUT( "char_type = %d", attr->char_type );
1686 	if( attr->char_type == ASCT_Char )
1687 	{
1688 		char *text = (char*)&src_text[0] ;
1689 #ifdef _MSC_VER
1690 		GET_TEXT_SIZE_LOOP(get_character_glyph(text[i],font),1,length);
1691 #else
1692 		GET_TEXT_SIZE_LOOP(get_character_glyph(text[i],font),/* */,length);
1693 #endif
1694 	}else if( attr->char_type == ASCT_UTF8 )
1695 	{
1696 		char *text = (char*)&src_text[0] ;
1697 		int byte_length = 0 ;
1698 		if( length > 0 )
1699 		{
1700 			int k ;
1701 			for( k = 0 ; k < length ; ++k )
1702 			{
1703 				if( text[byte_length] == '\0' )
1704 					break;
1705 				byte_length += UTF8_CHAR_SIZE(text[byte_length]);
1706 			}
1707 		}
1708 		GET_TEXT_SIZE_LOOP(get_utf8_glyph(&text[i],font),i+=UTF8_CHAR_SIZE(text[i])-1,byte_length);
1709 	}else if( attr->char_type == ASCT_Unicode )
1710 	{
1711 		UNICODE_CHAR *text = (UNICODE_CHAR*)&src_text[0] ;
1712 #ifdef _MSC_VER
1713 		GET_TEXT_SIZE_LOOP(get_unicode_glyph(text[i],font),1,length);
1714 #else
1715 		GET_TEXT_SIZE_LOOP(get_unicode_glyph(text[i],font),/* */,length);
1716 #endif
1717 	}
1718 
1719     h = line_count * (font->max_height+offset_3d_y) - font->spacing_y;
1720 
1721     if( w < 1 )
1722 		w = 1 ;
1723 	if( h < 1 )
1724 		h = 1 ;
1725 	if( width )
1726 		*width = w;
1727 	if( height )
1728 		*height = h;
1729 	return True ;
1730 }
1731 
1732 Bool
get_text_size(const char * src_text,ASFont * font,ASText3DType type,unsigned int * width,unsigned int * height)1733 get_text_size( const char *src_text, ASFont *font, ASText3DType type, unsigned int *width, unsigned int *height )
1734 {
1735 	ASTextAttributes attr = {ASTA_VERSION_INTERNAL, 0, 0, ASCT_Char, 8, 0, NULL, 0 };
1736 	attr.type = type ;
1737 	if( IsUTF8Locale() )
1738 		attr.char_type = ASCT_UTF8 ;
1739 	return get_text_size_internal( (char*)src_text, font, &attr, width, height, 0/*autodetect length*/, NULL );
1740 }
1741 
1742 Bool
get_unicode_text_size(const UNICODE_CHAR * src_text,ASFont * font,ASText3DType type,unsigned int * width,unsigned int * height)1743 get_unicode_text_size( const UNICODE_CHAR *src_text, ASFont *font, ASText3DType type, unsigned int *width, unsigned int *height )
1744 {
1745 	ASTextAttributes attr = {ASTA_VERSION_INTERNAL, 0, 0, ASCT_Unicode, 8, 0, NULL, 0 };
1746 	attr.type = type ;
1747 	return get_text_size_internal( (char*)src_text, font, &attr, width, height, 0/*autodetect length*/, NULL );
1748 }
1749 
1750 Bool
get_utf8_text_size(const char * src_text,ASFont * font,ASText3DType type,unsigned int * width,unsigned int * height)1751 get_utf8_text_size( const char *src_text, ASFont *font, ASText3DType type, unsigned int *width, unsigned int *height )
1752 {
1753 	ASTextAttributes attr = {ASTA_VERSION_INTERNAL, 0, 0, ASCT_UTF8, 8, 0, NULL, 0 };
1754 	attr.type = type ;
1755 	return get_text_size_internal( (char*)src_text, font, &attr, width, height, 0/*autodetect length*/, NULL );
1756 }
1757 
1758 Bool
get_fancy_text_size(const void * src_text,ASFont * font,ASTextAttributes * attr,unsigned int * width,unsigned int * height,int length,int * x_positions)1759 get_fancy_text_size( const void *src_text, ASFont *font, ASTextAttributes *attr, unsigned int *width, unsigned int *height, int length, int *x_positions )
1760 {
1761 	ASTextAttributes internal_attr = {ASTA_VERSION_INTERNAL, 0, 0, ASCT_Char, 8, 0, NULL, 0 };
1762 	if( attr != NULL )
1763 	{
1764 		internal_attr = *attr;
1765 		if( internal_attr.tab_size == 0 )
1766 			internal_attr.tab_size = 8 ;
1767 		internal_attr.version = ASTA_VERSION_INTERNAL ;
1768 	}else
1769 	{
1770 		if( IsUTF8Locale() )
1771 			internal_attr.char_type = ASCT_UTF8 ;
1772 	}
1773 	return get_text_size_internal( src_text, font, &internal_attr, width, height, length, x_positions );
1774 }
1775 
1776 inline static void
render_asglyph(CARD8 ** scanlines,CARD8 * row,int start_x,int y,int width,int height,CARD32 ratio)1777 render_asglyph( CARD8 **scanlines, CARD8 *row,
1778                 int start_x, int y, int width, int height,
1779 				CARD32 ratio )
1780 {
1781 	int count = -1 ;
1782 	int max_y = y + height ;
1783 	register CARD32 data = 0;
1784 	while( y < max_y )
1785 	{
1786 		register CARD8 *dst = scanlines[y]+start_x;
1787 		register int x = -1;
1788 		while( ++x < width )
1789 		{
1790 /*fprintf( stderr, "data = %X, count = %d, x = %d, y = %d\n", data, count, x, y );*/
1791 			if( count < 0 )
1792 			{
1793 				data = *(row++);
1794 				if( (data&0x80) != 0)
1795 				{
1796 					data = ((data&0x7F)<<1);
1797 					if( data != 0 )
1798 						++data;
1799 				}else
1800 				{
1801 					count = data&0x3F ;
1802 					data = ((data&0x40) != 0 )? 0xFF: 0x00;
1803 				}
1804 				if( ratio != 0xFF && data != 0 )
1805 					data = ((data*ratio)>>8)+1 ;
1806 			}
1807 			if( data > dst[x] )
1808 				dst[x] = (data > 255)? 0xFF:data ;
1809 			--count;
1810 		}
1811 		++y;
1812 	}
1813 }
1814 
1815 inline static void
render_asglyph_over(CARD8 ** scanlines,CARD8 * row,int start_x,int y,int width,int height,CARD32 value)1816 render_asglyph_over( CARD8 **scanlines, CARD8 *row,
1817                 int start_x, int y, int width, int height,
1818 				CARD32 value )
1819 {
1820 	int count = -1 ;
1821 	int max_y = y + height ;
1822 	CARD32 anti_data = 0;
1823 	register CARD32 data = 0;
1824 	while( y < max_y )
1825 	{
1826 		register CARD8 *dst = scanlines[y]+start_x;
1827 		register int x = -1;
1828 		while( ++x < width )
1829 		{
1830 /*fprintf( stderr, "data = %X, count = %d, x = %d, y = %d\n", data, count, x, y );*/
1831 			if( count < 0 )
1832 			{
1833 				data = *(row++);
1834 				if( (data&0x80) != 0)
1835 				{
1836 					data = ((data&0x7F)<<1);
1837 					if( data != 0 )
1838 						++data;
1839 				}else
1840 				{
1841 					count = data&0x3F ;
1842 					data = ((data&0x40) != 0 )? 0xFF: 0x00;
1843 				}
1844 				anti_data = 256 - data ;
1845 			}
1846 			if( data >= 254 )
1847 				dst[x] = value ;
1848 			else
1849 				dst[x] = ((CARD32)dst[x]*anti_data + value*data)>>8 ;
1850 			--count;
1851 		}
1852 		++y;
1853 	}
1854 }
1855 
1856 
1857 
1858 static ASImage *
draw_text_internal(const char * text,ASFont * font,ASTextAttributes * attr,int compression,int length)1859 draw_text_internal( const char *text, ASFont *font, ASTextAttributes *attr, int compression, int length )
1860 {
1861 	ASGlyphMap map ;
1862 	CARD8 *memory, *rgb_memory = NULL;
1863 	CARD8 **scanlines, **rgb_scanlines = NULL ;
1864 	int i = 0, offset = 0, line_height, space_size, base_line;
1865 	ASImage *im;
1866 	int pen_x = 0, pen_y = 0;
1867 	int offset_3d_x = 0, offset_3d_y = 0  ;
1868 	CARD32 back_color = 0 ;
1869 	CARD32 alpha_7 = 0x007F, alpha_9 = 0x009F, alpha_A = 0x00AF, alpha_C = 0x00CF, alpha_F = 0x00FF, alpha_E = 0x00EF;
1870 	START_TIME(started);
1871 
1872 	// Perform line breaks if a fixed width is specified
1873 	// TODO: this is a quick and dirty fix and should work for now, but we really should fix it
1874 	// so we don't have to calculate text size so many times as well as make it UNICODE friendly
1875 	// and remove mangling of the source text (Sasha):
1876 	if (attr->width)
1877 	{
1878         unsigned int width, height; // SMA
1879         get_text_size(  text , font, attr->type, &width, &height );
1880         if ( (width > attr->width)  &&  (strchr(text, ' ')) )
1881         {
1882           char *tryPtr = strchr(text,' ');
1883           char *oldTryPtr = tryPtr;
1884           while (tryPtr)
1885             {
1886                *tryPtr = 0;
1887                get_text_size(  text , font, attr->type, &width, &height );
1888                if (width > attr->width)
1889                    *oldTryPtr = '\n';
1890 
1891                *tryPtr = ' ';
1892                oldTryPtr = tryPtr;
1893                tryPtr = strchr(tryPtr + 1,' ');
1894             }
1895         }
1896 	}
1897 
1898 LOCAL_DEBUG_CALLER_OUT( "text = \"%s\", font = %p, compression = %d", text, font, compression );
1899 	if( !get_text_glyph_map( text, font, &map, attr, length) )
1900 		return NULL;
1901 
1902 	if( map.width <= 0 )
1903 		return NULL;
1904 
1905 	apply_text_3D_type( attr->type, &offset_3d_x, &offset_3d_y );
1906 
1907 	offset_3d_x += font->spacing_x ;
1908 	offset_3d_y += font->spacing_y ;
1909 	line_height = font->max_height+offset_3d_y ;
1910 
1911 LOCAL_DEBUG_OUT( "text size = %dx%d pixels", map.width, map.height );
1912 	im = create_asimage( map.width, map.height, compression );
1913 
1914 	space_size  = font->space_size ;
1915 	if( !get_flags( font->flags, ASF_Monospaced) )
1916 		space_size  = (space_size>>1)+1 ;
1917 	space_size += offset_3d_x;
1918 
1919 	base_line = font->max_ascend;
1920 LOCAL_DEBUG_OUT( "line_height is %d, space_size is %d, base_line is %d", line_height, space_size, base_line );
1921 	scanlines = safemalloc( line_height*sizeof(CARD8*));
1922 	memory = safecalloc( 1, line_height*map.width);
1923 	for( i = 0 ; i < line_height ; ++i )
1924 	{
1925 		scanlines[i] = memory + offset;
1926 		offset += map.width;
1927 	}
1928 	if( attr->type >= AST_OutlineAbove )
1929 	{
1930 		CARD32 fc = attr->fore_color ;
1931 		offset = 0 ;
1932 		rgb_scanlines = safemalloc( line_height*3*sizeof(CARD8*));
1933 		rgb_memory = safecalloc( 1, line_height*map.width*3);
1934 		for( i = 0 ; i < line_height*3 ; ++i )
1935 		{
1936 			rgb_scanlines[i] = rgb_memory + offset;
1937 			offset += map.width;
1938 		}
1939 		if( (ARGB32_RED16(fc)*222+ARGB32_GREEN16(fc)*707+ARGB32_BLUE16(fc) *71)/1000 < 0x07FFF )
1940 		{
1941 			back_color = 0xFF ;
1942 			memset( rgb_memory, back_color, line_height*map.width*3 );
1943 		}
1944 	}
1945 	if( ARGB32_ALPHA8(attr->fore_color) > 0 )
1946 	{
1947 		CARD32 a = ARGB32_ALPHA8(attr->fore_color);
1948 		alpha_7 = (0x007F*a)>>8 ;
1949 		alpha_9 = (0x009F*a)>>8 ;
1950 		alpha_A = (0x00AF*a)>>8 ;
1951 		alpha_C = (0x00CF*a)>>8 ;
1952 		alpha_E	= (0x00EF*a)>>8 ;
1953 		alpha_F = (0x00FF*a)>>8 ;
1954 	}
1955 
1956 	i = -1 ;
1957 	if(get_flags(font->flags, ASF_RightToLeft))
1958 		pen_x = map.width ;
1959 
1960 	do
1961 	{
1962 		++i;
1963 /*fprintf( stderr, "drawing character %d '%c'\n", i, text[i] );*/
1964 		if( map.glyphs[i] == GLYPH_EOL || map.glyphs[i] == GLYPH_EOT )
1965 		{
1966 			int y;
1967 			for( y = 0 ; y < line_height ; ++y )
1968 			{
1969 #if 1
1970 #if defined(LOCAL_DEBUG) && !defined(NO_DEBUG_OUTPUT)
1971 				{
1972 					int x = 0;
1973 					while( x < map.width )
1974 						fprintf( stderr, "%2.2X ", scanlines[y][x++] );
1975 					fprintf( stderr, "\n" );
1976 				}
1977 #endif
1978 #endif
1979  				im->channels[IC_ALPHA][pen_y+y] = store_data( NULL, scanlines[y], map.width, ASStorage_RLEDiffCompress, 0);
1980 				if( attr->type >= AST_OutlineAbove )
1981 				{
1982 	 				im->channels[IC_RED][pen_y+y] 	= store_data( NULL, rgb_scanlines[y], map.width, ASStorage_RLEDiffCompress, 0);
1983 	 				im->channels[IC_GREEN][pen_y+y] = store_data( NULL, rgb_scanlines[y+line_height], map.width, ASStorage_RLEDiffCompress, 0);
1984 	 				im->channels[IC_BLUE][pen_y+y]  = store_data( NULL, rgb_scanlines[y+line_height+line_height], map.width, ASStorage_RLEDiffCompress, 0);
1985 				}
1986 			}
1987 
1988 			memset( memory, 0x00, line_height*map.width );
1989 			if( attr->type >= AST_OutlineAbove )
1990 				memset( rgb_memory, back_color, line_height*map.width*3 );
1991 
1992 			pen_x = get_flags(font->flags, ASF_RightToLeft)? map.width : 0;
1993 			pen_y += line_height;
1994 			if( pen_y <0 )
1995 				pen_y = 0 ;
1996 		}else
1997 		{
1998 			if( map.glyphs[i] == GLYPH_SPACE || map.glyphs[i] == GLYPH_TAB )
1999 			{
2000 				if(map.glyphs[i] == GLYPH_TAB)
2001 				{
2002 					if( !get_flags(attr->rendition_flags, ASTA_UseTabStops) ) pen_x += space_size*attr->tab_size ;
2003 					else pen_x = goto_tab_stop( attr, space_size, pen_x );
2004 				}else if( get_flags(font->flags, ASF_RightToLeft) )
2005 					pen_x -= space_size ;
2006 				else
2007 					pen_x += space_size ;
2008 			}else
2009 			{
2010 				/* now comes the fun part : */
2011 				ASGlyph *asg = map.glyphs[i] ;
2012 				int y = base_line - asg->ascend;
2013 				int start_x = 0, offset_x = 0;
2014 
2015 				if( get_flags(font->flags, ASF_RightToLeft) )
2016 					pen_x  -= asg->step+offset_3d_x +map.x_kerning[i];
2017 				else
2018 				{
2019 					LOCAL_DEBUG_OUT( "char # %d : pen_x = %d, kerning = %d, lead = %d, width = %d, step = %d", i, pen_x, map.x_kerning[i], asg->lead, asg->width, asg->step );
2020 					pen_x += map.x_kerning[i] ;
2021 				}
2022 				if( asg->lead > 0 )
2023 					start_x = pen_x + asg->lead ;
2024 				else
2025 					start_x = pen_x + asg->lead ;
2026 				if( start_x < 0 )
2027 				{
2028 					offset_x = -start_x ;
2029 					start_x = 0 ;
2030 				}
2031 				if( y < 0 )
2032 					y = 0 ;
2033 
2034 				switch( attr->type )
2035 				{
2036 					case AST_Plain :
2037 						render_asglyph( scanlines, asg->pixmap, start_x, y, asg->width, asg->height, alpha_F );
2038 					    break ;
2039 					case AST_Embossed :
2040 						render_asglyph( scanlines, asg->pixmap, start_x, y, asg->width, asg->height, alpha_F );
2041 						render_asglyph( scanlines, asg->pixmap, start_x+2, y+2, asg->width, asg->height, alpha_9 );
2042 						render_asglyph( scanlines, asg->pixmap, start_x+1, y+1, asg->width, asg->height, alpha_C );
2043  					    break ;
2044 					case AST_Sunken :
2045 						render_asglyph( scanlines, asg->pixmap, start_x, y, asg->width, asg->height, alpha_9 );
2046 						render_asglyph( scanlines, asg->pixmap, start_x+2, y+2, asg->width, asg->height, alpha_F );
2047 						render_asglyph( scanlines, asg->pixmap, start_x+1, y+1, asg->width, asg->height, alpha_C );
2048 					    break ;
2049 					case AST_ShadeAbove :
2050 						render_asglyph( scanlines, asg->pixmap, start_x, y, asg->width, asg->height, alpha_7 );
2051 						render_asglyph( scanlines, asg->pixmap, start_x+3, y+3, asg->width, asg->height, alpha_F );
2052 					    break ;
2053 					case AST_ShadeBelow :
2054 						render_asglyph( scanlines, asg->pixmap, start_x+3, y+3, asg->width, asg->height, alpha_7 );
2055 						render_asglyph( scanlines, asg->pixmap, start_x, y, asg->width, asg->height, alpha_F );
2056 					    break ;
2057 					case AST_EmbossedThick :
2058 						render_asglyph( scanlines, asg->pixmap, start_x, y, asg->width, asg->height, alpha_F );
2059 						render_asglyph( scanlines, asg->pixmap, start_x+1, y+1, asg->width, asg->height, alpha_E );
2060 						render_asglyph( scanlines, asg->pixmap, start_x+3, y+3, asg->width, asg->height, alpha_7 );
2061 						render_asglyph( scanlines, asg->pixmap, start_x+2, y+2, asg->width, asg->height, alpha_C );
2062  					    break ;
2063 					case AST_SunkenThick :
2064 						render_asglyph( scanlines, asg->pixmap, start_x, y, asg->width, asg->height, alpha_7 );
2065 						render_asglyph( scanlines, asg->pixmap, start_x+1, y+1, asg->width, asg->height, alpha_A );
2066 						render_asglyph( scanlines, asg->pixmap, start_x+3, y+3, asg->width, asg->height, alpha_F );
2067 						render_asglyph( scanlines, asg->pixmap, start_x+2, y+2, asg->width, asg->height, alpha_C );
2068  					    break ;
2069 					case AST_OutlineAbove :
2070 						render_asglyph( scanlines, asg->pixmap, start_x, y, asg->width, asg->height, alpha_A );
2071 						render_asglyph( scanlines, asg->pixmap, start_x+1, y+1, asg->width, asg->height, alpha_F );
2072 						render_asglyph_over( rgb_scanlines, asg->pixmap, start_x+1, y+1, asg->width, asg->height, ARGB32_RED8(attr->fore_color) );
2073 						render_asglyph_over( &rgb_scanlines[line_height], asg->pixmap, start_x+1, y+1, asg->width, asg->height, ARGB32_GREEN8(attr->fore_color) );
2074 						render_asglyph_over( &rgb_scanlines[line_height*2], asg->pixmap, start_x+1, y+1, asg->width, asg->height, ARGB32_BLUE8(attr->fore_color) );
2075 					    break ;
2076 					case AST_OutlineBelow :
2077 						render_asglyph( scanlines, asg->pixmap, start_x, y, asg->width, asg->height, alpha_F );
2078 						render_asglyph( scanlines, asg->pixmap, start_x+1, y+1, asg->width, asg->height, alpha_A );
2079 						render_asglyph_over( rgb_scanlines, asg->pixmap, start_x, y, asg->width, asg->height, ARGB32_RED8(attr->fore_color) );
2080 						render_asglyph_over( &rgb_scanlines[line_height], asg->pixmap, start_x, y, asg->width, asg->height, ARGB32_GREEN8(attr->fore_color) );
2081 						render_asglyph_over( &rgb_scanlines[line_height*2], asg->pixmap, start_x, y, asg->width, asg->height, ARGB32_BLUE8(attr->fore_color) );
2082 					    break ;
2083 					case AST_OutlineFull :
2084 						render_asglyph( scanlines, asg->pixmap, start_x, y, asg->width, asg->height, alpha_A );
2085 						render_asglyph( scanlines, asg->pixmap, start_x+1, y+1, asg->width, asg->height, alpha_F );
2086 						render_asglyph( scanlines, asg->pixmap, start_x+2, y+2, asg->width, asg->height, alpha_A );
2087 						render_asglyph_over( rgb_scanlines, asg->pixmap, start_x+1, y+1, asg->width, asg->height, ARGB32_RED8(attr->fore_color) );
2088 						render_asglyph_over( &rgb_scanlines[line_height], asg->pixmap, start_x+1, y+1, asg->width, asg->height, ARGB32_GREEN8(attr->fore_color) );
2089 						render_asglyph_over( &rgb_scanlines[line_height*2], asg->pixmap, start_x+1, y+1, asg->width, asg->height, ARGB32_BLUE8(attr->fore_color) );
2090 					    break ;
2091 				  default:
2092 				        break ;
2093 				}
2094 
2095 				if( !get_flags(font->flags, ASF_RightToLeft) )
2096   					pen_x  += offset_x + asg->step+offset_3d_x;
2097 			}
2098 		}
2099 	}while( map.glyphs[i] != GLYPH_EOT );
2100     free_glyph_map( &map, True );
2101 	free( memory );
2102 	free( scanlines );
2103 	if( rgb_memory )
2104 		free( rgb_memory );
2105 	if( rgb_scanlines )
2106 		free( rgb_scanlines );
2107 	SHOW_TIME("", started);
2108 	return im;
2109 }
2110 
2111 ASImage *
draw_text(const char * text,ASFont * font,ASText3DType type,int compression)2112 draw_text( const char *text, ASFont *font, ASText3DType type, int compression )
2113 {
2114 	ASTextAttributes attr = {ASTA_VERSION_INTERNAL, 0, 0, ASCT_Char, 8, 0, NULL, 0, ARGB32_White };
2115 	attr.type = type ;
2116 	if( IsUTF8Locale() )
2117 		attr.char_type = ASCT_UTF8 ;
2118 	return draw_text_internal( text, font, &attr, compression, 0/*autodetect length*/ );
2119 }
2120 
2121 ASImage *
draw_unicode_text(const UNICODE_CHAR * text,ASFont * font,ASText3DType type,int compression)2122 draw_unicode_text( const UNICODE_CHAR *text, ASFont *font, ASText3DType type, int compression )
2123 {
2124 	ASTextAttributes attr = {ASTA_VERSION_INTERNAL, 0, 0, ASCT_Unicode, 8, 0, NULL, 0, ARGB32_White };
2125 	attr.type = type ;
2126 	return draw_text_internal( (const char*)text, font, &attr, compression, 0/*autodetect length*/ );
2127 }
2128 
2129 ASImage *
draw_utf8_text(const char * text,ASFont * font,ASText3DType type,int compression)2130 draw_utf8_text( const char *text, ASFont *font, ASText3DType type, int compression )
2131 {
2132 	ASTextAttributes attr = {ASTA_VERSION_INTERNAL, 0, 0, ASCT_UTF8, 8, 0, NULL, 0, ARGB32_White };
2133 	attr.type = type ;
2134 	return draw_text_internal( text, font, &attr, compression, 0/*autodetect length*/ );
2135 }
2136 
2137 ASImage *
draw_fancy_text(const void * text,ASFont * font,ASTextAttributes * attr,int compression,int length)2138 draw_fancy_text( const void *text, ASFont *font, ASTextAttributes *attr, int compression, int length )
2139 {
2140 	ASTextAttributes internal_attr = {ASTA_VERSION_INTERNAL, 0, 0, ASCT_Char, 8, 0, NULL, 0, ARGB32_White };
2141 	if( attr != NULL )
2142 	{
2143 		internal_attr = *attr;
2144 		if( internal_attr.tab_size == 0 )
2145 			internal_attr.tab_size = 8 ;
2146 		internal_attr.version = ASTA_VERSION_INTERNAL ;
2147 	}else
2148 	{
2149 		if( IsUTF8Locale() )
2150 			internal_attr.char_type = ASCT_UTF8 ;
2151 	}
2152 	return draw_text_internal( text, font, &internal_attr, compression, length );
2153 }
2154 
get_asfont_glyph_spacing(ASFont * font,int * x,int * y)2155 Bool get_asfont_glyph_spacing( ASFont* font, int *x, int *y )
2156 {
2157 	if( font )
2158 	{
2159 		if( x )
2160 			*x = font->spacing_x ;
2161 		if( y )
2162 			*y = font->spacing_y ;
2163 		return True ;
2164 	}
2165 	return False ;
2166 }
2167 
set_asfont_glyph_spacing(ASFont * font,int x,int y)2168 Bool set_asfont_glyph_spacing( ASFont* font, int x, int y )
2169 {
2170 	if( font )
2171 	{
2172 		font->spacing_x = (x < 0 )? 0: x;
2173 		font->spacing_y = (y < 0 )? 0: y;
2174 		return True ;
2175 	}
2176 	return False ;
2177 }
2178 
2179 /* Misc functions : */
print_asfont(FILE * stream,ASFont * font)2180 void print_asfont( FILE* stream, ASFont* font)
2181 {
2182 	if( font )
2183 	{
2184 		fprintf( stream, "font.type = %d\n", font->type       );
2185 		fprintf( stream, "font.flags = 0x%lX\n", font->flags       );
2186 #ifdef HAVE_FREETYPE
2187 		fprintf( stream, "font.ft_face = %p\n", font->ft_face    );              /* free type font handle */
2188 #endif
2189 		fprintf( stream, "font.max_height = %d\n", font->max_height );
2190 		fprintf( stream, "font.space_size = %d\n" , font->space_size );
2191 		fprintf( stream, "font.spacing_x  = %d\n" , font->spacing_x );
2192 		fprintf( stream, "font.spacing_y  = %d\n" , font->spacing_y );
2193 		fprintf( stream, "font.max_ascend = %d\n", font->max_ascend );
2194 		fprintf( stream, "font.max_descend = %d\n", font->max_descend );
2195 	}
2196 }
2197 
print_asglyph(FILE * stream,ASFont * font,unsigned long c)2198 void print_asglyph( FILE* stream, ASFont* font, unsigned long c)
2199 {
2200 	if( font )
2201 	{
2202 		int i, k ;
2203 		ASGlyph *asg = get_unicode_glyph( c, font );
2204 		if( asg == NULL )
2205 			return;
2206 
2207 		fprintf( stream, "glyph[%lu].ASCII = %c\n", c, (char)c );
2208 		fprintf( stream, "glyph[%lu].width = %d\n", c, asg->width  );
2209 		fprintf( stream, "glyph[%lu].height = %d\n", c, asg->height  );
2210 		fprintf( stream, "glyph[%lu].lead = %d\n", c, asg->lead  );
2211 		fprintf( stream, "glyph[%lu].ascend = %d\n", c, asg->ascend);
2212 		fprintf( stream, "glyph[%lu].descend = %d\n", c, asg->descend );
2213 		k = 0 ;
2214 		fprintf( stream, "glyph[%lu].pixmap = {", c);
2215 #if 1
2216 		for( i = 0 ; i < asg->height*asg->width ; i++ )
2217 		{
2218 			if( asg->pixmap[k]&0x80 )
2219 			{
2220 				fprintf( stream, "%2.2X ", ((asg->pixmap[k]&0x7F)<<1));
2221 			}else
2222 			{
2223 				int count = asg->pixmap[k]&0x3F;
2224 				if( asg->pixmap[k]&0x40 )
2225 					fprintf( stream, "FF(%d times) ", count+1 );
2226 				else
2227 					fprintf( stream, "00(%d times) ", count+1 );
2228 				i += count ;
2229 			}
2230 		    k++;
2231 		}
2232 #endif
2233 		fprintf( stream, "}\nglyph[%lu].used_memory = %d\n", c, k );
2234 	}
2235 }
2236 
2237 
2238 #ifndef HAVE_XRENDER
afterimage_uses_xrender()2239 Bool afterimage_uses_xrender(){ return False;}
2240 
2241 void
draw_text_xrender(ASVisual * asv,const void * text,ASFont * font,ASTextAttributes * attr,int length,int xrender_op,unsigned long xrender_src,unsigned long xrender_dst,int xrender_xSrc,int xrender_ySrc,int xrender_xDst,int xrender_yDst)2242 draw_text_xrender(  ASVisual *asv, const void *text, ASFont *font, ASTextAttributes *attr, int length,
2243 					int xrender_op, unsigned long	xrender_src, unsigned long xrender_dst,
2244 					int	xrender_xSrc,  int xrender_ySrc, int xrender_xDst, int xrender_yDst )
2245 {}
2246 #else
afterimage_uses_xrender()2247 Bool afterimage_uses_xrender(){ return True;}
2248 
2249 void
draw_text_xrender(ASVisual * asv,const void * text,ASFont * font,ASTextAttributes * attr,int length,Picture xrender_src,Picture xrender_dst,int xrender_xSrc,int xrender_ySrc,int xrender_xDst,int xrender_yDst)2250 draw_text_xrender(  ASVisual *asv, const void *text, ASFont *font, ASTextAttributes *attr, int length,
2251 					Picture	xrender_src, Picture xrender_dst,
2252 					int	xrender_xSrc,  int xrender_ySrc, int xrender_xDst, int xrender_yDst )
2253 {
2254 	ASGlyphMap map;
2255 	int max_gid = 0 ;
2256 	int i ;
2257 	int missing_glyphs = 0 ;
2258 	int glyphs_bmap_size = 0, max_height = 0 ;
2259 
2260 	if( !get_text_glyph_map( text, font, &map, attr, length) )
2261 		return;
2262 
2263 	if( map.width == 0 )
2264 		return;
2265 	/* xrender code starts here : */
2266 	/* Step 1: we have to make sure we have a valid GlyphSet */
2267 	if( font->xrender_glyphset == 0 )
2268 		font->xrender_glyphset = XRenderCreateGlyphSet (asv->dpy, asv->xrender_mask_format);
2269 	/* Step 2: we have to make sure all the glyphs are in GlyphSet */
2270 	for( i = 0 ; map.glyphs[i] != GLYPH_EOT ; ++i )
2271 		if( map.glyphs[i] > MAX_SPECIAL_GLYPH && map.glyphs[i]->xrender_gid == 0 )
2272 		{
2273 			glyphs_bmap_size += map.glyphs[i]->width * map.glyphs[i]->height ;
2274 			if( map.glyphs[i]->height > max_height )
2275 				max_height = map.glyphs[i]->height ;
2276 			++missing_glyphs;
2277 		}
2278 
2279 	if( missing_glyphs > 0 )
2280 	{
2281 		Glyph		*gids;
2282 		XGlyphInfo	*glyphs;
2283 		char *bitmap, *bmap_ptr ;
2284 		int	 nbytes_bitmap = 0;
2285 		CARD8 **scanlines ;
2286 
2287 		scanlines = safecalloc(max_height, sizeof(CARD8*));
2288 
2289 		bmap_ptr = bitmap = safemalloc( glyphs_bmap_size );
2290 		glyphs = safecalloc( missing_glyphs, sizeof(XGlyphInfo));
2291 		gids = safecalloc( missing_glyphs, sizeof(Glyph));
2292 		for( i = 0 ; map.glyphs[i] != GLYPH_EOT ; ++i )
2293 			if( map.glyphs[i] > MAX_SPECIAL_GLYPH && map.glyphs[i]->xrender_gid == 0 )
2294 			{
2295 				ASGlyph *asg = map.glyphs[i];
2296 				int k = asg->height ;
2297 				char *ptr = bmap_ptr + asg->width*asg->height ;
2298 				bmap_ptr = ptr ;
2299 				while ( --k >= 0 )
2300 				{
2301 					ptr -= asg->width ;
2302 					scanlines[k] = ptr ;
2303 				}
2304 				render_asglyph( scanlines, asg->pixmap,	0, 0, asg->width, asg->height, 0xFF );
2305 				gids[i] =
2306 			}
2307 		XRenderAddGlyphs( asv->dpy, font->xrender_glyphset, gids, glyphs, missing_glyphs, bitmap, nbytes_bitmap );
2308 		free( gids );
2309 		free( glyphs );
2310 		free( bitmap );
2311 		free( scanlines );
2312 	}
2313 	/* Step 3: actually rendering text  : */
2314 	if( max_gid <= 255 )
2315 	{
2316 		char *string = safemalloc( map->glyphs_num-1 );
2317 		for( i = 0 ; map.glyphs[i] != GLYPH_EOT ; ++i )
2318 			string[i] = map.glyphs[i]->xrender_gid ;
2319 		XRenderCompositeString8 ( asv->dpy, PictOpOver, xrender_src, xrender_dst,
2320 								  asv->xrender_mask_format,
2321 			  					  font->xrender_glyphset,
2322 								  xrender_xSrc,xrender_ySrc,xrender_xDst,xrender_yDst,
2323 								  string, i);
2324 		free( string );
2325 	}else if( max_gid <= 65000 )
2326 	{
2327 		unsigned short *string = safemalloc( sizeof(unsigned short)*(map->glyphs_num-1) );
2328 		for( i = 0 ; map.glyphs[i] != GLYPH_EOT ; ++i )
2329 			string[i] = map.glyphs[i]->xrender_gid ;
2330 		XRenderCompositeString16 (asv->dpy, PictOpOver, xrender_src, xrender_dst,
2331 								  asv->xrender_mask_format,
2332 			  					  font->xrender_glyphset,
2333 								  xrender_xSrc,xrender_ySrc,xrender_xDst,xrender_yDst,
2334 								  string, i);
2335 		free( string );
2336 	}else
2337 	{
2338 		unsigned int *string = safemalloc( sizeof(int)*(map->glyphs_num-1) );
2339 		for( i = 0 ; map.glyphs[i] != GLYPH_EOT ; ++i )
2340 			string[i] = map.glyphs[i]->xrender_gid ;
2341 		XRenderCompositeString32 (asv->dpy, PictOpOver, xrender_src, xrender_dst,
2342 								  asv->xrender_mask_format,
2343 			  					  font->xrender_glyphset,
2344 								  xrender_xSrc,xrender_ySrc,xrender_xDst,xrender_yDst,
2345 								  string, i);
2346 		free( string );
2347 	}
2348 
2349 	/* xrender code ends here : */
2350 	free_glyph_map( &map, True );
2351 }
2352 
2353 #endif
2354 
2355 
2356 /*********************************************************************************/
2357 /* The end !!!! 																 */
2358 /*********************************************************************************/
2359 
2360