00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #undef LOCAL_DEBUG
00019 #undef DO_CLOCKING
00020
00021 #ifdef _WIN32
00022 #include "win32/config.h"
00023 #else
00024 #include "config.h"
00025 #endif
00026
00027
00028 #define DO_X11_ANTIALIASING
00029 #define DO_2STEP_X11_ANTIALIASING
00030 #define DO_3STEP_X11_ANTIALIASING
00031 #define X11_AA_HEIGHT_THRESHOLD 10
00032 #define X11_2STEP_AA_HEIGHT_THRESHOLD 15
00033 #define X11_3STEP_AA_HEIGHT_THRESHOLD 15
00034
00035
00036 #ifdef HAVE_UNISTD_H
00037 #include <unistd.h>
00038 #endif
00039 #ifdef HAVE_STDLIB_H
00040 #include <stdlib.h>
00041 #endif
00042 #ifdef HAVE_STDARG_H
00043 #include <stdarg.h>
00044 #endif
00045 #include <ctype.h>
00046 #include <string.h>
00047 #include <stdio.h>
00048 #ifdef DO_CLOCKING
00049 #if TIME_WITH_SYS_TIME
00050 # include <sys/time.h>
00051 # include <time.h>
00052 #else
00053 # if HAVE_SYS_TIME_H
00054 # include <sys/time.h>
00055 # else
00056 # include <time.h>
00057 # endif
00058 #endif
00059 #endif
00060
00061 #ifdef HAVE_FREETYPE
00062 # ifdef HAVE_FT2BUILD_H
00063 # include <ft2build.h>
00064 # include FT_FREETYPE_H
00065 # endif
00066 # ifdef HAVE_FREETYPE_FREETYPE
00067 # include <freetype/freetype.h>
00068 # else
00069 # include <freetype.h>
00070 # endif
00071 # if (FREETYPE_MAJOR == 2) && ((FREETYPE_MINOR == 0) || ((FREETYPE_MINOR == 1) && (FREETYPE_PATCH < 3)))
00072 # define FT_KERNING_DEFAULT ft_kerning_default
00073 # endif
00074 #endif
00075
00076 #define INCLUDE_ASFONT_PRIVATE
00077
00078 #ifdef _WIN32
00079 # include "win32/afterbase.h"
00080 #else
00081 # include "afterbase.h"
00082 #endif
00083 #include "asfont.h"
00084 #include "asimage.h"
00085 #include "asvisual.h"
00086
00087 #ifdef HAVE_XRENDER
00088 #include <X11/extensions/Xrender.h>
00089 #endif
00090
00091 #undef MAX_GLYPHS_PER_FONT
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102 void asfont_destroy (ASHashableValue value, void *data);
00103
00104 ASFontManager *
00105 create_font_manager( Display *dpy, const char * font_path, ASFontManager *reusable_memory )
00106 {
00107 ASFontManager *fontman = reusable_memory;
00108 if( fontman == NULL )
00109 fontman = safecalloc( 1, sizeof(ASFontManager));
00110 else
00111 memset( fontman, 0x00, sizeof(ASFontManager));
00112
00113 fontman->dpy = dpy ;
00114 if( font_path )
00115 fontman->font_path = mystrdup( font_path );
00116
00117 #ifdef HAVE_FREETYPE
00118 if( !FT_Init_FreeType( &(fontman->ft_library)) )
00119 fontman->ft_ok = True ;
00120 else
00121 show_error( "Failed to initialize FreeType library - TrueType Fonts support will be disabled!");
00122 LOCAL_DEBUG_OUT( "Freetype library is %p", fontman->ft_library );
00123 #endif
00124
00125 fontman->fonts_hash = create_ashash( 7, string_hash_value, string_compare, asfont_destroy );
00126
00127 return fontman;
00128 }
00129
00130 void
00131 destroy_font_manager( ASFontManager *fontman, Bool reusable )
00132 {
00133 if( fontman )
00134 {
00135
00136 destroy_ashash( &(fontman->fonts_hash) );
00137
00138 #ifdef HAVE_FREETYPE
00139 FT_Done_FreeType( fontman->ft_library);
00140 fontman->ft_ok = False ;
00141 #endif
00142 if( fontman->font_path )
00143 free( fontman->font_path );
00144
00145 if( !reusable )
00146 free( fontman );
00147 else
00148 memset( fontman, 0x00, sizeof(ASFontManager));
00149 }
00150 }
00151
00152 #ifdef HAVE_FREETYPE
00153 static int load_freetype_glyphs( ASFont *font );
00154 #endif
00155 #ifndef X_DISPLAY_MISSING
00156 static int load_X11_glyphs( Display *dpy, ASFont *font, XFontStruct *xfs );
00157 #endif
00158
00159
00160 static ASFont*
00161 open_freetype_font_int( ASFontManager *fontman, const char *font_string, int face_no, int size, Bool verbose, ASFlagType flags)
00162 {
00163 ASFont *font = NULL ;
00164 #ifdef HAVE_FREETYPE
00165 if( fontman && fontman->ft_ok )
00166 {
00167 char *realfilename;
00168 FT_Face face ;
00169 LOCAL_DEBUG_OUT( "looking for \"%s\" in \"%s\"", font_string, fontman->font_path );
00170 if( (realfilename = find_file( font_string, fontman->font_path, R_OK )) == NULL )
00171 {
00172 char *tmp = mystrdup( font_string );
00173 register int i = 0;
00174 while(tmp[i] != '\0' ) ++i ;
00175 while( --i >= 0 )
00176 if( !isdigit( tmp[i] ) )
00177 {
00178 if( tmp[i] == '.' )
00179 {
00180 face_no = atoi( &tmp[i+1] );
00181 tmp[i] = '\0' ;
00182 }
00183 break;
00184 }
00185 if( i >= 0 && font_string[i] != '\0' )
00186 realfilename = find_file( tmp, fontman->font_path, R_OK );
00187 free( tmp );
00188 }
00189
00190 if( realfilename )
00191 {
00192 face = NULL ;
00193 LOCAL_DEBUG_OUT( "font file found : \"%s\", trying to load face #%d, using library %p", realfilename, face_no, fontman->ft_library );
00194 if( FT_New_Face( fontman->ft_library, realfilename, face_no, &face ) )
00195 {
00196 LOCAL_DEBUG_OUT( "face load failed.%s", "" );
00197
00198 if( face_no > 0 )
00199 {
00200 show_warning( "face %d is not available in font \"%s\" - falling back to first available.", face_no, realfilename );
00201 FT_New_Face( fontman->ft_library, realfilename, 0, &face );
00202 }
00203 }
00204 LOCAL_DEBUG_OUT( "face found : %p", face );
00205 if( face != NULL )
00206 {
00207 #ifdef MAX_GLYPHS_PER_FONT
00208 if( face->num_glyphs > MAX_GLYPHS_PER_FONT )
00209 show_error( "Font \"%s\" contains too many glyphs - %d. Max allowed is %d", realfilename, face->num_glyphs, MAX_GLYPHS_PER_FONT );
00210 else
00211 #endif
00212 {
00213 font = safecalloc( 1, sizeof(ASFont));
00214 font->magic = MAGIC_ASFONT ;
00215 font->fontman = fontman;
00216 font->type = ASF_Freetype ;
00217 font->flags = flags ;
00218 font->ft_face = face ;
00219 if( FT_HAS_KERNING( face ) )
00220 {
00221 set_flags( font->flags, ASF_HasKerning );
00222
00223 }
00224
00225
00226 FT_Set_Pixel_Sizes( font->ft_face, size, size );
00227
00228 font->space_size = size*2/3 ;
00229 load_freetype_glyphs( font );
00230 }
00231 }else if( verbose )
00232 show_error( "FreeType library failed to load font \"%s\"", realfilename );
00233
00234 if( realfilename != font_string )
00235 free( realfilename );
00236 }
00237 }
00238 #endif
00239 return font;
00240 }
00241
00242 ASFont*
00243 open_freetype_font( ASFontManager *fontman, const char *font_string, int face_no, int size, Bool verbose)
00244 {
00245 return open_freetype_font_int( fontman, font_string, face_no, size, verbose, 0);
00246 }
00247
00248 static ASFont*
00249 open_X11_font_int( ASFontManager *fontman, const char *font_string, ASFlagType flags)
00250 {
00251 ASFont *font = NULL ;
00252 #ifndef X_DISPLAY_MISSING
00253
00254
00255
00256
00257
00258
00259
00260 XFontStruct *xfs ;
00261 if( fontman->dpy == NULL )
00262 return NULL;
00263 if( (xfs = XLoadQueryFont( fontman->dpy, font_string )) == NULL )
00264 {
00265 show_warning( "failed to load X11 font \"%s\". Sorry about that.", font_string );
00266 return NULL;
00267 }
00268 font = safecalloc( 1, sizeof(ASFont));
00269 font->magic = MAGIC_ASFONT ;
00270 font->fontman = fontman;
00271 font->type = ASF_X11 ;
00272 font->flags = flags ;
00273 load_X11_glyphs( fontman->dpy, font, xfs );
00274 XFreeFont( fontman->dpy, xfs );
00275 #endif
00276 return font;
00277 }
00278
00279 ASFont*
00280 open_X11_font( ASFontManager *fontman, const char *font_string)
00281 {
00282 return open_X11_font_int( fontman, font_string, 0);
00283 }
00284
00285 ASFont*
00286 get_asfont( ASFontManager *fontman, const char *font_string, int face_no, int size, ASFontType type_and_flags )
00287 {
00288 ASFont *font = NULL ;
00289 Bool freetype = False ;
00290 int type = type_and_flags&ASF_TypeMask ;
00291 if( face_no >= 100 )
00292 face_no = 0 ;
00293 if( size >= 1000 )
00294 size = 999 ;
00295
00296 if( fontman && font_string )
00297 {
00298 ASHashData hdata = { 0 };
00299 if( get_hash_item( fontman->fonts_hash, AS_HASHABLE((char*)font_string), &hdata.vptr) != ASH_Success )
00300 {
00301 char *ff_name ;
00302 int len = strlen( font_string)+1 ;
00303 len += ((size>=100)?3:2)+1 ;
00304 len += ((face_no>=10)?2:1)+1 ;
00305 ff_name = safemalloc( len );
00306 sprintf( ff_name, "%s$%d$%d", font_string, size, face_no );
00307 if( get_hash_item( fontman->fonts_hash, AS_HASHABLE((char*)ff_name), &hdata.vptr) != ASH_Success )
00308 {
00309 if( type == ASF_Freetype || type == ASF_GuessWho )
00310 font = open_freetype_font_int( fontman, font_string, face_no, size, (type == ASF_Freetype), get_flags(type_and_flags,~ASF_TypeMask));
00311 if( font == NULL && type != ASF_Freetype )
00312 {
00313 font = open_X11_font_int( fontman, font_string, get_flags(type_and_flags,~ASF_TypeMask) );
00314 }else
00315 freetype = True ;
00316 if( font != NULL )
00317 {
00318 if( freetype )
00319 {
00320 font->name = ff_name ;
00321 ff_name = NULL ;
00322 }else
00323 font->name = mystrdup( font_string );
00324 add_hash_item( fontman->fonts_hash, AS_HASHABLE((char*)font->name), font);
00325 }
00326 }
00327 if( ff_name != NULL )
00328 free( ff_name );
00329 }
00330
00331 if( font == NULL )
00332 font = hdata.vptr ;
00333
00334 if( font )
00335 font->ref_count++ ;
00336 }
00337 return font;
00338 }
00339
00340 ASFont*
00341 dup_asfont( ASFont *font )
00342 {
00343 if( font && font->fontman )
00344 font->ref_count++ ;
00345 else
00346 font = NULL;
00347 return font;
00348 }
00349
00350 int
00351 release_font( ASFont *font )
00352 {
00353 int res = -1 ;
00354 if( font )
00355 {
00356 if( font->magic == MAGIC_ASFONT )
00357 {
00358 if( --(font->ref_count) < 0 )
00359 {
00360 ASFontManager *fontman = font->fontman ;
00361 if( fontman )
00362 remove_hash_item(fontman->fonts_hash, (ASHashableValue)(char*)font->name, NULL, True);
00363 }else
00364 res = font->ref_count ;
00365 }
00366 }
00367 return res ;
00368 }
00369
00370 static inline void
00371 free_glyph_data( register ASGlyph *asg )
00372 {
00373 if( asg->pixmap )
00374 free( asg->pixmap );
00375
00376 asg->pixmap = NULL ;
00377 }
00378
00379 static void
00380 destroy_glyph_range( ASGlyphRange **pgr )
00381 {
00382 ASGlyphRange *gr = *pgr;
00383 if( gr )
00384 {
00385 *pgr = gr->above ;
00386 if( gr->below )
00387 gr->below->above = gr->above ;
00388 if( gr->above )
00389 gr->above->below = gr->below ;
00390 if( gr->glyphs )
00391 {
00392 int max_i = ((int)gr->max_char-(int)gr->min_char)+1 ;
00393 register int i = -1 ;
00394
00395 while( ++i < max_i )
00396 {
00397
00398 free_glyph_data( &(gr->glyphs[i]) );
00399 }
00400 free( gr->glyphs );
00401 gr->glyphs = NULL ;
00402 }
00403 free( gr );
00404 }
00405 }
00406
00407 static void
00408 destroy_font( ASFont *font )
00409 {
00410 if( font )
00411 {
00412 #ifdef HAVE_FREETYPE
00413 if( font->type == ASF_Freetype && font->ft_face )
00414 FT_Done_Face(font->ft_face);
00415 #endif
00416 if( font->name )
00417 free( font->name );
00418 while( font->codemap )
00419 destroy_glyph_range( &(font->codemap) );
00420 free_glyph_data( &(font->default_glyph) );
00421 if( font->locale_glyphs )
00422 destroy_ashash( &(font->locale_glyphs) );
00423 font->magic = 0 ;
00424 free( font );
00425 }
00426 }
00427
00428 void
00429 asglyph_destroy (ASHashableValue value, void *data)
00430 {
00431 if( data )
00432 {
00433 free_glyph_data( (ASGlyph*)data );
00434 free( data );
00435 }
00436 }
00437
00438 void
00439 asfont_destroy (ASHashableValue value, void *data)
00440 {
00441 if( data )
00442 {
00443 char* cval = (char*)value ;
00444 if( ((ASMagic*)data)->magic == MAGIC_ASFONT )
00445 {
00446 if( cval == ((ASFont*)data)->name )
00447 cval = NULL ;
00448
00449 destroy_font( (ASFont*)data );
00450
00451 }
00452 if( cval )
00453 free( cval );
00454 }
00455 }
00456
00457
00458
00459
00460
00461 static unsigned char *
00462 compress_glyph_pixmap( unsigned char *src, unsigned char *buffer,
00463 unsigned int width, unsigned int height,
00464 int src_step )
00465 {
00466 unsigned char *pixmap ;
00467 register unsigned char *dst = buffer ;
00468 register int k = 0, i = 0 ;
00469 int count = -1;
00470 unsigned char last = src[0];
00471
00472
00473
00474
00475
00476
00477 while ( height)
00478 {
00479 if( src[k] != last || (last != 0 && last != 0xFF) || count >= 63 )
00480 {
00481 if( count == 0 )
00482 dst[i++] = (last>>1)|0x80;
00483 else if( count > 0 )
00484 {
00485 if( last == 0xFF )
00486 count |= 0x40 ;
00487 dst[i++] = count;
00488 count = 0 ;
00489 }else
00490 count = 0 ;
00491 last = src[k] ;
00492 }else
00493 count++ ;
00494
00495 if( ++k >= (int)width )
00496 {
00497
00498 --height ;
00499 k = 0 ;
00500 src += src_step ;
00501 }
00502 }
00503 if( count == 0 )
00504 dst[i++] = (last>>1)|0x80;
00505 else
00506 {
00507 if( last == 0xFF )
00508 count |= 0x40 ;
00509 dst[i++] = count;
00510 }
00511 pixmap = safemalloc( i);
00512
00513 memcpy( pixmap, buffer, i );
00514
00515 return pixmap;
00516 }
00517
00518 #ifdef DO_X11_ANTIALIASING
00519 void
00520 antialias_glyph( unsigned char *buffer, unsigned int width, unsigned int height )
00521 {
00522 unsigned char *row1, *row2 ;
00523 register unsigned char *row ;
00524 register int x;
00525 int y;
00526
00527 row1 = &(buffer[0]);
00528 row = &(buffer[width]);
00529 row2 = &(buffer[width+width]);
00530 for( x = 1 ; x < (int)width-1 ; x++ )
00531 if( row1[x] == 0 )
00532 {
00533 unsigned int c = (unsigned int)row[x]+
00534 (unsigned int)row1[x-1]+
00535 (unsigned int)row1[x+1];
00536 if( c >= 0x01FE )
00537 row1[x] = c>>2;
00538 }
00539 for( y = 1 ; y < (int)height-1 ; y++ )
00540 {
00541 if( row[0] == 0 )
00542 {
00543 unsigned int c = (unsigned int)row1[0]+
00544 (unsigned int)row[1]+
00545 (unsigned int)row2[0];
00546 if( c >= 0x01FE )
00547 row[0] = c>>2;
00548 }
00549 for( x = 1 ; x < (int)width-1 ; x++ )
00550 {
00551 if( row[x] == 0 )
00552 {
00553 unsigned int c = (unsigned int)row1[x]+
00554 (unsigned int)row[x-1]+
00555 (unsigned int)row[x+1]+
00556 (unsigned int)row2[x];
00557 if( row1[x] != 0 && row[x-1] != 0 && row[x+1] != 0 && row2[x] != 0 &&
00558 c >= 0x01FE )
00559 row[x] = c>>3;
00560 else if( c >= 0x01FE )
00561 row[x] = c>>2;
00562 }
00563 }
00564 if( row[x] == 0 )
00565 {
00566 unsigned int c = (unsigned int)row1[x]+
00567 (unsigned int)row[x-1]+
00568 (unsigned int)row2[x];
00569 if( c >= 0x01FE )
00570 row[x] = c>>2;
00571 }
00572 row += width ;
00573 row1 += width ;
00574 row2 += width ;
00575 }
00576 for( x = 1 ; x < (int)width-1 ; x++ )
00577 if( row[x] == 0 )
00578 {
00579 unsigned int c = (unsigned int)row1[x]+
00580 (unsigned int)row[x-1]+
00581 (unsigned int)row[x+1];
00582 if( c >= 0x01FE )
00583 row[x] = c>>2;
00584 }
00585 #ifdef DO_2STEP_X11_ANTIALIASING
00586 if( height > X11_2STEP_AA_HEIGHT_THRESHOLD )
00587 {
00588 row1 = &(buffer[0]);
00589 row = &(buffer[width]);
00590 row2 = &(buffer[width+width]);
00591 for( y = 1 ; y < (int)height-1 ; y++ )
00592 {
00593 for( x = 1 ; x < (int)width-1 ; x++ )
00594 {
00595 if( row[x] == 0 )
00596 {
00597 unsigned int c = (unsigned int)row1[x]+
00598 (unsigned int)row[x-1]+
00599 (unsigned int)row[x+1]+
00600 (unsigned int)row2[x];
00601 if( row1[x] != 0 && row[x-1] != 0 && row[x+1] != 0 && row2[x] != 0
00602 && c >= 0x00FF+0x007F)
00603 row[x] = c>>3;
00604 else if( (c >= 0x00FF+0x007F)|| c == 0x00FE )
00605 row[x] = c>>2;
00606 }
00607 }
00608 row += width ;
00609 row1 += width ;
00610 row2 += width ;
00611 }
00612 }
00613 #endif
00614 #ifdef DO_3STEP_X11_ANTIALIASING
00615 if( height > X11_3STEP_AA_HEIGHT_THRESHOLD )
00616 {
00617 row1 = &(buffer[0]);
00618 row = &(buffer[width]);
00619 row2 = &(buffer[width+width]);
00620 for( y = 1 ; y < (int)height-1 ; y++ )
00621 {
00622 for( x = 1 ; x < (int)width-1 ; x++ )
00623 {
00624 if( row[x] == 0xFF )
00625 {
00626 if( row1[x] < 0xFE || row2[x] < 0xFE )
00627 if( row[x+1] < 0xFE || row[x-1] < 0xFE )
00628 row[x] = 0xFE;
00629 }
00630 }
00631 row += width ;
00632 row1 += width ;
00633 row2 += width ;
00634 }
00635 row = &(buffer[width]);
00636 for( y = 1 ; y < (int)height-1 ; y++ )
00637 {
00638 for( x = 1 ; x < (int)width-1 ; x++ )
00639 if( row[x] == 0xFE )
00640 row[x] = 0xBF ;
00641 row += width ;
00642 }
00643 }
00644
00645 #endif
00646 }
00647 #endif
00648
00649 static void
00650 scale_down_glyph_width( unsigned char *buffer, int from_width, int to_width, int height )
00651 {
00652 int smaller = to_width;
00653 int bigger = from_width;
00654 register int i = 0, k = 0, l;
00655
00656
00657
00658
00659
00660 for( l = 0 ; l < height ; ++l )
00661 {
00662 unsigned char *ptr = &(buffer[l*from_width]) ;
00663 CARD32 sum = 0;
00664 int count = 0 ;
00665 int eps = -bigger/2;
00666
00667 k = 0 ;
00668 for ( i = 0 ; i < bigger ; i++ )
00669 {
00670
00671 sum += (unsigned int)ptr[i] ;
00672 ++count ;
00673 eps += smaller;
00674
00675 if( eps+eps >= bigger )
00676 {
00677
00678
00679 ptr[k] = ( count > 1 )?sum/count:sum ;
00680 sum = 0 ;
00681 count = 0 ;
00682 ++k ;
00683 eps -= bigger ;
00684 }
00685 }
00686 }
00687
00688
00689 l = to_width ;
00690 k = from_width ;
00691 do
00692 {
00693 for( i = 0 ; i < to_width; ++i )
00694 buffer[l+i] = buffer[k+i];
00695 l += to_width ;
00696 k += from_width ;
00697 }while( l < to_width*height );
00698 }
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714 #ifndef X_DISPLAY_MISSING
00715 static ASGlyphRange*
00716 split_X11_glyph_range( unsigned int min_char, unsigned int max_char, XCharStruct *chars )
00717 {
00718 ASGlyphRange *first = NULL, **r = &first;
00719 int c = 0, delta = (max_char-min_char)+1;
00720 LOCAL_DEBUG_CALLER_OUT( "min_char = %u, max_char = %u, chars = %p", min_char, max_char, chars );
00721 while( c < delta )
00722 {
00723 while( c < delta && chars[c].width == 0 ) ++c;
00724
00725 if( c < delta )
00726 {
00727 *r = safecalloc( 1, sizeof(ASGlyphRange));
00728 (*r)->min_char = c+min_char ;
00729 while( c < delta && chars[c].width != 0 ) ++c ;
00730 (*r)->max_char = (c-1)+min_char;
00731 LOCAL_DEBUG_OUT( "created glyph range from %lu to %lu", (*r)->min_char, (*r)->max_char );
00732 r = &((*r)->above);
00733 }
00734 }
00735 return first;
00736 }
00737
00738 void
00739 load_X11_glyph_range( Display *dpy, ASFont *font, XFontStruct *xfs, size_t char_offset,
00740 unsigned char byte1,
00741 unsigned char min_byte2,
00742 unsigned char max_byte2, GC *gc )
00743 {
00744 ASGlyphRange *all, *r ;
00745 unsigned long min_char = (byte1<<8)|min_byte2;
00746 unsigned char *buffer, *compressed_buf ;
00747 unsigned int height = xfs->ascent+xfs->descent ;
00748 static XGCValues gcv;
00749
00750 buffer = safemalloc( xfs->max_bounds.width*height*2);
00751 compressed_buf = safemalloc( xfs->max_bounds.width*height*4);
00752 all = split_X11_glyph_range( min_char, (byte1<<8)|max_byte2, &(xfs->per_char[char_offset]));
00753 for( r = all ; r != NULL ; r = r->above )
00754 {
00755 XCharStruct *chars = &(xfs->per_char[char_offset+r->min_char-min_char]);
00756 int len = ((int)r->max_char-(int)r->min_char)+1;
00757 unsigned char char_base = r->min_char&0x00FF;
00758 register int i ;
00759 Pixmap p;
00760 XImage *xim;
00761 unsigned int total_width = 0 ;
00762 int pen_x = 0;
00763 LOCAL_DEBUG_OUT( "loading glyph range of %lu-%lu", r->min_char, r->max_char );
00764 r->glyphs = safecalloc( len, sizeof(ASGlyph) );
00765 for( i = 0 ; i < len ; i++ )
00766 {
00767 int w = chars[i].rbearing - chars[i].lbearing ;
00768 r->glyphs[i].lead = chars[i].lbearing ;
00769 r->glyphs[i].width = MAX(w,(int)chars[i].width) ;
00770 r->glyphs[i].step = chars[i].width;
00771 total_width += r->glyphs[i].width ;
00772 if( chars[i].lbearing > 0 )
00773 total_width += chars[i].lbearing ;
00774 }
00775 p = XCreatePixmap( dpy, DefaultRootWindow(dpy), total_width, height, 1 );
00776 if( *gc == NULL )
00777 {
00778 gcv.font = xfs->fid;
00779 gcv.foreground = 1;
00780 *gc = XCreateGC( dpy, p, GCFont|GCForeground, &gcv);
00781 }else
00782 XSetForeground( dpy, *gc, 1 );
00783 XFillRectangle( dpy, p, *gc, 0, 0, total_width, height );
00784 XSetForeground( dpy, *gc, 0 );
00785
00786 for( i = 0 ; i < len ; i++ )
00787 {
00788 XChar2b test_char ;
00789 int offset = MIN(0,(int)chars[i].lbearing);
00790
00791 test_char.byte1 = byte1 ;
00792 test_char.byte2 = char_base+i ;
00793
00794
00795 XDrawImageString16( dpy, p, *gc, pen_x-offset, xfs->ascent, &test_char, 1 );
00796 pen_x += r->glyphs[i].width ;
00797 if( chars[i].lbearing > 0 )
00798 pen_x += chars[i].lbearing ;
00799 }
00800
00801 xim = XGetImage( dpy, p, 0, 0, total_width, height, 0xFFFFFFFF, ZPixmap );
00802 XFreePixmap( dpy, p );
00803 pen_x = 0 ;
00804 for( i = 0 ; i < len ; i++ )
00805 {
00806 register int x, y ;
00807 int width = r->glyphs[i].width;
00808 unsigned char *row = &(buffer[0]);
00809
00810 if( chars[i].lbearing > 0 )
00811 pen_x += chars[i].lbearing ;
00812 for( y = 0 ; y < height ; y++ )
00813 {
00814 for( x = 0 ; x < width ; x++ )
00815 {
00816
00817
00818
00819 row[x] = ( XGetPixel( xim, pen_x+x, y ) != 0 )? 0x00:0xFF;
00820 }
00821 row += width;
00822 }
00823
00824 #ifdef DO_X11_ANTIALIASING
00825 if( height > X11_AA_HEIGHT_THRESHOLD )
00826 antialias_glyph( buffer, width, height );
00827 #endif
00828 if( get_flags( font->flags, ASF_Monospaced ) )
00829 {
00830 if( r->glyphs[i].lead > 0 && (int)width + (int)r->glyphs[i].lead > (int)font->space_size )
00831 if( r->glyphs[i].lead > (int)font->space_size/8 )
00832 r->glyphs[i].lead = (int)font->space_size/8 ;
00833 if( (int)width + r->glyphs[i].lead > (int)font->space_size )
00834 {
00835 r->glyphs[i].width = (int)font->space_size - r->glyphs[i].lead ;
00836
00837
00838 scale_down_glyph_width( buffer, width, r->glyphs[i].width, height );
00839 }
00840
00841
00842
00843
00844
00845 r->glyphs[i].step = font->space_size ;
00846 }
00847 r->glyphs[i].pixmap = compress_glyph_pixmap( buffer, compressed_buf, r->glyphs[i].width, height, r->glyphs[i].width );
00848 r->glyphs[i].height = height ;
00849 r->glyphs[i].ascend = xfs->ascent ;
00850 r->glyphs[i].descend = xfs->descent ;
00851 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 );
00852 pen_x += width ;
00853 }
00854 if( xim )
00855 XDestroyImage( xim );
00856 }
00857 LOCAL_DEBUG_OUT( "done loading glyphs. Attaching set of glyph ranges to the codemap...%s", "" );
00858 if( all != NULL )
00859 {
00860 if( font->codemap == NULL )
00861 font->codemap = all ;
00862 else
00863 {
00864 for( r = font->codemap ; r != NULL ; r = r->above )
00865 {
00866 if( r->min_char > all->min_char )
00867 {
00868 if( r->below )
00869 r->below->above = all ;
00870 r->below = all ;
00871 while ( all->above != NULL )
00872 all = all->above ;
00873 all->above = r ;
00874 r->below = all ;
00875 break;
00876 }
00877 all->below = r ;
00878 }
00879 if( r == NULL && all->below->above == NULL )
00880 all->below->above = all ;
00881 }
00882 }
00883 free( buffer ) ;
00884 free( compressed_buf ) ;
00885 LOCAL_DEBUG_OUT( "all don%s", "" );
00886 }
00887
00888
00889 void
00890 make_X11_default_glyph( ASFont *font, XFontStruct *xfs )
00891 {
00892 unsigned char *buf, *compressed_buf ;
00893 int width, height ;
00894 int x, y;
00895 unsigned char *row ;
00896
00897
00898 height = xfs->ascent+xfs->descent ;
00899 width = xfs->max_bounds.width ;
00900
00901 if( height <= 0 ) height = 4;
00902 if( width <= 0 ) width = 4;
00903 buf = safecalloc( height*width, sizeof(unsigned char) );
00904 compressed_buf = safemalloc( height*width*2 );
00905 row = buf;
00906 for( x = 0 ; x < width ; ++x )
00907 row[x] = 0xFF;
00908 for( y = 1 ; y < height-1 ; ++y )
00909 {
00910 row += width ;
00911 row[0] = 0xFF ; row[width-1] = 0xFF ;
00912 }
00913 for( x = 0 ; x < width ; ++x )
00914 row[x] = 0xFF;
00915 font->default_glyph.pixmap = compress_glyph_pixmap( buf, compressed_buf, width, height, width );
00916 font->default_glyph.width = width ;
00917 font->default_glyph.step = width ;
00918 font->default_glyph.height = height ;
00919 font->default_glyph.lead = 0 ;
00920 font->default_glyph.ascend = xfs->ascent ;
00921 font->default_glyph.descend = xfs->descent ;
00922
00923 free( buf ) ;
00924 free( compressed_buf ) ;
00925 }
00926
00927 static int
00928 load_X11_glyphs( Display *dpy, ASFont *font, XFontStruct *xfs )
00929 {
00930 GC gc = NULL;
00931 font->max_height = xfs->ascent+xfs->descent;
00932 font->max_ascend = xfs->ascent;
00933 font->max_descend = xfs->descent;
00934 font->space_size = xfs->max_bounds.width ;
00935 if( !get_flags( font->flags, ASF_Monospaced) )
00936 font->space_size = font->space_size*2/3 ;
00937
00938 #if 0
00939 if( xfs->max_byte1 > 0 && xfs->min_byte1 > 0 )
00940 {
00941
00942 char_num *= rows ;
00943 }else
00944 {
00945 int i;
00946 int min_byte1 = (xfs->min_char_or_byte2>>8)&0x00FF;
00947 int max_byte1 = (xfs->max_char_or_byte2>>8)&0x00FF;
00948 size_t offset = MAX(0x00FF,(int)xfs->max_char_or_byte2-(int)(min_byte1<<8)) ;
00949
00950 load_X11_glyph_range( dpy, font, xfs, 0, min_byte1,
00951 xfs->min_char_or_byte2-(min_byte1<<8),
00952 offset, &gc );
00953 offset -= xfs->min_char_or_byte2-(min_byte1<<8);
00954 if( max_byte1 > min_byte1 )
00955 {
00956 for( i = min_byte1+1; i < max_byte1 ; i++ )
00957 {
00958 load_X11_glyph_range( dpy, font, xfs, offset, i, 0x00, 0xFF, &gc );
00959 offset += 256 ;
00960 }
00961 load_X11_glyph_range( dpy, font, xfs, offset, max_byte1,
00962 0,
00963 (int)xfs->max_char_or_byte2-(int)(max_byte1<<8), &gc );
00964 }
00965 }
00966 #else
00967 {
00968
00969 int min_char, max_char, our_min_char = 0x0021, our_max_char = 0x00FF ;
00970 int byte1 = xfs->min_byte1;
00971 if( xfs->min_byte1 > 0 )
00972 {
00973 min_char = xfs->min_char_or_byte2 ;
00974 max_char = xfs->max_char_or_byte2 ;
00975 if( min_char > 0x00FF )
00976 {
00977 byte1 = (min_char>>8)&0x00FF;
00978 min_char &= 0x00FF;
00979 if( ((max_char>>8)&0x00FF) > byte1 )
00980 max_char = 0x00FF;
00981 else
00982 max_char &= 0x00FF;
00983 }
00984 }else
00985 {
00986 min_char = ((xfs->min_byte1<<8)&0x00FF00)|(xfs->min_char_or_byte2&0x00FF);
00987 max_char = ((xfs->min_byte1<<8)&0x00FF00)|(xfs->max_char_or_byte2&0x00FF);
00988 our_min_char |= ((xfs->min_byte1<<8)&0x00FF00) ;
00989 our_max_char |= ((xfs->min_byte1<<8)&0x00FF00) ;
00990 }
00991 our_min_char = MAX(our_min_char,min_char);
00992 our_max_char = MIN(our_max_char,max_char);
00993
00994 load_X11_glyph_range( dpy, font, xfs, (int)our_min_char-(int)min_char, byte1, our_min_char&0x00FF, our_max_char&0x00FF, &gc );
00995 }
00996 #endif
00997 if( font->default_glyph.pixmap == NULL )
00998 make_X11_default_glyph( font, xfs );
00999 if( gc )
01000 XFreeGC( dpy, gc );
01001 return xfs->ascent+xfs->descent;
01002 }
01003 #endif
01004
01005 #ifdef HAVE_FREETYPE
01006 static void
01007 load_glyph_freetype( ASFont *font, ASGlyph *asg, int glyph, UNICODE_CHAR uc )
01008 {
01009 register FT_Face face ;
01010 static CARD8 *glyph_compress_buf = NULL, *glyph_scaling_buf = NULL ;
01011 static int glyph_compress_buf_size = 0, glyph_scaling_buf_size = 0;
01012
01013 if( font == NULL )
01014 {
01015 if( glyph_compress_buf )
01016 {
01017 free( glyph_compress_buf );
01018 glyph_compress_buf = NULL ;
01019 }
01020 if( glyph_scaling_buf )
01021 {
01022 free( glyph_scaling_buf );
01023 glyph_scaling_buf = NULL ;
01024 }
01025 glyph_compress_buf_size = 0 ;
01026 glyph_scaling_buf_size = 0 ;
01027 return;
01028 }
01029
01030 face = font->ft_face;
01031 if( FT_Load_Glyph( face, glyph, FT_LOAD_DEFAULT ) )
01032 return;
01033
01034 if( FT_Render_Glyph( face->glyph, ft_render_mode_normal ) )
01035 return;
01036
01037 if( face->glyph->bitmap.buffer )
01038 {
01039 FT_Bitmap *bmap = &(face->glyph->bitmap) ;
01040 register CARD8 *src = bmap->buffer ;
01041 int src_step ;
01042
01043
01044 asg->font_gid = glyph ;
01045 asg->width = bmap->width ;
01046 asg->height = bmap->rows ;
01047
01048 if( uc >= 0x0300 && uc <= 0x0362 )
01049 asg->step = 0 ;
01050 else
01051 #if 0
01052 asg->step = bmap->width+face->glyph->bitmap_left ;
01053 #else
01054 asg->step = (short)face->glyph->advance.x>>6 ;
01055 #endif
01056
01057
01058 if( uc >= 0x0300 && uc <= 0x0362 && face->glyph->bitmap_left >= 0 )
01059 asg->lead = -((int)font->space_size - (int)face->glyph->bitmap_left) ;
01060 else
01061 asg->lead = face->glyph->bitmap_left;
01062
01063 if( bmap->pitch < 0 )
01064 src += -bmap->pitch*bmap->rows ;
01065 src_step = bmap->pitch ;
01066
01067
01068 if( get_flags( font->flags, ASF_Monospaced ) && ( uc < 0x0300 || uc > 0x0362 ) )
01069 {
01070 if( asg->lead < 0 )
01071 {
01072 if( asg->lead < -(int)font->space_size/8 )
01073 asg->lead = -(int)font->space_size/8 ;
01074 if( (int)asg->width + asg->lead <= (int)font->space_size )
01075 {
01076 asg->lead = (int)font->space_size - (int)asg->width ;
01077 if( asg->lead > 0 )
01078 asg->lead /= 2 ;
01079 }
01080 }else
01081 {
01082 if( (int)asg->width + (int)asg->lead > (int)font->space_size )
01083 {
01084 if( asg->lead > (int)font->space_size/8 )
01085 asg->lead = (int)font->space_size/8 ;
01086 }else
01087 asg->lead += ((int)font->space_size - ((int)asg->width+asg->lead))/2 ;
01088 }
01089 if( (int)asg->width + asg->lead > (int)font->space_size )
01090 {
01091 register CARD8 *buf ;
01092 int i ;
01093 asg->width = (int)font->space_size - asg->lead ;
01094 if( glyph_scaling_buf_size < bmap->width*bmap->rows*2 )
01095 {
01096 glyph_scaling_buf_size = bmap->width*bmap->rows*2;
01097 glyph_scaling_buf = realloc( glyph_scaling_buf, glyph_scaling_buf_size );
01098 }
01099 buf = &(glyph_scaling_buf[0]);
01100 for( i = 0 ; i < bmap->rows ; ++i )
01101 {
01102 int k = bmap->width;
01103 while( --k >= 0 )
01104 buf[k] = src[k] ;
01105 buf += bmap->width ;
01106 src += src_step ;
01107 }
01108 src = &(glyph_scaling_buf[0]);
01109 scale_down_glyph_width( src, bmap->width, asg->width, asg->height );
01110 src_step = asg->width ;
01111
01112
01113 }
01114
01115
01116
01117
01118
01119 asg->step = font->space_size ;
01120 }
01121
01122
01123 if( glyph_compress_buf_size < asg->width*asg->height*3 )
01124 {
01125 glyph_compress_buf_size = asg->width*asg->height*3;
01126 glyph_compress_buf = realloc( glyph_compress_buf, glyph_compress_buf_size );
01127 }
01128
01129
01130 asg->pixmap = compress_glyph_pixmap( src, glyph_compress_buf, asg->width, asg->height, src_step );
01131 asg->ascend = face->glyph->bitmap_top;
01132 asg->descend = bmap->rows - asg->ascend;
01133 LOCAL_DEBUG_OUT( "glyph %p with FT index %u is %dx%d ascend = %d, lead = %d, bmap_top = %d",
01134 asg, glyph, asg->width, asg->height, asg->ascend, asg->lead,
01135 face->glyph->bitmap_top );
01136 }
01137 }
01138
01139 static ASGlyphRange*
01140 split_freetype_glyph_range( unsigned long min_char, unsigned long max_char, FT_Face face )
01141 {
01142 ASGlyphRange *first = NULL, **r = &first;
01143 LOCAL_DEBUG_CALLER_OUT( "min_char = %lu, max_char = %lu, face = %p", min_char, max_char, face );
01144 while( min_char <= max_char )
01145 {
01146 register unsigned long i = min_char;
01147 while( i <= max_char && FT_Get_Char_Index( face, CHAR2UNICODE(i)) == 0 ) i++ ;
01148 if( i <= max_char )
01149 {
01150 *r = safecalloc( 1, sizeof(ASGlyphRange));
01151 (*r)->min_char = i ;
01152 while( i <= max_char && FT_Get_Char_Index( face, CHAR2UNICODE(i)) != 0 ) i++ ;
01153 (*r)->max_char = i ;
01154 LOCAL_DEBUG_OUT( "created glyph range from %lu to %lu", (*r)->min_char, (*r)->max_char );
01155 r = &((*r)->above);
01156 }
01157 min_char = i ;
01158 }
01159 return first;
01160 }
01161
01162 static ASGlyph*
01163 load_freetype_locale_glyph( ASFont *font, UNICODE_CHAR uc )
01164 {
01165 ASGlyph *asg = NULL ;
01166 if( FT_Get_Char_Index( font->ft_face, uc) != 0 )
01167 {
01168 asg = safecalloc( 1, sizeof(ASGlyph));
01169 load_glyph_freetype( font, asg, FT_Get_Char_Index( font->ft_face, uc), uc);
01170 if( add_hash_item( font->locale_glyphs, AS_HASHABLE(uc), asg ) != ASH_Success )
01171 {
01172 LOCAL_DEBUG_OUT( "Failed to add glyph %p for char %ld to hash", asg, uc );
01173 asglyph_destroy( 0, asg);
01174 asg = NULL ;
01175 }else
01176 {
01177 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 );
01178
01179 if( asg->ascend > font->max_ascend )
01180 font->max_ascend = asg->ascend ;
01181 if( asg->descend > font->max_descend )
01182 font->max_descend = asg->descend ;
01183 font->max_height = font->max_ascend+font->max_descend ;
01184 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 );
01185 }
01186 }else
01187 add_hash_item( font->locale_glyphs, AS_HASHABLE(uc), NULL );
01188 return asg;
01189 }
01190
01191 static void
01192 load_freetype_locale_glyphs( unsigned long min_char, unsigned long max_char, ASFont *font )
01193 {
01194 register unsigned long i = min_char ;
01195 LOCAL_DEBUG_CALLER_OUT( "min_char = %lu, max_char = %lu, font = %p", min_char, max_char, font );
01196 if( font->locale_glyphs == NULL )
01197 font->locale_glyphs = create_ashash( 0, NULL, NULL, asglyph_destroy );
01198 while( i <= max_char )
01199 {
01200 load_freetype_locale_glyph( font, CHAR2UNICODE(i));
01201 ++i;
01202 }
01203 LOCAL_DEBUG_OUT( "font attr(%d,%d,%d)", font->max_ascend, font->max_descend, font->max_height );
01204 }
01205
01206
01207 static int
01208 load_freetype_glyphs( ASFont *font )
01209 {
01210 int max_ascend = 0, max_descend = 0;
01211 ASGlyphRange *r ;
01212
01213
01214
01215
01216 font->codemap = split_freetype_glyph_range( 0x0021, 0x007F, font->ft_face );
01217
01218 load_glyph_freetype( font, &(font->default_glyph), 0, 0);
01219 load_freetype_locale_glyphs( 0x0080, 0x00FF, font );
01220 if( font->codemap == NULL )
01221 {
01222 font->max_height = font->default_glyph.ascend+font->default_glyph.descend;
01223 if( font->max_height <= 0 )
01224 font->max_height = 1 ;
01225 font->max_ascend = MAX((int)font->default_glyph.ascend,1);
01226 font->max_descend = MAX((int)font->default_glyph.descend,1);
01227 }else
01228 {
01229 for( r = font->codemap ; r != NULL ; r = r->above )
01230 {
01231 long min_char = r->min_char ;
01232 long max_char = r->max_char ;
01233 long i ;
01234 if( max_char < min_char )
01235 {
01236 i = max_char ;
01237 max_char = min_char ;
01238 min_char = i ;
01239 }
01240 r->glyphs = safecalloc( (max_char - min_char) + 1, sizeof(ASGlyph));
01241 for( i = min_char ; i < max_char ; ++i )
01242 {
01243 if( i != ' ' && i != '\t' && i!= '\n' )
01244 {
01245 ASGlyph *asg = &(r->glyphs[i-min_char]);
01246 UNICODE_CHAR uc = CHAR2UNICODE(i);
01247 load_glyph_freetype( font, asg, FT_Get_Char_Index( font->ft_face, uc), uc);
01248
01249
01250
01251
01252 if( asg->ascend > max_ascend )
01253 max_ascend = asg->ascend ;
01254 if( asg->descend > max_descend )
01255 max_descend = asg->descend ;
01256 }
01257 }
01258 }
01259 if( (int)font->max_ascend <= max_ascend )
01260 font->max_ascend = MAX(max_ascend,1);
01261 if( (int)font->max_descend <= max_descend )
01262 font->max_descend = MAX(max_descend,1);
01263 font->max_height = font->max_ascend+font->max_descend;
01264 }
01265
01266 load_glyph_freetype(NULL, NULL, 0, 0);
01267 return max_ascend+max_descend;
01268 }
01269 #endif
01270
01271 static inline ASGlyph *get_unicode_glyph( const UNICODE_CHAR uc, ASFont *font )
01272 {
01273 register ASGlyphRange *r;
01274 ASGlyph *asg = NULL ;
01275 ASHashData hdata = {0} ;
01276 for( r = font->codemap ; r != NULL ; r = r->above )
01277 {
01278 LOCAL_DEBUG_OUT( "looking for glyph for char %lu (%p) if range (%ld,%ld)", uc, asg, r->min_char, r->max_char);
01279
01280 if( r->max_char >= uc )
01281 if( r->min_char <= uc )
01282 {
01283 asg = &(r->glyphs[uc - r->min_char]);
01284 LOCAL_DEBUG_OUT( "Found glyph for char %lu (%p)", uc, asg );
01285 if( asg->width > 0 && asg->pixmap != NULL )
01286 return asg;
01287 break;
01288 }
01289 }
01290 if( get_hash_item( font->locale_glyphs, AS_HASHABLE(uc), &hdata.vptr ) != ASH_Success )
01291 {
01292 #ifdef HAVE_FREETYPE
01293 asg = load_freetype_locale_glyph( font, uc );
01294 LOCAL_DEBUG_OUT( "glyph for char %lu loaded as %p", uc, asg );
01295 #endif
01296 }else
01297 asg = hdata.vptr ;
01298 LOCAL_DEBUG_OUT( "%sFound glyph for char %lu ( %p )", asg?"":"Did not ", uc, asg );
01299 return asg?asg:&(font->default_glyph) ;
01300 }
01301
01302
01303 static inline ASGlyph *get_character_glyph( const unsigned char c, ASFont *font )
01304 {
01305 return get_unicode_glyph( CHAR2UNICODE(c), font );
01306 }
01307
01308 static UNICODE_CHAR
01309 utf8_to_unicode ( const unsigned char *s )
01310 {
01311 unsigned char c = s[0];
01312
01313 if (c < 0x80)
01314 {
01315 return (UNICODE_CHAR)c;
01316 } else if (c < 0xc2)
01317 {
01318 return 0;
01319 } else if (c < 0xe0)
01320 {
01321 if (!((s[1] ^ 0x80) < 0x40))
01322 return 0;
01323 return ((UNICODE_CHAR) (c & 0x1f) << 6)
01324 |(UNICODE_CHAR) (s[1] ^ 0x80);
01325 } else if (c < 0xf0)
01326 {
01327 if (!((s[1] ^ 0x80) < 0x40 && (s[2] ^ 0x80) < 0x40
01328 && (c >= 0xe1 || s[1] >= 0xa0)))
01329 return 0;
01330 return ((UNICODE_CHAR) (c & 0x0f) << 12)
01331 | ((UNICODE_CHAR) (s[1] ^ 0x80) << 6)
01332 | (UNICODE_CHAR) (s[2] ^ 0x80);
01333 } else if (c < 0xf8 && sizeof(UNICODE_CHAR)*8 >= 32)
01334 {
01335 if (!((s[1] ^ 0x80) < 0x40 && (s[2] ^ 0x80) < 0x40
01336 && (s[3] ^ 0x80) < 0x40
01337 && (c >= 0xf1 || s[1] >= 0x90)))
01338 return 0;
01339 return ((UNICODE_CHAR) (c & 0x07) << 18)
01340 | ((UNICODE_CHAR) (s[1] ^ 0x80) << 12)
01341 | ((UNICODE_CHAR) (s[2] ^ 0x80) << 6)
01342 | (UNICODE_CHAR) (s[3] ^ 0x80);
01343 } else if (c < 0xfc && sizeof(UNICODE_CHAR)*8 >= 32)
01344 {
01345 if (!((s[1] ^ 0x80) < 0x40 && (s[2] ^ 0x80) < 0x40
01346 && (s[3] ^ 0x80) < 0x40 && (s[4] ^ 0x80) < 0x40
01347 && (c >= 0xf9 || s[1] >= 0x88)))
01348 return 0;
01349 return ((UNICODE_CHAR) (c & 0x03) << 24)
01350 | ((UNICODE_CHAR) (s[1] ^ 0x80) << 18)
01351 | ((UNICODE_CHAR) (s[2] ^ 0x80) << 12)
01352 | ((UNICODE_CHAR) (s[3] ^ 0x80) << 6)
01353 | (UNICODE_CHAR) (s[4] ^ 0x80);
01354 } else if (c < 0xfe && sizeof(UNICODE_CHAR)*8 >= 32)
01355 {
01356 if (!((s[1] ^ 0x80) < 0x40 && (s[2] ^ 0x80) < 0x40
01357 && (s[3] ^ 0x80) < 0x40 && (s[4] ^ 0x80) < 0x40
01358 && (s[5] ^ 0x80) < 0x40
01359 && (c >= 0xfd || s[1] >= 0x84)))
01360 return 0;
01361 return ((UNICODE_CHAR) (c & 0x01) << 30)
01362 | ((UNICODE_CHAR) (s[1] ^ 0x80) << 24)
01363 | ((UNICODE_CHAR) (s[2] ^ 0x80) << 18)
01364 | ((UNICODE_CHAR) (s[3] ^ 0x80) << 12)
01365 | ((UNICODE_CHAR) (s[4] ^ 0x80) << 6)
01366 | (UNICODE_CHAR) (s[5] ^ 0x80);
01367 }
01368 return 0;
01369 }
01370
01371 static inline ASGlyph *get_utf8_glyph( const char *utf8, ASFont *font )
01372 {
01373 UNICODE_CHAR uc = utf8_to_unicode ( (const unsigned char*)utf8 );
01374 LOCAL_DEBUG_OUT( "translated to Unicode 0x%lX(%ld), UTF8 size = %d", uc, uc, UTF8_CHAR_SIZE(utf8[0]) );
01375 return get_unicode_glyph( uc, font );
01376 }
01377
01378
01379
01380
01381
01382 typedef struct ASGlyphMap
01383 {
01384 int height, width ;
01385 ASGlyph **glyphs;
01386 int glyphs_num;
01387 short *x_kerning ;
01388 }ASGlyphMap;
01389
01390
01391 static void
01392 apply_text_3D_type( ASText3DType type,
01393 int *width, int *height )
01394 {
01395 switch( type )
01396 {
01397 case AST_Embossed :
01398 case AST_Sunken :
01399 (*width) += 2; (*height) += 2 ;
01400 break ;
01401 case AST_ShadeAbove :
01402 case AST_ShadeBelow :
01403 (*width)+=3; (*height)+=3 ;
01404 break ;
01405 case AST_SunkenThick :
01406 case AST_EmbossedThick :
01407 (*width)+=3; (*height)+=3 ;
01408 break ;
01409 case AST_OutlineAbove :
01410 case AST_OutlineBelow :
01411 (*width) += 1; (*height) += 1 ;
01412 break ;
01413 case AST_OutlineFull :
01414 (*width) += 2; (*height) += 2 ;
01415 break ;
01416 default :
01417 break ;
01418 }
01419 }
01420
01421 static unsigned int
01422 goto_tab_stop( ASTextAttributes *attr, unsigned int space_size, unsigned int line_width )
01423 {
01424 unsigned int tab_size = attr->tab_size*space_size ;
01425 unsigned int tab_stop = (((attr->origin + line_width)/tab_size)+1)*tab_size ;
01426 if( attr->tab_stops != NULL && attr->tab_stops_num > 0 )
01427 {
01428 unsigned int i ;
01429 for( i = 0 ; i < attr->tab_stops_num ; ++i )
01430 {
01431 if( attr->tab_stops[i] < line_width )
01432 continue;
01433 if( attr->tab_stops[i] < tab_stop )
01434 tab_stop = attr->tab_stops[i] ;
01435 break;
01436 }
01437 }
01438 return tab_stop;
01439 }
01440
01441 #ifdef HAVE_FREETYPE
01442 #define GET_KERNING(var,prev_gid,this_gid) \
01443 do{ if( (prev_gid) != 0 && font->type == ASF_Freetype && get_flags(font->flags, ASF_Monospaced|ASF_HasKerning) == ASF_HasKerning ) { \
01444 FT_Vector delta; \
01445 FT_Get_Kerning( font->ft_face, (prev_gid), (this_gid), FT_KERNING_DEFAULT, &delta );\
01446 (var) = (short)(delta.x >> 6); \
01447 }}while(0)
01448 #else
01449 #define GET_KERNING(var,prev_gid,this_gid) do{(var)=0;}while(0)
01450 #endif
01451
01452
01453
01454 #define FILL_TEXT_GLYPH_MAP(name,type,getglyph,incr) \
01455 static unsigned int \
01456 name( const type *text, ASFont *font, ASGlyphMap *map, ASTextAttributes *attr, int space_size, unsigned int offset_3d_x ) \
01457 { \
01458 int w = 0, line_count = 0, line_width = 0; \
01459 int i = -1, g = 0 ; \
01460 ASGlyph *last_asg = NULL ; unsigned int last_gid = 0 ; \
01461 do \
01462 { \
01463 ++i ; \
01464 LOCAL_DEBUG_OUT("begin_i=%d, char_code = 0x%2.2X",i,text[i]); \
01465 if( text[i] == '\n' || g == map->glyphs_num-1 ) \
01466 { \
01467 if( last_asg && last_asg->width+last_asg->lead > last_asg->step ) \
01468 line_width += last_asg->width+last_asg->lead - last_asg->step ; \
01469 last_asg = NULL; last_gid = 0 ; \
01470 if( line_width > w ) \
01471 w = line_width ; \
01472 line_width = 0 ; \
01473 ++line_count ; \
01474 map->glyphs[g] = (g == map->glyphs_num-1)?GLYPH_EOT:GLYPH_EOL; \
01475 ++g; \
01476 }else \
01477 { \
01478 last_asg = NULL ; \
01479 if( text[i] == ' ' ) \
01480 { last_gid = 0 ; \
01481 line_width += space_size ; \
01482 map->glyphs[g++] = GLYPH_SPACE; \
01483 }else if( text[i] == '\t' ) \
01484 { last_gid = 0 ; \
01485 if( !get_flags(attr->rendition_flags, ASTA_UseTabStops) ) line_width += space_size*attr->tab_size ; \
01486 else line_width = goto_tab_stop( attr, space_size, line_width ); \
01487 map->glyphs[g++] = GLYPH_TAB; \
01488 }else \
01489 { \
01490 last_asg = getglyph; \
01491 map->glyphs[g] = last_asg; \
01492 GET_KERNING(map->x_kerning[g],last_gid,last_asg->font_gid); \
01493 if( line_width < -last_asg->lead ) line_width -= (line_width+last_asg->lead);\
01494 line_width += last_asg->step+offset_3d_x+map->x_kerning[g]; \
01495 ++g; last_gid = last_asg->font_gid ; \
01496 LOCAL_DEBUG_OUT("pre_i=%d",i); \
01497 incr; \
01498 LOCAL_DEBUG_OUT("post_i=%d",i); \
01499 } \
01500 } \
01501 }while( g < map->glyphs_num ); \
01502 map->width = MAX( w, 1 ); \
01503 return line_count ; \
01504 }
01505
01506 #ifdef _MSC_VER
01507 FILL_TEXT_GLYPH_MAP(fill_text_glyph_map_Char,char,get_character_glyph(text[i],font),1)
01508 FILL_TEXT_GLYPH_MAP(fill_text_glyph_map_Unicode,UNICODE_CHAR,get_unicode_glyph(text[i],font),1)
01509 #else
01510 FILL_TEXT_GLYPH_MAP(fill_text_glyph_map_Char,char,get_character_glyph(text[i],font),)
01511 FILL_TEXT_GLYPH_MAP(fill_text_glyph_map_Unicode,UNICODE_CHAR,get_unicode_glyph(text[i],font),)
01512 #endif
01513 FILL_TEXT_GLYPH_MAP(fill_text_glyph_map_UTF8,char,get_utf8_glyph(&text[i],font),i+=(UTF8_CHAR_SIZE(text[i])-1))
01514
01515 void
01516 free_glyph_map( ASGlyphMap *map, Bool reusable )
01517 {
01518 if( map )
01519 {
01520 if( map->glyphs )
01521 free( map->glyphs );
01522 if( map->x_kerning )
01523 free( map->x_kerning );
01524 if( !reusable )
01525 free( map );
01526 }
01527 }
01528
01529 static int
01530 get_text_length (ASCharType char_type, const char *text)
01531 {
01532 register int count = 0;
01533 if( char_type == ASCT_Char )
01534 {
01535 register char *ptr = (char*)text ;
01536 while( ptr[count] != 0 )++count;
01537 }else if( char_type == ASCT_UTF8 )
01538 {
01539 register char *ptr = (char*)text ;
01540 while( *ptr != 0 ){ ++count; ptr += UTF8_CHAR_SIZE(*ptr); }
01541 }else if( char_type == ASCT_Unicode )
01542 {
01543 register UNICODE_CHAR *uc_ptr = (UNICODE_CHAR*)text ;
01544 while( uc_ptr[count] != 0 ) ++count;
01545 }
01546 return count;
01547 }
01548
01549 ASGlyph**
01550 get_text_glyph_list (const char *text, ASFont *font, ASCharType char_type, int length)
01551 {
01552 ASGlyph** glyphs = NULL;
01553 int i = 0;
01554
01555 if (text == NULL || font == NULL)
01556 return NULL;
01557 if (length <= 0)
01558 if ((length = get_text_length (char_type, text)) <= 0)
01559 return NULL;
01560
01561 glyphs = safecalloc( length+1, sizeof(ASGlyph*));
01562 if (char_type == ASCT_Char)
01563 {
01564 register char *ptr = (char*)text;
01565 for (i = 0 ; i < length ; ++i)
01566 glyphs[i] = get_character_glyph (ptr[i], font);
01567 }else if (char_type == ASCT_UTF8)
01568 {
01569 register char *ptr = (char*)text;
01570 for (i = 0 ; i < length ; ++i)
01571 {
01572 glyphs[i] = get_utf8_glyph (ptr, font);
01573 ptr += UTF8_CHAR_SIZE(*ptr);
01574 }
01575 }else if( char_type == ASCT_Unicode )
01576 {
01577 register UNICODE_CHAR *uc_ptr = (UNICODE_CHAR*)text ;
01578 for (i = 0 ; i < length ; ++i)
01579 glyphs[i] = get_unicode_glyph (uc_ptr[i], font);
01580 }
01581
01582 return glyphs;
01583 }
01584
01585 static Bool
01586 get_text_glyph_map (const char *text, ASFont *font, ASGlyphMap *map, ASTextAttributes *attr, int length )
01587 {
01588 unsigned int line_count = 0;
01589 int offset_3d_x = 0, offset_3d_y = 0 ;
01590 int space_size = 0 ;
01591
01592 apply_text_3D_type( attr->type, &offset_3d_x, &offset_3d_y );
01593
01594 if( text == NULL || font == NULL || map == NULL)
01595 return False;
01596
01597 offset_3d_x += font->spacing_x ;
01598 offset_3d_y += font->spacing_y ;
01599
01600 space_size = font->space_size ;
01601 if( !get_flags( font->flags, ASF_Monospaced) )
01602 space_size = (space_size>>1)+1 ;
01603 space_size += offset_3d_x;
01604
01605 map->glyphs_num = 1;
01606 if( length <= 0 )
01607 length = get_text_length (attr->char_type, text);
01608
01609 map->glyphs_num = 1 + length ;
01610
01611 map->glyphs = safecalloc( map->glyphs_num, sizeof(ASGlyph*));
01612 map->x_kerning = safecalloc( map->glyphs_num, sizeof(short));
01613
01614 if( attr->char_type == ASCT_UTF8 )
01615 line_count = fill_text_glyph_map_UTF8( text, font, map, attr, space_size, offset_3d_x );
01616 else if( attr->char_type == ASCT_Unicode )
01617 line_count = fill_text_glyph_map_Unicode( (UNICODE_CHAR*)text, font, map, attr, space_size, offset_3d_x );
01618 else
01619 line_count = fill_text_glyph_map_Char( text, font, map, attr, space_size, offset_3d_x );
01620
01621 map->height = line_count * (font->max_height+offset_3d_y) - font->spacing_y;
01622
01623 if( map->height <= 0 )
01624 map->height = 1 ;
01625
01626 return True;
01627 }
01628
01629 #define GET_TEXT_SIZE_LOOP(getglyph,incr,len) \
01630 do{ Bool terminated = True; ++i ;\
01631 if( len == 0 || i < len ) \
01632 { terminated = ( text[i] == '\0' || text[i] == '\n' ); \
01633 if( x_positions ) x_positions[i] = line_width ; \
01634 } \
01635 if( terminated ) { \
01636 if( last_asg && last_asg->width+last_asg->lead > last_asg->step ) \
01637 line_width += last_asg->width+last_asg->lead - last_asg->step ; \
01638 last_asg = NULL; last_gid = 0 ; \
01639 if( line_width > w ) \
01640 w = line_width ; \
01641 line_width = 0 ; \
01642 ++line_count ; \
01643 }else { \
01644 last_asg = NULL ; \
01645 if( text[i] == ' ' ){ \
01646 line_width += space_size ; last_gid = 0 ;\
01647 }else if( text[i] == '\t' ){ last_gid = 0 ; \
01648 if( !get_flags(attr->rendition_flags, ASTA_UseTabStops) ) line_width += space_size*attr->tab_size ; \
01649 else line_width = goto_tab_stop( attr, space_size, line_width ); \
01650 }else{ int kerning = 0 ;\
01651 last_asg = getglyph; \
01652 GET_KERNING(kerning,last_gid,last_asg->font_gid); \
01653 if( line_width < -last_asg->lead ) line_width -= (line_width+last_asg->lead);\
01654 line_width += last_asg->step+offset_3d_x +kerning ; \
01655 last_gid = last_asg->font_gid ; \
01656 incr ; \
01657 } \
01658 } \
01659 }while( (len <= 0 || len > i) && text[i] != '\0' )
01660
01661 static Bool
01662 get_text_size_internal( const char *src_text, ASFont *font, ASTextAttributes *attr, unsigned int *width, unsigned int *height, int length, int *x_positions )
01663 {
01664 int w = 0, h = 0, line_count = 0;
01665 int line_width = 0;
01666 int i = -1;
01667 ASGlyph *last_asg = NULL ;
01668 int space_size = 0;
01669 int offset_3d_x = 0, offset_3d_y = 0 ;
01670 int last_gid = 0 ;
01671
01672
01673 apply_text_3D_type( attr->type, &offset_3d_x, &offset_3d_y );
01674 if( src_text == NULL || font == NULL )
01675 return False;
01676
01677 offset_3d_x += font->spacing_x ;
01678 offset_3d_y += font->spacing_y ;
01679
01680 space_size = font->space_size ;
01681 if( !get_flags( font->flags, ASF_Monospaced) )
01682 space_size = (space_size>>1)+1 ;
01683 space_size += offset_3d_x ;
01684
01685 LOCAL_DEBUG_OUT( "char_type = %d", attr->char_type );
01686 if( attr->char_type == ASCT_Char )
01687 {
01688 char *text = (char*)&src_text[0] ;
01689 #ifdef _MSC_VER
01690 GET_TEXT_SIZE_LOOP(get_character_glyph(text[i],font),1,length);
01691 #else
01692 GET_TEXT_SIZE_LOOP(get_character_glyph(text[i],font),,length);
01693 #endif
01694 }else if( attr->char_type == ASCT_UTF8 )
01695 {
01696 char *text = (char*)&src_text[0] ;
01697 int byte_length = 0 ;
01698 if( length > 0 )
01699 {
01700 int k ;
01701 for( k = 0 ; k < length ; ++k )
01702 {
01703 if( text[byte_length] == '\0' )
01704 break;
01705 byte_length += UTF8_CHAR_SIZE(text[byte_length]);
01706 }
01707 }
01708 GET_TEXT_SIZE_LOOP(get_utf8_glyph(&text[i],font),i+=UTF8_CHAR_SIZE(text[i])-1,byte_length);
01709 }else if( attr->char_type == ASCT_Unicode )
01710 {
01711 UNICODE_CHAR *text = (UNICODE_CHAR*)&src_text[0] ;
01712 #ifdef _MSC_VER
01713 GET_TEXT_SIZE_LOOP(get_unicode_glyph(text[i],font),1,length);
01714 #else
01715 GET_TEXT_SIZE_LOOP(get_unicode_glyph(text[i],font),,length);
01716 #endif
01717 }
01718
01719 h = line_count * (font->max_height+offset_3d_y) - font->spacing_y;
01720
01721 if( w < 1 )
01722 w = 1 ;
01723 if( h < 1 )
01724 h = 1 ;
01725 if( width )
01726 *width = w;
01727 if( height )
01728 *height = h;
01729 return True ;
01730 }
01731
01732 Bool
01733 get_text_size( const char *src_text, ASFont *font, ASText3DType type, unsigned int *width, unsigned int *height )
01734 {
01735 ASTextAttributes attr = {ASTA_VERSION_INTERNAL, 0, 0, ASCT_Char, 8, 0, NULL, 0 };
01736 attr.type = type ;
01737 if( IsUTF8Locale() )
01738 attr.char_type = ASCT_UTF8 ;
01739 return get_text_size_internal( (char*)src_text, font, &attr, width, height, 0, NULL );
01740 }
01741
01742 Bool
01743 get_unicode_text_size( const UNICODE_CHAR *src_text, ASFont *font, ASText3DType type, unsigned int *width, unsigned int *height )
01744 {
01745 ASTextAttributes attr = {ASTA_VERSION_INTERNAL, 0, 0, ASCT_Unicode, 8, 0, NULL, 0 };
01746 attr.type = type ;
01747 return get_text_size_internal( (char*)src_text, font, &attr, width, height, 0, NULL );
01748 }
01749
01750 Bool
01751 get_utf8_text_size( const char *src_text, ASFont *font, ASText3DType type, unsigned int *width, unsigned int *height )
01752 {
01753 ASTextAttributes attr = {ASTA_VERSION_INTERNAL, 0, 0, ASCT_UTF8, 8, 0, NULL, 0 };
01754 attr.type = type ;
01755 return get_text_size_internal( (char*)src_text, font, &attr, width, height, 0, NULL );
01756 }
01757
01758 Bool
01759 get_fancy_text_size( const void *src_text, ASFont *font, ASTextAttributes *attr, unsigned int *width, unsigned int *height, int length, int *x_positions )
01760 {
01761 ASTextAttributes internal_attr = {ASTA_VERSION_INTERNAL, 0, 0, ASCT_Char, 8, 0, NULL, 0 };
01762 if( attr != NULL )
01763 {
01764 internal_attr = *attr;
01765 if( internal_attr.tab_size == 0 )
01766 internal_attr.tab_size = 8 ;
01767 internal_attr.version = ASTA_VERSION_INTERNAL ;
01768 }else
01769 {
01770 if( IsUTF8Locale() )
01771 internal_attr.char_type = ASCT_UTF8 ;
01772 }
01773 return get_text_size_internal( src_text, font, &internal_attr, width, height, length, x_positions );
01774 }
01775
01776 inline static void
01777 render_asglyph( CARD8 **scanlines, CARD8 *row,
01778 int start_x, int y, int width, int height,
01779 CARD32 ratio )
01780 {
01781 int count = -1 ;
01782 int max_y = y + height ;
01783 register CARD32 data = 0;
01784 while( y < max_y )
01785 {
01786 register CARD8 *dst = scanlines[y]+start_x;
01787 register int x = -1;
01788 while( ++x < width )
01789 {
01790
01791 if( count < 0 )
01792 {
01793 data = *(row++);
01794 if( (data&0x80) != 0)
01795 {
01796 data = ((data&0x7F)<<1);
01797 if( data != 0 )
01798 ++data;
01799 }else
01800 {
01801 count = data&0x3F ;
01802 data = ((data&0x40) != 0 )? 0xFF: 0x00;
01803 }
01804 if( ratio != 0xFF && data != 0 )
01805 data = ((data*ratio)>>8)+1 ;
01806 }
01807 if( data > dst[x] )
01808 dst[x] = (data > 255)? 0xFF:data ;
01809 --count;
01810 }
01811 ++y;
01812 }
01813 }
01814
01815 inline static void
01816 render_asglyph_over( CARD8 **scanlines, CARD8 *row,
01817 int start_x, int y, int width, int height,
01818 CARD32 value )
01819 {
01820 int count = -1 ;
01821 int max_y = y + height ;
01822 CARD32 anti_data = 0;
01823 register CARD32 data = 0;
01824 while( y < max_y )
01825 {
01826 register CARD8 *dst = scanlines[y]+start_x;
01827 register int x = -1;
01828 while( ++x < width )
01829 {
01830
01831 if( count < 0 )
01832 {
01833 data = *(row++);
01834 if( (data&0x80) != 0)
01835 {
01836 data = ((data&0x7F)<<1);
01837 if( data != 0 )
01838 ++data;
01839 }else
01840 {
01841 count = data&0x3F ;
01842 data = ((data&0x40) != 0 )? 0xFF: 0x00;
01843 }
01844 anti_data = 256 - data ;
01845 }
01846 if( data >= 254 )
01847 dst[x] = value ;
01848 else
01849 dst[x] = ((CARD32)dst[x]*anti_data + value*data)>>8 ;
01850 --count;
01851 }
01852 ++y;
01853 }
01854 }
01855
01856
01857
01858 static ASImage *
01859 draw_text_internal( const char *text, ASFont *font, ASTextAttributes *attr, int compression, int length )
01860 {
01861 ASGlyphMap map ;
01862 CARD8 *memory, *rgb_memory = NULL;
01863 CARD8 **scanlines, **rgb_scanlines = NULL ;
01864 int i = 0, offset = 0, line_height, space_size, base_line;
01865 ASImage *im;
01866 int pen_x = 0, pen_y = 0;
01867 int offset_3d_x = 0, offset_3d_y = 0 ;
01868 CARD32 back_color = 0 ;
01869 CARD32 alpha_7 = 0x007F, alpha_9 = 0x009F, alpha_A = 0x00AF, alpha_C = 0x00CF, alpha_F = 0x00FF, alpha_E = 0x00EF;
01870 START_TIME(started);
01871
01872
01873
01874
01875
01876 if (attr->width)
01877 {
01878 unsigned int width, height;
01879 get_text_size( text , font, attr->type, &width, &height );
01880 if ( (width > attr->width) && (strchr(text, ' ')) )
01881 {
01882 char *tryPtr = strchr(text,' ');
01883 char *oldTryPtr = tryPtr;
01884 while (tryPtr)
01885 {
01886 *tryPtr = 0;
01887 get_text_size( text , font, attr->type, &width, &height );
01888 if (width > attr->width)
01889 *oldTryPtr = '\n';
01890
01891 *tryPtr = ' ';
01892 oldTryPtr = tryPtr;
01893 tryPtr = strchr(tryPtr + 1,' ');
01894 }
01895 }
01896 }
01897
01898 LOCAL_DEBUG_CALLER_OUT( "text = \"%s\", font = %p, compression = %d", text, font, compression );
01899 if( !get_text_glyph_map( text, font, &map, attr, length) )
01900 return NULL;
01901
01902 if( map.width <= 0 )
01903 return NULL;
01904
01905 apply_text_3D_type( attr->type, &offset_3d_x, &offset_3d_y );
01906
01907 offset_3d_x += font->spacing_x ;
01908 offset_3d_y += font->spacing_y ;
01909 line_height = font->max_height+offset_3d_y ;
01910
01911 LOCAL_DEBUG_OUT( "text size = %dx%d pixels", map.width, map.height );
01912 im = create_asimage( map.width, map.height, compression );
01913
01914 space_size = font->space_size ;
01915 if( !get_flags( font->flags, ASF_Monospaced) )
01916 space_size = (space_size>>1)+1 ;
01917 space_size += offset_3d_x;
01918
01919 base_line = font->max_ascend;
01920 LOCAL_DEBUG_OUT( "line_height is %d, space_size is %d, base_line is %d", line_height, space_size, base_line );
01921 scanlines = safemalloc( line_height*sizeof(CARD8*));
01922 memory = safecalloc( 1, line_height*map.width);
01923 for( i = 0 ; i < line_height ; ++i )
01924 {
01925 scanlines[i] = memory + offset;
01926 offset += map.width;
01927 }
01928 if( attr->type >= AST_OutlineAbove )
01929 {
01930 CARD32 fc = attr->fore_color ;
01931 offset = 0 ;
01932 rgb_scanlines = safemalloc( line_height*3*sizeof(CARD8*));
01933 rgb_memory = safecalloc( 1, line_height*map.width*3);
01934 for( i = 0 ; i < line_height*3 ; ++i )
01935 {
01936 rgb_scanlines[i] = rgb_memory + offset;
01937 offset += map.width;
01938 }
01939 if( (ARGB32_RED16(fc)*222+ARGB32_GREEN16(fc)*707+ARGB32_BLUE16(fc) *71)/1000 < 0x07FFF )
01940 {
01941 back_color = 0xFF ;
01942 memset( rgb_memory, back_color, line_height*map.width*3 );
01943 }
01944 }
01945 if( ARGB32_ALPHA8(attr->fore_color) > 0 )
01946 {
01947 CARD32 a = ARGB32_ALPHA8(attr->fore_color);
01948 alpha_7 = (0x007F*a)>>8 ;
01949 alpha_9 = (0x009F*a)>>8 ;
01950 alpha_A = (0x00AF*a)>>8 ;
01951 alpha_C = (0x00CF*a)>>8 ;
01952 alpha_E = (0x00EF*a)>>8 ;
01953 alpha_F = (0x00FF*a)>>8 ;
01954 }
01955
01956 i = -1 ;
01957 if(get_flags(font->flags, ASF_RightToLeft))
01958 pen_x = map.width ;
01959
01960 do
01961 {
01962 ++i;
01963
01964 if( map.glyphs[i] == GLYPH_EOL || map.glyphs[i] == GLYPH_EOT )
01965 {
01966 int y;
01967 for( y = 0 ; y < line_height ; ++y )
01968 {
01969 #if 1
01970 #if defined(LOCAL_DEBUG) && !defined(NO_DEBUG_OUTPUT)
01971 {
01972 int x = 0;
01973 while( x < map.width )
01974 fprintf( stderr, "%2.2X ", scanlines[y][x++] );
01975 fprintf( stderr, "\n" );
01976 }
01977 #endif
01978 #endif
01979 im->channels[IC_ALPHA][pen_y+y] = store_data( NULL, scanlines[y], map.width, ASStorage_RLEDiffCompress, 0);
01980 if( attr->type >= AST_OutlineAbove )
01981 {
01982 im->channels[IC_RED][pen_y+y] = store_data( NULL, rgb_scanlines[y], map.width, ASStorage_RLEDiffCompress, 0);
01983 im->channels[IC_GREEN][pen_y+y] = store_data( NULL, rgb_scanlines[y+line_height], map.width, ASStorage_RLEDiffCompress, 0);
01984 im->channels[IC_BLUE][pen_y+y] = store_data( NULL, rgb_scanlines[y+line_height+line_height], map.width, ASStorage_RLEDiffCompress, 0);
01985 }
01986 }
01987
01988 memset( memory, 0x00, line_height*map.width );
01989 if( attr->type >= AST_OutlineAbove )
01990 memset( rgb_memory, back_color, line_height*map.width*3 );
01991
01992 pen_x = get_flags(font->flags, ASF_RightToLeft)? map.width : 0;
01993 pen_y += line_height;
01994 if( pen_y <0 )
01995 pen_y = 0 ;
01996 }else
01997 {
01998 if( map.glyphs[i] == GLYPH_SPACE || map.glyphs[i] == GLYPH_TAB )
01999 {
02000 if(map.glyphs[i] == GLYPH_TAB)
02001 {
02002 if( !get_flags(attr->rendition_flags, ASTA_UseTabStops) ) pen_x += space_size*attr->tab_size ;
02003 else pen_x = goto_tab_stop( attr, space_size, pen_x );
02004 }else if( get_flags(font->flags, ASF_RightToLeft) )
02005 pen_x -= space_size ;
02006 else
02007 pen_x += space_size ;
02008 }else
02009 {
02010
02011 ASGlyph *asg = map.glyphs[i] ;
02012 int y = base_line - asg->ascend;
02013 int start_x = 0, offset_x = 0;
02014
02015 if( get_flags(font->flags, ASF_RightToLeft) )
02016 pen_x -= asg->step+offset_3d_x +map.x_kerning[i];
02017 else
02018 {
02019 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 );
02020 pen_x += map.x_kerning[i] ;
02021 }
02022 if( asg->lead > 0 )
02023 start_x = pen_x + asg->lead ;
02024 else
02025 start_x = pen_x + asg->lead ;
02026 if( start_x < 0 )
02027 {
02028 offset_x = -start_x ;
02029 start_x = 0 ;
02030 }
02031 if( y < 0 )
02032 y = 0 ;
02033
02034 switch( attr->type )
02035 {
02036 case AST_Plain :
02037 render_asglyph( scanlines, asg->pixmap, start_x, y, asg->width, asg->height, alpha_F );
02038 break ;
02039 case AST_Embossed :
02040 render_asglyph( scanlines, asg->pixmap, start_x, y, asg->width, asg->height, alpha_F );
02041 render_asglyph( scanlines, asg->pixmap, start_x+2, y+2, asg->width, asg->height, alpha_9 );
02042 render_asglyph( scanlines, asg->pixmap, start_x+1, y+1, asg->width, asg->height, alpha_C );
02043 break ;
02044 case AST_Sunken :
02045 render_asglyph( scanlines, asg->pixmap, start_x, y, asg->width, asg->height, alpha_9 );
02046 render_asglyph( scanlines, asg->pixmap, start_x+2, y+2, asg->width, asg->height, alpha_F );
02047 render_asglyph( scanlines, asg->pixmap, start_x+1, y+1, asg->width, asg->height, alpha_C );
02048 break ;
02049 case AST_ShadeAbove :
02050 render_asglyph( scanlines, asg->pixmap, start_x, y, asg->width, asg->height, alpha_7 );
02051 render_asglyph( scanlines, asg->pixmap, start_x+3, y+3, asg->width, asg->height, alpha_F );
02052 break ;
02053 case AST_ShadeBelow :
02054 render_asglyph( scanlines, asg->pixmap, start_x+3, y+3, asg->width, asg->height, alpha_7 );
02055 render_asglyph( scanlines, asg->pixmap, start_x, y, asg->width, asg->height, alpha_F );
02056 break ;
02057 case AST_EmbossedThick :
02058 render_asglyph( scanlines, asg->pixmap, start_x, y, asg->width, asg->height, alpha_F );
02059 render_asglyph( scanlines, asg->pixmap, start_x+1, y+1, asg->width, asg->height, alpha_E );
02060 render_asglyph( scanlines, asg->pixmap, start_x+3, y+3, asg->width, asg->height, alpha_7 );
02061 render_asglyph( scanlines, asg->pixmap, start_x+2, y+2, asg->width, asg->height, alpha_C );
02062 break ;
02063 case AST_SunkenThick :
02064 render_asglyph( scanlines, asg->pixmap, start_x, y, asg->width, asg->height, alpha_7 );
02065 render_asglyph( scanlines, asg->pixmap, start_x+1, y+1, asg->width, asg->height, alpha_A );
02066 render_asglyph( scanlines, asg->pixmap, start_x+3, y+3, asg->width, asg->height, alpha_F );
02067 render_asglyph( scanlines, asg->pixmap, start_x+2, y+2, asg->width, asg->height, alpha_C );
02068 break ;
02069 case AST_OutlineAbove :
02070 render_asglyph( scanlines, asg->pixmap, start_x, y, asg->width, asg->height, alpha_A );
02071 render_asglyph( scanlines, asg->pixmap, start_x+1, y+1, asg->width, asg->height, alpha_F );
02072 render_asglyph_over( rgb_scanlines, asg->pixmap, start_x+1, y+1, asg->width, asg->height, ARGB32_RED8(attr->fore_color) );
02073 render_asglyph_over( &rgb_scanlines[line_height], asg->pixmap, start_x+1, y+1, asg->width, asg->height, ARGB32_GREEN8(attr->fore_color) );
02074 render_asglyph_over( &rgb_scanlines[line_height*2], asg->pixmap, start_x+1, y+1, asg->width, asg->height, ARGB32_BLUE8(attr->fore_color) );
02075 break ;
02076 case AST_OutlineBelow :
02077 render_asglyph( scanlines, asg->pixmap, start_x, y, asg->width, asg->height, alpha_F );
02078 render_asglyph( scanlines, asg->pixmap, start_x+1, y+1, asg->width, asg->height, alpha_A );
02079 render_asglyph_over( rgb_scanlines, asg->pixmap, start_x, y, asg->width, asg->height, ARGB32_RED8(attr->fore_color) );
02080 render_asglyph_over( &rgb_scanlines[line_height], asg->pixmap, start_x, y, asg->width, asg->height, ARGB32_GREEN8(attr->fore_color) );
02081 render_asglyph_over( &rgb_scanlines[line_height*2], asg->pixmap, start_x, y, asg->width, asg->height, ARGB32_BLUE8(attr->fore_color) );
02082 break ;
02083 case AST_OutlineFull :
02084 render_asglyph( scanlines, asg->pixmap, start_x, y, asg->width, asg->height, alpha_A );
02085 render_asglyph( scanlines, asg->pixmap, start_x+1, y+1, asg->width, asg->height, alpha_F );
02086 render_asglyph( scanlines, asg->pixmap, start_x+2, y+2, asg->width, asg->height, alpha_A );
02087 render_asglyph_over( rgb_scanlines, asg->pixmap, start_x+1, y+1, asg->width, asg->height, ARGB32_RED8(attr->fore_color) );
02088 render_asglyph_over( &rgb_scanlines[line_height], asg->pixmap, start_x+1, y+1, asg->width, asg->height, ARGB32_GREEN8(attr->fore_color) );
02089 render_asglyph_over( &rgb_scanlines[line_height*2], asg->pixmap, start_x+1, y+1, asg->width, asg->height, ARGB32_BLUE8(attr->fore_color) );
02090 break ;
02091 default:
02092 break ;
02093 }
02094
02095 if( !get_flags(font->flags, ASF_RightToLeft) )
02096 pen_x += offset_x + asg->step+offset_3d_x;
02097 }
02098 }
02099 }while( map.glyphs[i] != GLYPH_EOT );
02100 free_glyph_map( &map, True );
02101 free( memory );
02102 free( scanlines );
02103 if( rgb_memory )
02104 free( rgb_memory );
02105 if( rgb_scanlines )
02106 free( rgb_scanlines );
02107 SHOW_TIME("", started);
02108 return im;
02109 }
02110
02111 ASImage *
02112 draw_text( const char *text, ASFont *font, ASText3DType type, int compression )
02113 {
02114 ASTextAttributes attr = {ASTA_VERSION_INTERNAL, 0, 0, ASCT_Char, 8, 0, NULL, 0, ARGB32_White };
02115 attr.type = type ;
02116 if( IsUTF8Locale() )
02117 attr.char_type = ASCT_UTF8 ;
02118 return draw_text_internal( text, font, &attr, compression, 0 );
02119 }
02120
02121 ASImage *
02122 draw_unicode_text( const UNICODE_CHAR *text, ASFont *font, ASText3DType type, int compression )
02123 {
02124 ASTextAttributes attr = {ASTA_VERSION_INTERNAL, 0, 0, ASCT_Unicode, 8, 0, NULL, 0, ARGB32_White };
02125 attr.type = type ;
02126 return draw_text_internal( (const char*)text, font, &attr, compression, 0 );
02127 }
02128
02129 ASImage *
02130 draw_utf8_text( const char *text, ASFont *font, ASText3DType type, int compression )
02131 {
02132 ASTextAttributes attr = {ASTA_VERSION_INTERNAL, 0, 0, ASCT_UTF8, 8, 0, NULL, 0, ARGB32_White };
02133 attr.type = type ;
02134 return draw_text_internal( text, font, &attr, compression, 0 );
02135 }
02136
02137 ASImage *
02138 draw_fancy_text( const void *text, ASFont *font, ASTextAttributes *attr, int compression, int length )
02139 {
02140 ASTextAttributes internal_attr = {ASTA_VERSION_INTERNAL, 0, 0, ASCT_Char, 8, 0, NULL, 0, ARGB32_White };
02141 if( attr != NULL )
02142 {
02143 internal_attr = *attr;
02144 if( internal_attr.tab_size == 0 )
02145 internal_attr.tab_size = 8 ;
02146 internal_attr.version = ASTA_VERSION_INTERNAL ;
02147 }else
02148 {
02149 if( IsUTF8Locale() )
02150 internal_attr.char_type = ASCT_UTF8 ;
02151 }
02152 return draw_text_internal( text, font, &internal_attr, compression, length );
02153 }
02154
02155 Bool get_asfont_glyph_spacing( ASFont* font, int *x, int *y )
02156 {
02157 if( font )
02158 {
02159 if( x )
02160 *x = font->spacing_x ;
02161 if( y )
02162 *y = font->spacing_y ;
02163 return True ;
02164 }
02165 return False ;
02166 }
02167
02168 Bool set_asfont_glyph_spacing( ASFont* font, int x, int y )
02169 {
02170 if( font )
02171 {
02172 font->spacing_x = (x < 0 )? 0: x;
02173 font->spacing_y = (y < 0 )? 0: y;
02174 return True ;
02175 }
02176 return False ;
02177 }
02178
02179
02180 void print_asfont( FILE* stream, ASFont* font)
02181 {
02182 if( font )
02183 {
02184 fprintf( stream, "font.type = %d\n", font->type );
02185 fprintf( stream, "font.flags = 0x%lX\n", font->flags );
02186 #ifdef HAVE_FREETYPE
02187 fprintf( stream, "font.ft_face = %p\n", font->ft_face );
02188 #endif
02189 fprintf( stream, "font.max_height = %d\n", font->max_height );
02190 fprintf( stream, "font.space_size = %d\n" , font->space_size );
02191 fprintf( stream, "font.spacing_x = %d\n" , font->spacing_x );
02192 fprintf( stream, "font.spacing_y = %d\n" , font->spacing_y );
02193 fprintf( stream, "font.max_ascend = %d\n", font->max_ascend );
02194 fprintf( stream, "font.max_descend = %d\n", font->max_descend );
02195 }
02196 }
02197
02198 void print_asglyph( FILE* stream, ASFont* font, unsigned long c)
02199 {
02200 if( font )
02201 {
02202 int i, k ;
02203 ASGlyph *asg = get_unicode_glyph( c, font );
02204 if( asg == NULL )
02205 return;
02206
02207 fprintf( stream, "glyph[%lu].ASCII = %c\n", c, (char)c );
02208 fprintf( stream, "glyph[%lu].width = %d\n", c, asg->width );
02209 fprintf( stream, "glyph[%lu].height = %d\n", c, asg->height );
02210 fprintf( stream, "glyph[%lu].lead = %d\n", c, asg->lead );
02211 fprintf( stream, "glyph[%lu].ascend = %d\n", c, asg->ascend);
02212 fprintf( stream, "glyph[%lu].descend = %d\n", c, asg->descend );
02213 k = 0 ;
02214 fprintf( stream, "glyph[%lu].pixmap = {", c);
02215 #if 1
02216 for( i = 0 ; i < asg->height*asg->width ; i++ )
02217 {
02218 if( asg->pixmap[k]&0x80 )
02219 {
02220 fprintf( stream, "%2.2X ", ((asg->pixmap[k]&0x7F)<<1));
02221 }else
02222 {
02223 int count = asg->pixmap[k]&0x3F;
02224 if( asg->pixmap[k]&0x40 )
02225 fprintf( stream, "FF(%d times) ", count+1 );
02226 else
02227 fprintf( stream, "00(%d times) ", count+1 );
02228 i += count ;
02229 }
02230 k++;
02231 }
02232 #endif
02233 fprintf( stream, "}\nglyph[%lu].used_memory = %d\n", c, k );
02234 }
02235 }
02236
02237
02238 #ifndef HAVE_XRENDER
02239 Bool afterimage_uses_xrender(){ return False;}
02240
02241 void
02242 draw_text_xrender( ASVisual *asv, const void *text, ASFont *font, ASTextAttributes *attr, int length,
02243 int xrender_op, unsigned long xrender_src, unsigned long xrender_dst,
02244 int xrender_xSrc, int xrender_ySrc, int xrender_xDst, int xrender_yDst )
02245 {}
02246 #else
02247 Bool afterimage_uses_xrender(){ return True;}
02248
02249 void
02250 draw_text_xrender( ASVisual *asv, const void *text, ASFont *font, ASTextAttributes *attr, int length,
02251 Picture xrender_src, Picture xrender_dst,
02252 int xrender_xSrc, int xrender_ySrc, int xrender_xDst, int xrender_yDst )
02253 {
02254 ASGlyphMap map;
02255 int max_gid = 0 ;
02256 int i ;
02257 int missing_glyphs = 0 ;
02258 int glyphs_bmap_size = 0, max_height = 0 ;
02259
02260 if( !get_text_glyph_map( text, font, &map, attr, length) )
02261 return;
02262
02263 if( map.width == 0 )
02264 return;
02265
02266
02267 if( font->xrender_glyphset == 0 )
02268 font->xrender_glyphset = XRenderCreateGlyphSet (asv->dpy, asv->xrender_mask_format);
02269
02270 for( i = 0 ; map.glyphs[i] != GLYPH_EOT ; ++i )
02271 if( map.glyphs[i] > MAX_SPECIAL_GLYPH && map.glyphs[i]->xrender_gid == 0 )
02272 {
02273 glyphs_bmap_size += map.glyphs[i]->width * map.glyphs[i]->height ;
02274 if( map.glyphs[i]->height > max_height )
02275 max_height = map.glyphs[i]->height ;
02276 ++missing_glyphs;
02277 }
02278
02279 if( missing_glyphs > 0 )
02280 {
02281 Glyph *gids;
02282 XGlyphInfo *glyphs;
02283 char *bitmap, *bmap_ptr ;
02284 int nbytes_bitmap = 0;
02285 CARD8 **scanlines ;
02286
02287 scanlines = safecalloc(max_height, sizeof(CARD8*));
02288
02289 bmap_ptr = bitmap = safemalloc( glyphs_bmap_size );
02290 glyphs = safecalloc( missing_glyphs, sizeof(XGlyphInfo));
02291 gids = safecalloc( missing_glyphs, sizeof(Glyph));
02292 for( i = 0 ; map.glyphs[i] != GLYPH_EOT ; ++i )
02293 if( map.glyphs[i] > MAX_SPECIAL_GLYPH && map.glyphs[i]->xrender_gid == 0 )
02294 {
02295 ASGlyph *asg = map.glyphs[i];
02296 int k = asg->height ;
02297 char *ptr = bmap_ptr + asg->width*asg->height ;
02298 bmap_ptr = ptr ;
02299 while ( --k >= 0 )
02300 {
02301 ptr -= asg->width ;
02302 scanlines[k] = ptr ;
02303 }
02304 render_asglyph( scanlines, asg->pixmap, 0, 0, asg->width, asg->height, 0xFF );
02305 gids[i] =
02306 }
02307 XRenderAddGlyphs( asv->dpy, font->xrender_glyphset, gids, glyphs, missing_glyphs, bitmap, nbytes_bitmap );
02308 free( gids );
02309 free( glyphs );
02310 free( bitmap );
02311 free( scanlines );
02312 }
02313
02314 if( max_gid <= 255 )
02315 {
02316 char *string = safemalloc( map->glyphs_num-1 );
02317 for( i = 0 ; map.glyphs[i] != GLYPH_EOT ; ++i )
02318 string[i] = map.glyphs[i]->xrender_gid ;
02319 XRenderCompositeString8 ( asv->dpy, PictOpOver, xrender_src, xrender_dst,
02320 asv->xrender_mask_format,
02321 font->xrender_glyphset,
02322 xrender_xSrc,xrender_ySrc,xrender_xDst,xrender_yDst,
02323 string, i);
02324 free( string );
02325 }else if( max_gid <= 65000 )
02326 {
02327 unsigned short *string = safemalloc( sizeof(unsigned short)*(map->glyphs_num-1) );
02328 for( i = 0 ; map.glyphs[i] != GLYPH_EOT ; ++i )
02329 string[i] = map.glyphs[i]->xrender_gid ;
02330 XRenderCompositeString16 (asv->dpy, PictOpOver, xrender_src, xrender_dst,
02331 asv->xrender_mask_format,
02332 font->xrender_glyphset,
02333 xrender_xSrc,xrender_ySrc,xrender_xDst,xrender_yDst,
02334 string, i);
02335 free( string );
02336 }else
02337 {
02338 unsigned int *string = safemalloc( sizeof(int)*(map->glyphs_num-1) );
02339 for( i = 0 ; map.glyphs[i] != GLYPH_EOT ; ++i )
02340 string[i] = map.glyphs[i]->xrender_gid ;
02341 XRenderCompositeString32 (asv->dpy, PictOpOver, xrender_src, xrender_dst,
02342 asv->xrender_mask_format,
02343 font->xrender_glyphset,
02344 xrender_xSrc,xrender_ySrc,xrender_xDst,xrender_yDst,
02345 string, i);
02346 free( string );
02347 }
02348
02349
02350 free_glyph_map( &map, True );
02351 }
02352
02353 #endif
02354
02355
02356
02357
02358
02359