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