asfont.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2001 Sasha Vasko <sasha at aftercode.net>
00003  *
00004  * This library is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU Lesser General Public
00006  * License as published by the Free Software Foundation; either
00007  * version 2.1 of the License, or (at your option) any later version.
00008  *
00009  * This library is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * Lesser General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU Lesser General Public
00015  * License along with this library; if not, write to the Free Software
00016  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
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 /* TrueType and X11 font management functions :                                                                  */
00096 /*********************************************************************************/
00097 
00098 /*********************************************************************************/
00099 /* construction destruction miscelanea:                                                                                  */
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                 {/* we might have face index specifier at the end of the filename */
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                                                 /* fprintf( stderr, "@@@@@@@font %s has kerning!!!\n", realfilename );*/
00223                                         }/*else
00224                                                 fprintf( stderr, "@@@@@@@font %s don't have kerning!!!\n", realfilename ); */
00225                                         /* lets confine the font to square cell */
00226                                         FT_Set_Pixel_Sizes( font->ft_face, size, size );
00227                                         /* but let make our own cell width smaller then height */
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     #ifdef I18N
00255      TODO: we have to use FontSet and loop through fonts instead filling
00256            up 2 bytes per character table with glyphs 
00257     #else 
00258 */
00259     /* for now assume ISO Latin 1 encoding */
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 /* #ifndef X_DISPLAY_MISSING */
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                         {       /* not loaded just yet - lets do it :*/
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                                 {/* don't want to try and load font as X11 unless requested to do so */
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 /*fprintf( stderr, "\t\t%p\n", asg->pixmap );*/
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 /*fprintf( stderr, " max_char = %d, min_char = %d, i = %d", gr->max_char, gr->min_char, max_i);*/
00395             while( ++i < max_i )
00396             {
00397 /*fprintf( stderr, "%d >", i );*/
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 ;          /* name is freed as part of destroy_font */
00448 /*              fprintf( stderr,"freeing font \"%s\"...", (char*) value ); */
00449               destroy_font( (ASFont*)data );
00450 /*              fprintf( stderr,"   done.\n"); */
00451         }
00452         if( cval )
00453             free( cval );
00454     }
00455 }
00456 
00457 /*************************************************************************/
00458 /* Low level bitmap handling - compression and antialiasing              */
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 /* new way: if its FF we encode it as 01rrrrrr where rrrrrr is repitition count
00472  * if its 0 we encode it as 00rrrrrr. Any other symbol we bitshift right by 1
00473  * and then store it as 1sssssss where sssssss are topmost sugnificant bits.
00474  * Note  - single FFs and 00s are encoded as any other character. Its been noted
00475  * that in 99% of cases 0 or FF repeats, and very seldom anything else repeats
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 /*fprintf( stderr, "%2.2X ", src[k] ); */
00495                 if( ++k >= (int)width )
00496                 {
00497 /*                      fputc( '\n', stderr ); */
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/*+(32-(i&0x01F) )*/);
00512 /*fprintf( stderr, "pixmap alloced %p size %d(%d)", pixmap, i, i+(32-(i&0x01F) )); */
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                 {/* antialiasing here : */
00533                         unsigned int c = (unsigned int)row[x]+
00534                                                         (unsigned int)row1[x-1]+
00535                                                         (unsigned int)row1[x+1];
00536                         if( c >= 0x01FE )  /* we cut off secondary aliases */
00537                                 row1[x] = c>>2;
00538                 }
00539         for( y = 1 ; y < (int)height-1 ; y++ )
00540         {
00541                 if( row[0] == 0 )
00542                 {/* antialiasing here : */
00543                         unsigned int c = (unsigned int)row1[0]+
00544                                                         (unsigned int)row[1]+
00545                                                         (unsigned int)row2[0];
00546                         if( c >= 0x01FE )  /* we cut off secondary aliases */
00547                                 row[0] = c>>2;
00548                 }
00549                 for( x = 1 ; x < (int)width-1 ; x++ )
00550                 {
00551                         if( row[x] == 0 )
00552                         {/* antialiasing here : */
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 )  /* we cut off secondary aliases */
00561                                         row[x] = c>>2;
00562                         }
00563                 }
00564                 if( row[x] == 0 )
00565                 {/* antialiasing here : */
00566                         unsigned int c = (unsigned int)row1[x]+
00567                                                         (unsigned int)row[x-1]+
00568                                                         (unsigned int)row2[x];
00569                         if( c >= 0x01FE )  /* we cut off secondary aliases */
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                 {/* antialiasing here : */
00579                         unsigned int c = (unsigned int)row1[x]+
00580                                                         (unsigned int)row[x-1]+
00581                                                         (unsigned int)row[x+1];
00582                         if( c >= 0x01FE )  /* we cut off secondary aliases */
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                                 {/* antialiasing here : */
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 )  /* we cut off secondary aliases */
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                                 {/* antialiasing here : */
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         /*fprintf( stderr, "scaling glyph down from %d to %d\n", from_width, to_width );*/
00656     /* LOCAL_DEBUG_OUT( "smaller %d, bigger %d, eps %d", smaller, bigger, eps ); */
00657     /* now using Bresengham algoritm to fiill the scales :
00658          * since scaling is merely transformation
00659          * from 0:bigger space (x) to 0:smaller space(y)*/
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                         /* add next elem here */
00671                         sum += (unsigned int)ptr[i] ;
00672                         ++count ;                          
00673                         eps += smaller;
00674                 
00675                         if( eps+eps >= bigger )
00676                         {
00677                                 /* divide here */
00678                                 /*fprintf( stderr, "i=%d, k=%d, sum=%d, count=%d\n", i, k, sum, count );*/
00679                                 ptr[k] = ( count > 1 )?sum/count:sum ;
00680                                 sum = 0 ;
00681                                 count = 0 ;
00682                                 ++k ;
00683                                 eps -= bigger ;
00684                         }               
00685                 }         
00686         }
00687         /* now we need to compress the pixmap */
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 /* encoding/locale handling                                                                                                              */
00704 /*********************************************************************************/
00705 
00706 /* Now, this is the mess, I know :
00707  * Internally we store everything in current locale;
00708  * WE then need to convert it into Unicode 4 byte codes
00709  *
00710  * TODO: think about incoming data - does it has to be made local friendly ???
00711  * Definately
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                         /* we cannot draw string at once since in some fonts charcters may
00794                          * overlap each other : */
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                 /*XDrawImageString( dpy, p, *gc, 0, xfs->ascent, test_str_char, len );*/
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 /*                                      fprintf( stderr, "glyph %d (%c): (%d,%d) 0x%X\n", i, (char)(i+r->min_char), x, y, XGetPixel( xim, pen_x+x, y ));*/
00817                                         /* remember default GC colors are black on white - 0 on 1 - and we need
00818                                         * quite the opposite - 0xFF on 0x00 */
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 /*                                      fprintf(stderr, "lead = %d, space_size = %d, width = %d, to_width = %d\n",
00837                                                         r->glyphs[i].lead, font->space_size, width, r->glyphs[i].width ); */
00838                                         scale_down_glyph_width( buffer, width, r->glyphs[i].width, height );
00839                                 }
00840                                 /*else
00841                                 {
00842                                         fprintf(stderr, "lead = %d, space_size = %d, width = %d\n",
00843                                                         r->glyphs[i].lead, font->space_size, width );
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 /*I18N*/
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                 /* we blame X consortium for the following mess : */
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 /* #ifndef X_DISPLAY_MISSING */
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 /*              int hpad = (face->glyph->bitmap_left<0)? -face->glyph->bitmap_left: face->glyph->bitmap_left ;
01043 */
01044                 asg->font_gid = glyph ; 
01045                 asg->width   = bmap->width ;
01046                 asg->height  = bmap->rows ;
01047                 /* Combining Diacritical Marks : */
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                 /* we only want to keep lead if it was negative */
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                 /* TODO: insert monospaced adjastments here */
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                          /* centering the glyph : */
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 /*                                      fprintf(stderr, "lead = %d, space_size = %d, width = %d, to_width = %d\n",
01112                                                 r->glyphs[i].lead, font->space_size, width, r->glyphs[i].width ); */
01113                         }
01114                         /*else
01115                         {
01116                                 fprintf(stderr, "lead = %d, space_size = %d, width = %d\n",
01117                                                 r->glyphs[i].lead, font->space_size, width );
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                 /* we better do some RLE encoding in attempt to preserv memory */
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     /* we preload only codes in range 0x21-0xFF in current charset */
01214         /* if draw_unicode_text is used and we need some other glyphs
01215          * we'll just need to add them on demand */
01216         font->codemap = split_freetype_glyph_range( 0x0021, 0x007F, font->ft_face );
01217 
01218         load_glyph_freetype( font, &(font->default_glyph), 0, 0);/* special no-symbol glyph */
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 /* Not needed ?
01249  *                                      if( asg->lead >= 0 || asg->lead+asg->width > 3 )
01250  *                                              font->pen_move_dir = LEFT_TO_RIGHT ;
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         /* flushing out compression buffer : */
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 /* actuall rendering code :                                                                                                              */
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 /*              fprintf( stderr, "####### pair %d ,%d   has kerning = %d\n", prev_gid,this_gid, var ); */
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; /* i+=CHAR_SIZE(text[i])-1; */ \
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 /* assuming attr->char_type == ASCT_Char by default */
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/*autodetect length*/, 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/*autodetect length*/, 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/*autodetect length*/, 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 /*fprintf( stderr, "data = %X, count = %d, x = %d, y = %d\n", data, count, x, y );*/
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 /*fprintf( stderr, "data = %X, count = %d, x = %d, y = %d\n", data, count, x, y );*/
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         // Perform line breaks if a fixed width is specified
01873         // TODO: this is a quick and dirty fix and should work for now, but we really should fix it 
01874         // so we don't have to calculate text size so many times as well as make it UNICODE friendly
01875         // and remove mangling of the source text (Sasha): 
01876         if (attr->width)
01877         {
01878         unsigned int width, height; // SMA
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 /*fprintf( stderr, "drawing character %d '%c'\n", i, text[i] );*/
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                                 /* now comes the fun part : */
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/*autodetect length*/ );
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/*autodetect length*/ );
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/*autodetect length*/ );
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 /* Misc functions : */
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    );              /* free type font handle */
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         /* xrender code starts here : */
02266         /* Step 1: we have to make sure we have a valid GlyphSet */
02267         if( font->xrender_glyphset == 0 ) 
02268                 font->xrender_glyphset = XRenderCreateGlyphSet (asv->dpy, asv->xrender_mask_format);
02269         /* Step 2: we have to make sure all the glyphs are in GlyphSet */
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         /* Step 3: actually rendering text  : */
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         /* xrender code ends here : */
02350         free_glyph_map( &map, True );     
02351 }
02352 
02353 #endif
02354 
02355 
02356 /*********************************************************************************/
02357 /* The end !!!!                                                                                                                                  */
02358 /*********************************************************************************/
02359 

Generated on Tue Jul 5 14:13:26 2011 for ROOT_528-00b_version by  doxygen 1.5.1