13 font.c - implements font handling functions for t1 and truetype fonts
20 fontnum = i_t1_new(path_to_pfb, path_to_afm);
21 i_t1_bbox(fontnum, points, "foo", 3, int cords[6]);
22 rc = i_t1_destroy(fontnum);
26 handle = i_tt_new(path_to_ttf);
27 rc = i_tt_bbox(handle, points, "foo", 3, int cords[6], utf8);
34 font.c implements font creation, rendering, bounding box functions and
37 =head1 FUNCTION REFERENCE
39 Some of these functions are internal.
50 Initialize font rendering libraries if they are avaliable.
56 i_init_fonts(int t1log) {
57 mm_log((1,"Initializing fonts\n"));
72 return(1); /* FIXME: Always true - check the return values of the init_t1 and init_tt functions */
80 static int t1_get_flags(char const *flags);
81 static char *t1_from_utf8(char const *in, int len, int *outlen);
83 static void t1_push_error(void);
86 =item i_init_t1(t1log)
88 Initializes the t1lib font rendering engine.
94 i_init_t1(int t1log) {
95 int init_flags = IGNORE_CONFIGFILE|IGNORE_FONTDATABASE;
96 mm_log((1,"init_t1()\n"));
99 init_flags |= LOGFILE;
100 if ((T1_InitLib(init_flags) == NULL)){
101 mm_log((1,"Initialization of t1lib failed\n"));
104 T1_SetLogLevel(T1LOG_DEBUG);
105 i_t1_set_aa(1); /* Default Antialias value */
113 Shuts the t1lib font rendering engine down.
115 This it seems that this function is never used.
127 =item i_t1_new(pfb, afm)
129 Loads the fonts with the given filenames, returns its font id
131 pfb - path to pfb file for font
132 afm - path to afm file for font
138 i_t1_new(char *pfb,char *afm) {
141 mm_log((1,"i_t1_new(pfb %s,afm %s)\n",pfb,(afm?afm:"NULL")));
142 font_id = T1_AddFont(pfb);
144 mm_log((1,"i_t1_new: Failed to load pfb file '%s' - return code %d.\n",pfb,font_id));
149 mm_log((1,"i_t1_new: requesting afm file '%s'.\n",afm));
150 if (T1_SetAfmFileName(font_id,afm)<0) mm_log((1,"i_t1_new: afm loading of '%s' failed.\n",afm));
157 =item i_t1_destroy(font_id)
159 Frees resources for a t1 font with given font id.
161 font_id - number of the font to free
167 i_t1_destroy(int font_id) {
168 mm_log((1,"i_t1_destroy(font_id %d)\n",font_id));
169 return T1_DeleteFont(font_id);
174 =item i_t1_set_aa(st)
176 Sets the antialiasing level of the t1 library.
178 st - 0 = NONE, 1 = LOW, 2 = HIGH.
184 i_t1_set_aa(int st) {
186 unsigned long cst[17];
189 T1_AASetBitsPerPixel( 8 );
190 T1_AASetLevel( T1_AA_NONE );
191 T1_AANSetGrayValues( 0, 255 );
192 mm_log((1,"setting T1 antialias to none\n"));
195 T1_AASetBitsPerPixel( 8 );
196 T1_AASetLevel( T1_AA_LOW );
197 T1_AASetGrayValues( 0,65,127,191,255 );
198 mm_log((1,"setting T1 antialias to low\n"));
201 T1_AASetBitsPerPixel(8);
202 T1_AASetLevel(T1_AA_HIGH);
203 for(i=0;i<17;i++) cst[i]=(i*255)/16;
204 T1_AAHSetGrayValues( cst );
205 mm_log((1,"setting T1 antialias to high\n"));
211 =item i_t1_cp(im, xb, yb, channel, fontnum, points, str, len, align)
213 Interface to text rendering into a single channel in an image
215 im pointer to image structure
216 xb x coordinate of start of string
217 yb y coordinate of start of string ( see align )
218 channel - destination channel
219 fontnum - t1 library font id
220 points - number of points in fontheight
221 str - string to render
223 align - (0 - top of font glyph | 1 - baseline )
229 i_t1_cp(i_img *im,int xb,int yb,int channel,int fontnum,float points,char* str,int len,int align, int utf8, char const *flags) {
233 int mod_flags = t1_get_flags(flags);
235 unsigned int ch_mask_store;
237 if (im == NULL) { mm_log((1,"i_t1_cp: Null image in input\n")); return(0); }
241 char *work = t1_from_utf8(str, len, &worklen);
242 glyph=T1_AASetString( fontnum, work, worklen, 0, mod_flags, points, NULL);
246 glyph=T1_AASetString( fontnum, str, len, 0, mod_flags, points, NULL);
251 mm_log((1,"metrics: ascent: %d descent: %d\n",glyph->metrics.ascent,glyph->metrics.descent));
252 mm_log((1," leftSideBearing: %d rightSideBearing: %d\n",glyph->metrics.leftSideBearing,glyph->metrics.rightSideBearing));
253 mm_log((1," advanceX: %d advanceY: %d\n",glyph->metrics.advanceX,glyph->metrics.advanceY));
254 mm_log((1,"bpp: %d\n",glyph->bpp));
256 xsize=glyph->metrics.rightSideBearing-glyph->metrics.leftSideBearing;
257 ysize=glyph->metrics.ascent-glyph->metrics.descent;
259 mm_log((1,"width: %d height: %d\n",xsize,ysize));
261 ch_mask_store=im->ch_mask;
262 im->ch_mask=1<<channel;
264 if (align==1) { xb+=glyph->metrics.leftSideBearing; yb-=glyph->metrics.ascent; }
266 for(y=0;y<ysize;y++) for(x=0;x<xsize;x++) {
267 val.channel[channel]=glyph->bits[y*xsize+x];
268 i_ppix(im,x+xb,y+yb,&val);
271 im->ch_mask=ch_mask_store;
277 =item i_t1_bbox(handle, fontnum, points, str, len, cords)
279 function to get a strings bounding box given the font id and sizes
281 handle - pointer to font handle
282 fontnum - t1 library font id
283 points - number of points in fontheight
284 str - string to measure
286 cords - the bounding box (modified in place)
292 i_t1_bbox(int fontnum,float points,char *str,int len,int cords[6], int utf8,char const *flags) {
295 int mod_flags = t1_get_flags(flags);
298 mm_log((1,"i_t1_bbox(fontnum %d,points %.2f,str '%.*s', len %d)\n",fontnum,points,len,str,len));
299 T1_LoadFont(fontnum); /* FIXME: Here a return code is ignored - haw haw haw */
302 char *work = t1_from_utf8(str, len, &worklen);
303 bbox = T1_GetStringBBox(fontnum,work,worklen,0,mod_flags);
307 bbox = T1_GetStringBBox(fontnum,str,len,0,mod_flags);
309 gbbox = T1_GetFontBBox(fontnum);
310 advance = T1_GetStringWidth(fontnum, str, len, 0, mod_flags);
312 mm_log((1,"bbox: (%d,%d,%d,%d)\n",
313 (int)(bbox.llx*points/1000),
314 (int)(gbbox.lly*points/1000),
315 (int)(bbox.urx*points/1000),
316 (int)(gbbox.ury*points/1000),
317 (int)(bbox.lly*points/1000),
318 (int)(bbox.ury*points/1000) ));
321 cords[BBOX_NEG_WIDTH]=((float)bbox.llx*points)/1000;
322 cords[BBOX_POS_WIDTH]=((float)bbox.urx*points)/1000;
324 cords[BBOX_GLOBAL_DESCENT]=((float)gbbox.lly*points)/1000;
325 cords[BBOX_GLOBAL_ASCENT]=((float)gbbox.ury*points)/1000;
327 cords[BBOX_DESCENT]=((float)bbox.lly*points)/1000;
328 cords[BBOX_ASCENT]=((float)bbox.ury*points)/1000;
330 cords[BBOX_ADVANCE_WIDTH] = ((float)advance * points)/1000;
332 return BBOX_ADVANCE_WIDTH+1;
337 =item i_t1_text(im, xb, yb, cl, fontnum, points, str, len, align)
339 Interface to text rendering in a single color onto an image
341 im - pointer to image structure
342 xb - x coordinate of start of string
343 yb - y coordinate of start of string ( see align )
344 cl - color to draw the text in
345 fontnum - t1 library font id
346 points - number of points in fontheight
347 str - char pointer to string to render
349 align - (0 - top of font glyph | 1 - baseline )
355 i_t1_text(i_img *im,int xb,int yb,i_color *cl,int fontnum,float points,char* str,int len,int align, int utf8, char const *flags) {
357 int xsize,ysize,x,y,ch;
360 int mod_flags = t1_get_flags(flags);
362 if (im == NULL) { mm_log((1,"i_t1_cp: Null image in input\n")); return(0); }
366 char *work = t1_from_utf8(str, len, &worklen);
367 glyph=T1_AASetString( fontnum, work, worklen, 0, mod_flags, points, NULL);
371 glyph=T1_AASetString( fontnum, str, len, 0, mod_flags, points, NULL);
376 mm_log((1,"metrics: ascent: %d descent: %d\n",glyph->metrics.ascent,glyph->metrics.descent));
377 mm_log((1," leftSideBearing: %d rightSideBearing: %d\n",glyph->metrics.leftSideBearing,glyph->metrics.rightSideBearing));
378 mm_log((1," advanceX: %d advanceY: %d\n",glyph->metrics.advanceX,glyph->metrics.advanceY));
379 mm_log((1,"bpp: %d\n",glyph->bpp));
381 xsize=glyph->metrics.rightSideBearing-glyph->metrics.leftSideBearing;
382 ysize=glyph->metrics.ascent-glyph->metrics.descent;
384 mm_log((1,"width: %d height: %d\n",xsize,ysize));
386 if (align==1) { xb+=glyph->metrics.leftSideBearing; yb-=glyph->metrics.ascent; }
388 for(y=0;y<ysize;y++) for(x=0;x<xsize;x++) {
389 c=glyph->bits[y*xsize+x];
391 i_gpix(im,x+xb,y+yb,&val);
392 for(ch=0;ch<im->channels;ch++) val.channel[ch]=(c*cl->channel[ch]+i*val.channel[ch])/255;
393 i_ppix(im,x+xb,y+yb,&val);
399 =item t1_get_flags(flags)
401 Processes the characters in I<flags> to create a mod_flags value used
402 by some T1Lib functions.
407 t1_get_flags(char const *flags) {
408 int mod_flags = T1_KERNING;
412 case 'u': case 'U': mod_flags |= T1_UNDERLINE; break;
413 case 'o': case 'O': mod_flags |= T1_OVERLINE; break;
414 case 's': case 'S': mod_flags |= T1_OVERSTRIKE; break;
415 /* ignore anything we don't recognize */
423 =item t1_from_utf8(char const *in, int len, int *outlen)
425 Produces an unencoded version of I<in> by dropping any Unicode
428 Returns a newly allocated buffer which should be freed with myfree().
429 Sets *outlen to the number of bytes used in the output string.
435 t1_from_utf8(char const *in, int len, int *outlen) {
436 char *out = mymalloc(len+1);
441 c = i_utf8_advance(&in, &len);
444 i_push_error(0, "invalid UTF8 character");
447 /* yeah, just drop them */
459 =item i_t1_has_chars(font_num, text, len, utf8, out)
461 Check if the given characters are defined by the font. Note that len
462 is the number of bytes, not the number of characters (when utf8 is
465 out[char index] will be true if the character exists.
467 Accepts UTF-8, but since T1 can only have 256 characters, any chars
468 with values over 255 will simply be returned as false.
470 Returns the number of characters that were checked.
476 i_t1_has_chars(int font_num, const char *text, int len, int utf8,
480 mm_log((1, "i_t1_has_chars(font_num %d, text %p, len %d, utf8 %d)\n",
481 font_num, text, len, utf8));
484 if (T1_LoadFont(font_num)) {
493 c = i_utf8_advance(&text, &len);
495 i_push_error(0, "invalid UTF8 character");
500 c = (unsigned char)*text++;
505 /* limit of 256 characters for T1 */
509 char const * name = T1_GetCharName(font_num, (unsigned char)c);
512 *out++ = strcmp(name, ".notdef") != 0;
515 mm_log((2, " No name found for character %lx\n", c));
526 =item i_t1_face_name(font_num, name_buf, name_buf_size)
528 Copies the face name of the given C<font_num> to C<name_buf>. Returns
529 the number of characters required to store the name (which can be
530 larger than C<name_buf_size>, including the space required to store
531 the terminating NUL).
533 If name_buf is too small (as specified by name_buf_size) then the name
534 will be truncated. name_buf will always be NUL termintaed.
540 i_t1_face_name(int font_num, char *name_buf, size_t name_buf_size) {
544 if (T1_LoadFont(font_num)) {
548 name = T1_GetFontName(font_num);
551 strncpy(name_buf, name, name_buf_size);
552 name_buf[name_buf_size-1] = '\0';
553 return strlen(name) + 1;
562 i_t1_glyph_name(int font_num, unsigned long ch, char *name_buf,
563 size_t name_buf_size) {
570 if (T1_LoadFont(font_num)) {
574 name = T1_GetCharName(font_num, (unsigned char)ch);
576 if (strcmp(name, ".notdef")) {
577 strncpy(name_buf, name, name_buf_size);
578 name_buf[name_buf_size-1] = '\0';
579 return strlen(name) + 1;
592 t1_push_error(void) {
595 i_push_error(0, "No error");
598 case T1ERR_SCAN_FONT_FORMAT:
599 i_push_error(T1ERR_SCAN_FONT_FORMAT, "SCAN_FONT_FORMAT");
602 case T1ERR_SCAN_FILE_OPEN_ERR:
603 i_push_error(T1ERR_SCAN_FILE_OPEN_ERR, "SCAN_FILE_OPEN_ERR");
606 case T1ERR_SCAN_OUT_OF_MEMORY:
607 i_push_error(T1ERR_SCAN_OUT_OF_MEMORY, "SCAN_OUT_OF_MEMORY");
610 case T1ERR_SCAN_ERROR:
611 i_push_error(T1ERR_SCAN_ERROR, "SCAN_ERROR");
614 case T1ERR_SCAN_FILE_EOF:
615 i_push_error(T1ERR_SCAN_FILE_EOF, "SCAN_FILE_EOF");
618 case T1ERR_PATH_ERROR:
619 i_push_error(T1ERR_PATH_ERROR, "PATH_ERROR");
622 case T1ERR_PARSE_ERROR:
623 i_push_error(T1ERR_PARSE_ERROR, "PARSE_ERROR");
626 case T1ERR_TYPE1_ABORT:
627 i_push_error(T1ERR_TYPE1_ABORT, "TYPE1_ABORT");
630 case T1ERR_INVALID_FONTID:
631 i_push_error(T1ERR_INVALID_FONTID, "INVALID_FONTID");
634 case T1ERR_INVALID_PARAMETER:
635 i_push_error(T1ERR_INVALID_PARAMETER, "INVALID_PARAMETER");
638 case T1ERR_OP_NOT_PERMITTED:
639 i_push_error(T1ERR_OP_NOT_PERMITTED, "OP_NOT_PERMITTED");
642 case T1ERR_ALLOC_MEM:
643 i_push_error(T1ERR_ALLOC_MEM, "ALLOC_MEM");
646 case T1ERR_FILE_OPEN_ERR:
647 i_push_error(T1ERR_FILE_OPEN_ERR, "FILE_OPEN_ERR");
650 case T1ERR_UNSPECIFIED:
651 i_push_error(T1ERR_UNSPECIFIED, "UNSPECIFIED");
654 case T1ERR_NO_AFM_DATA:
655 i_push_error(T1ERR_NO_AFM_DATA, "NO_AFM_DATA");
659 i_push_error(T1ERR_X11, "X11");
662 case T1ERR_COMPOSITE_CHAR:
663 i_push_error(T1ERR_COMPOSITE_CHAR, "COMPOSITE_CHAR");
667 i_push_errorf(T1_errno, "unknown error %d", (int)T1_errno);
671 #endif /* HAVE_LIBT1 */
674 /* Truetype font support */
677 /* This is enabled by default when configuring Freetype 1.x
678 I haven't a clue how to reliably detect it at compile time.
680 We need a compilation probe in Makefile.PL
684 #include <freetype.h>
691 /* some versions of FT1.x don't seem to define this - it's font defined
692 so it won't change */
693 #ifndef TT_MS_LANGID_ENGLISH_GENERAL
694 #define TT_MS_LANGID_ENGLISH_GENERAL 0x0409
697 /* convert a code point into an index in the glyph cache */
698 #define TT_HASH(x) ((x) & 0xFF)
700 typedef struct i_glyph_entry_ {
705 #define TT_NOCHAR (~0UL)
707 struct TT_Instancehandle_ {
708 TT_Instance instance;
709 TT_Instance_Metrics imetrics;
710 TT_Glyph_Metrics gmetrics[256];
711 i_tt_glyph_entry glyphs[256];
717 typedef struct TT_Instancehandle_ TT_Instancehandle;
719 struct TT_Fonthandle_ {
721 TT_Face_Properties properties;
722 TT_Instancehandle instanceh[TT_CHC];
732 #define USTRCT(x) ((x).z)
733 #define TT_VALID( handle ) ( ( handle ).z != NULL )
738 static int i_tt_get_instance( TT_Fonthandle *handle, int points, int smooth );
739 static void i_tt_init_raster_map( TT_Raster_Map* bit, int width, int height, int smooth );
740 static void i_tt_done_raster_map( TT_Raster_Map *bit );
741 static void i_tt_clear_raster_map( TT_Raster_Map* bit );
742 static void i_tt_blit_or( TT_Raster_Map *dst, TT_Raster_Map *src,int x_off, int y_off );
743 static int i_tt_get_glyph( TT_Fonthandle *handle, int inst, unsigned long j );
745 i_tt_render_glyph( TT_Glyph glyph, TT_Glyph_Metrics* gmetrics,
746 TT_Raster_Map *bit, TT_Raster_Map *small_bit,
747 int x_off, int y_off, int smooth );
749 i_tt_render_all_glyphs( TT_Fonthandle *handle, int inst, TT_Raster_Map *bit,
750 TT_Raster_Map *small_bit, int cords[6],
751 char const* txt, int len, int smooth, int utf8 );
752 static void i_tt_dump_raster_map2( i_img* im, TT_Raster_Map* bit, int xb, int yb, i_color *cl, int smooth );
753 static void i_tt_dump_raster_map_channel( i_img* im, TT_Raster_Map* bit, int xb, int yb, int channel, int smooth );
755 i_tt_rasterize( TT_Fonthandle *handle, TT_Raster_Map *bit, int cords[6],
756 float points, char const* txt, int len, int smooth, int utf8 );
757 static undef_int i_tt_bbox_inst( TT_Fonthandle *handle, int inst ,const char *txt, int len, int cords[6], int utf8 );
760 /* static globals needed */
762 static TT_Engine engine;
763 static int LTT_dpi = 72; /* FIXME: this ought to be a part of the call interface */
764 static int LTT_hinted = 1; /* FIXME: this too */
775 Initializes the freetype font rendering engine
783 mm_log((1,"init_tt()\n"));
784 error = TT_Init_FreeType( &engine );
786 mm_log((1,"Initialization of freetype failed, code = 0x%x\n",error));
791 error = TT_Init_Post_Extension( engine );
793 mm_log((1, "Initialization of Post extension failed = 0x%x\n", error));
803 =item i_tt_get_instance(handle, points, smooth)
805 Finds a points+smooth instance or if one doesn't exist in the cache
806 allocates room and returns its cache entry
808 fontname - path to the font to load
809 handle - handle to the font.
810 points - points of the requested font
811 smooth - boolean (True: antialias on, False: antialias is off)
818 i_tt_get_instance( TT_Fonthandle *handle, int points, int smooth ) {
822 mm_log((1,"i_tt_get_instance(handle 0x%X, points %d, smooth %d)\n",
823 handle,points,smooth));
825 if (smooth == -1) { /* Smooth doesn't matter for this search */
826 for(i=0;i<TT_CHC;i++) {
827 if (handle->instanceh[i].ptsize==points) {
828 mm_log((1,"i_tt_get_instance: in cache - (non selective smoothing search) returning %d\n",i));
832 smooth=1; /* We will be adding a font - add it as smooth then */
833 } else { /* Smooth doesn't matter for this search */
834 for(i=0;i<TT_CHC;i++) {
835 if (handle->instanceh[i].ptsize == points
836 && handle->instanceh[i].smooth == smooth) {
837 mm_log((1,"i_tt_get_instance: in cache returning %d\n",i));
843 /* Found the instance in the cache - return the cache index */
845 for(idx=0;idx<TT_CHC;idx++) {
846 if (!(handle->instanceh[idx].order)) break; /* find the lru item */
849 mm_log((1,"i_tt_get_instance: lru item is %d\n",idx));
850 mm_log((1,"i_tt_get_instance: lru pointer 0x%X\n",
851 USTRCT(handle->instanceh[idx].instance) ));
853 if ( USTRCT(handle->instanceh[idx].instance) ) {
854 mm_log((1,"i_tt_get_instance: freeing lru item from cache %d\n",idx));
856 /* Free cached glyphs */
858 if ( USTRCT(handle->instanceh[idx].glyphs[i].glyph) )
859 TT_Done_Glyph( handle->instanceh[idx].glyphs[i].glyph );
862 handle->instanceh[idx].glyphs[i].ch = TT_NOCHAR;
863 USTRCT(handle->instanceh[idx].glyphs[i].glyph)=NULL;
866 /* Free instance if needed */
867 TT_Done_Instance( handle->instanceh[idx].instance );
870 /* create and initialize instance */
871 /* FIXME: probably a memory leak on fail */
873 (void) (( error = TT_New_Instance( handle->face, &handle->instanceh[idx].instance ) ) ||
874 ( error = TT_Set_Instance_Resolutions( handle->instanceh[idx].instance, LTT_dpi, LTT_dpi ) ) ||
875 ( error = TT_Set_Instance_CharSize( handle->instanceh[idx].instance, points*64 ) ) );
878 mm_log((1, "Could not create and initialize instance: error 0x%x.\n",error ));
882 /* Now that the instance should the inplace we need to lower all of the
883 ru counts and put `this' one with the highest entry */
885 for(i=0;i<TT_CHC;i++) handle->instanceh[i].order--;
887 handle->instanceh[idx].order=TT_CHC-1;
888 handle->instanceh[idx].ptsize=points;
889 handle->instanceh[idx].smooth=smooth;
890 TT_Get_Instance_Metrics( handle->instanceh[idx].instance, &(handle->instanceh[idx].imetrics) );
892 /* Zero the memory for the glyph storage so they are not thought as
893 cached if they haven't been cached since this new font was loaded */
896 handle->instanceh[idx].glyphs[i].ch = TT_NOCHAR;
897 USTRCT(handle->instanceh[idx].glyphs[i].glyph)=NULL;
905 =item i_tt_new(fontname)
907 Creates a new font handle object, finds a character map and initialise the
908 the font handle's cache
910 fontname - path to the font to load
916 i_tt_new(char *fontname) {
918 TT_Fonthandle *handle;
920 unsigned short platform,encoding;
922 mm_log((1,"i_tt_new(fontname '%s')\n",fontname));
924 /* allocate memory for the structure */
926 handle = mymalloc( sizeof(TT_Fonthandle) );
928 /* load the typeface */
929 error = TT_Open_Face( engine, fontname, &handle->face );
931 if ( error == TT_Err_Could_Not_Open_File ) {
932 mm_log((1, "Could not find/open %s.\n", fontname ));
935 mm_log((1, "Error while opening %s, error code = 0x%x.\n",fontname,
941 TT_Get_Face_Properties( handle->face, &(handle->properties) );
943 /* First, look for a Unicode charmap */
944 n = handle->properties.num_CharMaps;
945 USTRCT( handle->char_map )=NULL; /* Invalidate character map */
947 for ( i = 0; i < n; i++ ) {
948 TT_Get_CharMap_ID( handle->face, i, &platform, &encoding );
949 if ( (platform == 3 && encoding == 1 )
950 || (platform == 0 && encoding == 0 ) ) {
951 mm_log((2,"i_tt_new - found char map platform %u encoding %u\n",
952 platform, encoding));
953 TT_Get_CharMap( handle->face, i, &(handle->char_map) );
957 if (!USTRCT(handle->char_map) && n != 0) {
958 /* just use the first one */
959 TT_Get_CharMap( handle->face, 0, &(handle->char_map));
962 /* Zero the pointsizes - and ordering */
964 for(i=0;i<TT_CHC;i++) {
965 USTRCT(handle->instanceh[i].instance)=NULL;
966 handle->instanceh[i].order=i;
967 handle->instanceh[i].ptsize=0;
968 handle->instanceh[i].smooth=-1;
972 handle->loaded_names = 0;
975 mm_log((1,"i_tt_new <- 0x%X\n",handle));
982 * raster map management
986 =item i_tt_init_raster_map(bit, width, height, smooth)
988 Allocates internal memory for the bitmap as needed by the parameters (internal)
990 bit - bitmap to allocate into
991 width - width of the bitmap
992 height - height of the bitmap
993 smooth - boolean (True: antialias on, False: antialias is off)
1000 i_tt_init_raster_map( TT_Raster_Map* bit, int width, int height, int smooth ) {
1002 mm_log((1,"i_tt_init_raster_map( bit 08x%08X, width %d, height %d, smooth %d)\n", bit, width, height, smooth));
1005 bit->width = ( width + 3 ) & -4;
1006 bit->flow = TT_Flow_Down;
1009 bit->cols = bit->width;
1010 bit->size = bit->rows * bit->width;
1012 bit->cols = ( bit->width + 7 ) / 8; /* convert to # of bytes */
1013 bit->size = bit->rows * bit->cols; /* number of bytes in buffer */
1016 mm_log((1,"i_tt_init_raster_map: bit->width %d, bit->cols %d, bit->rows %d, bit->size %d)\n", bit->width, bit->cols, bit->rows, bit->size ));
1018 bit->bitmap = (void *) mymalloc( bit->size );
1019 if ( !bit->bitmap ) m_fatal(0,"Not enough memory to allocate bitmap (%d)!\n",bit->size );
1024 =item i_tt_clear_raster_map(bit)
1026 Frees the bitmap data and sets pointer to NULL (internal)
1028 bit - bitmap to free
1035 i_tt_done_raster_map( TT_Raster_Map *bit ) {
1036 myfree( bit->bitmap );
1042 =item i_tt_clear_raster_map(bit)
1044 Clears the specified bitmap (internal)
1046 bit - bitmap to zero
1054 i_tt_clear_raster_map( TT_Raster_Map* bit ) {
1055 memset( bit->bitmap, 0, bit->size );
1060 =item i_tt_blit_or(dst, src, x_off, y_off)
1062 function that blits one raster map into another (internal)
1064 dst - destination bitmap
1066 x_off - x offset into the destination bitmap
1067 y_off - y offset into the destination bitmap
1074 i_tt_blit_or( TT_Raster_Map *dst, TT_Raster_Map *src,int x_off, int y_off ) {
1079 x1 = x_off < 0 ? -x_off : 0;
1080 y1 = y_off < 0 ? -y_off : 0;
1082 x2 = (int)dst->cols - x_off;
1083 if ( x2 > src->cols ) x2 = src->cols;
1085 y2 = (int)dst->rows - y_off;
1086 if ( y2 > src->rows ) y2 = src->rows;
1088 if ( x1 >= x2 ) return;
1090 /* do the real work now */
1092 for ( y = y1; y < y2; ++y ) {
1093 s = ( (char*)src->bitmap ) + y * src->cols + x1;
1094 d = ( (char*)dst->bitmap ) + ( y + y_off ) * dst->cols + x1 + x_off;
1096 for ( x = x1; x < x2; ++x ) {
1105 /* useful for debugging */
1108 static void dump_raster_map(FILE *out, TT_Raster_Map *bit ) {
1110 fprintf(out, "cols %d rows %d flow %d\n", bit->cols, bit->rows, bit->flow);
1111 for (y = 0; y < bit->rows; ++y) {
1112 fprintf(out, "%2d:", y);
1113 for (x = 0; x < bit->cols; ++x) {
1114 if ((x & 7) == 0 && x) putc(' ', out);
1115 fprintf(out, "%02x", ((unsigned char *)bit->bitmap)[y*bit->cols+x]);
1124 =item i_tt_get_glyph(handle, inst, j)
1126 Function to see if a glyph exists and if so cache it (internal)
1128 handle - pointer to font handle
1129 inst - font instance
1130 j - charcode of glyph
1137 i_tt_get_glyph( TT_Fonthandle *handle, int inst, unsigned long j) {
1138 unsigned short load_flags, code;
1141 mm_log((1, "i_tt_get_glyph(handle 0x%X, inst %d, j %d (%c))\n",
1142 handle,inst,j, ((j >= ' ' && j <= '~') ? j : '.')));
1144 /*mm_log((1, "handle->instanceh[inst].glyphs[j]=0x%08X\n",handle->instanceh[inst].glyphs[j] ));*/
1146 if ( TT_VALID(handle->instanceh[inst].glyphs[TT_HASH(j)].glyph)
1147 && handle->instanceh[inst].glyphs[TT_HASH(j)].ch == j) {
1148 mm_log((1,"i_tt_get_glyph: %d in cache\n",j));
1152 if ( TT_VALID(handle->instanceh[inst].glyphs[TT_HASH(j)].glyph) ) {
1153 /* clean up the entry */
1154 TT_Done_Glyph( handle->instanceh[inst].glyphs[TT_HASH(j)].glyph );
1155 USTRCT( handle->instanceh[inst].glyphs[TT_HASH(j)].glyph ) = NULL;
1156 handle->instanceh[inst].glyphs[TT_HASH(j)].ch = TT_NOCHAR;
1159 /* Ok - it wasn't cached - try to get it in */
1160 load_flags = TTLOAD_SCALE_GLYPH;
1161 if ( LTT_hinted ) load_flags |= TTLOAD_HINT_GLYPH;
1163 if ( !TT_VALID(handle->char_map) ) {
1164 code = (j - ' ' + 1) < 0 ? 0 : (j - ' ' + 1);
1165 if ( code >= handle->properties.num_Glyphs ) code = 0;
1166 } else code = TT_Char_Index( handle->char_map, j );
1168 if ( (error = TT_New_Glyph( handle->face, &handle->instanceh[inst].glyphs[TT_HASH(j)].glyph)) ) {
1169 mm_log((1, "Cannot allocate and load glyph: error 0x%x.\n", error ));
1170 i_push_error(error, "TT_New_Glyph()");
1173 if ( (error = TT_Load_Glyph( handle->instanceh[inst].instance, handle->instanceh[inst].glyphs[TT_HASH(j)].glyph, code, load_flags)) ) {
1174 mm_log((1, "Cannot allocate and load glyph: error 0x%x.\n", error ));
1176 TT_Done_Glyph( handle->instanceh[inst].glyphs[TT_HASH(j)].glyph );
1177 USTRCT( handle->instanceh[inst].glyphs[TT_HASH(j)].glyph ) = NULL;
1178 i_push_error(error, "TT_Load_Glyph()");
1182 /* At this point the glyph should be allocated and loaded */
1183 handle->instanceh[inst].glyphs[TT_HASH(j)].ch = j;
1185 /* Next get the glyph metrics */
1186 error = TT_Get_Glyph_Metrics( handle->instanceh[inst].glyphs[TT_HASH(j)].glyph,
1187 &handle->instanceh[inst].gmetrics[TT_HASH(j)] );
1189 mm_log((1, "TT_Get_Glyph_Metrics: error 0x%x.\n", error ));
1190 TT_Done_Glyph( handle->instanceh[inst].glyphs[TT_HASH(j)].glyph );
1191 USTRCT( handle->instanceh[inst].glyphs[TT_HASH(j)].glyph ) = NULL;
1192 handle->instanceh[inst].glyphs[TT_HASH(j)].ch = TT_NOCHAR;
1193 i_push_error(error, "TT_Get_Glyph_Metrics()");
1201 =item i_tt_has_chars(handle, text, len, utf8, out)
1203 Check if the given characters are defined by the font. Note that len
1204 is the number of bytes, not the number of characters (when utf8 is
1207 Returns the number of characters that were checked.
1213 i_tt_has_chars(TT_Fonthandle *handle, char const *text, int len, int utf8,
1217 mm_log((1, "i_tt_has_chars(handle %p, text %p, len %d, utf8 %d)\n",
1218 handle, text, len, utf8));
1224 c = i_utf8_advance(&text, &len);
1226 i_push_error(0, "invalid UTF8 character");
1231 c = (unsigned char)*text++;
1235 if (TT_VALID(handle->char_map)) {
1236 index = TT_Char_Index(handle->char_map, c);
1239 index = (c - ' ' + 1) < 0 ? 0 : (c - ' ' + 1);
1240 if (index >= handle->properties.num_Glyphs)
1243 *out++ = index != 0;
1251 =item i_tt_destroy(handle)
1253 Clears the data taken by a font including all cached data such as
1256 handle - pointer to font handle
1262 i_tt_destroy( TT_Fonthandle *handle) {
1263 TT_Close_Face( handle->face );
1266 /* FIXME: Should these be freed automatically by the library?
1268 TT_Done_Instance( instance );
1270 i_tt_done_glyphs( void ) {
1273 if ( !glyphs ) return;
1275 for ( i = 0; i < 256; ++i ) TT_Done_Glyph( glyphs[i] );
1285 * FreeType Rendering functions
1290 =item i_tt_render_glyph(handle, gmetrics, bit, smallbit, x_off, y_off, smooth)
1292 Renders a single glyph into the bit rastermap (internal)
1294 handle - pointer to font handle
1295 gmetrics - the metrics for the glyph to be rendered
1296 bit - large bitmap that is the destination for the text
1297 smallbit - small bitmap that is used only if smooth is true
1298 x_off - x offset of glyph
1299 y_off - y offset of glyph
1300 smooth - boolean (True: antialias on, False: antialias is off)
1307 i_tt_render_glyph( TT_Glyph glyph, TT_Glyph_Metrics* gmetrics, TT_Raster_Map *bit, TT_Raster_Map *small_bit, int x_off, int y_off, int smooth ) {
1309 mm_log((1,"i_tt_render_glyph(glyph 0x0%X, gmetrics 0x0%X, bit 0x%X, small_bit 0x%X, x_off %d, y_off %d, smooth %d)\n",
1310 USTRCT(glyph), gmetrics, bit, small_bit, x_off,y_off,smooth));
1312 if ( !smooth ) TT_Get_Glyph_Bitmap( glyph, bit, x_off * 64, y_off * 64);
1314 TT_F26Dot6 xmin, ymin, xmax, ymax;
1316 xmin = gmetrics->bbox.xMin & -64;
1317 ymin = gmetrics->bbox.yMin & -64;
1318 xmax = (gmetrics->bbox.xMax + 63) & -64;
1319 ymax = (gmetrics->bbox.yMax + 63) & -64;
1321 i_tt_clear_raster_map( small_bit );
1322 TT_Get_Glyph_Pixmap( glyph, small_bit, -xmin, -ymin );
1323 i_tt_blit_or( bit, small_bit, xmin/64 + x_off, -ymin/64 - y_off );
1329 =item i_tt_render_all_glyphs(handle, inst, bit, small_bit, cords, txt, len, smooth)
1331 calls i_tt_render_glyph to render each glyph into the bit rastermap (internal)
1333 handle - pointer to font handle
1334 inst - font instance
1335 bit - large bitmap that is the destination for the text
1336 smallbit - small bitmap that is used only if smooth is true
1337 txt - string to render
1338 len - length of the string to render
1339 smooth - boolean (True: antialias on, False: antialias is off)
1346 i_tt_render_all_glyphs( TT_Fonthandle *handle, int inst, TT_Raster_Map *bit,
1347 TT_Raster_Map *small_bit, int cords[6],
1348 char const* txt, int len, int smooth, int utf8 ) {
1353 mm_log((1,"i_tt_render_all_glyphs( handle 0x%X, inst %d, bit 0x%X, small_bit 0x%X, txt '%.*s', len %d, smooth %d, utf8 %d)\n",
1354 handle, inst, bit, small_bit, len, txt, len, smooth, utf8));
1357 y=-( handle->properties.horizontal->Descender * handle->instanceh[inst].imetrics.y_ppem )/(handle->properties.header->Units_Per_EM);
1360 x=-cords[0]; /* FIXME: If you font is antialiased this should be expanded by one to allow for aa expansion and the allocation too - do before passing here */
1365 j = i_utf8_advance(&txt, &len);
1367 i_push_error(0, "invalid UTF8 character");
1372 j = (unsigned char)*txt++;
1375 if ( !i_tt_get_glyph(handle,inst,j) )
1377 i_tt_render_glyph( handle->instanceh[inst].glyphs[TT_HASH(j)].glyph,
1378 &handle->instanceh[inst].gmetrics[TT_HASH(j)], bit,
1379 small_bit, x, y, smooth );
1380 x += handle->instanceh[inst].gmetrics[TT_HASH(j)].advance / 64;
1388 * Functions to render rasters (single channel images) onto images
1392 =item i_tt_dump_raster_map2(im, bit, xb, yb, cl, smooth)
1394 Function to dump a raster onto an image in color used by i_tt_text() (internal).
1396 im - image to dump raster on
1397 bit - bitmap that contains the text to be dumped to im
1398 xb, yb - coordinates, left edge and baseline
1399 cl - color to use for text
1400 smooth - boolean (True: antialias on, False: antialias is off)
1407 i_tt_dump_raster_map2( i_img* im, TT_Raster_Map* bit, int xb, int yb, i_color *cl, int smooth ) {
1411 mm_log((1,"i_tt_dump_raster_map2(im 0x%x, bit 0x%X, xb %d, yb %d, cl 0x%X)\n",im,bit,xb,yb,cl));
1413 bmap = (char *)bit->bitmap;
1417 for(y=0;y<bit->rows;y++) for(x=0;x<bit->width;x++) {
1418 c=(255*bmap[y*(bit->cols)+x])/4;
1420 i_gpix(im,x+xb,y+yb,&val);
1421 for(ch=0;ch<im->channels;ch++) val.channel[ch]=(c*cl->channel[ch]+i*val.channel[ch])/255;
1422 i_ppix(im,x+xb,y+yb,&val);
1427 for(y=0;y<bit->rows;y++) for(x=0;x<bit->width;x++) {
1428 c=( bmap[y*bit->cols+x/8] & (128>>(x%8)) ) ? 255 : 0;
1430 i_gpix(im,x+xb,y+yb,&val);
1431 for(ch=0;ch<im->channels;ch++) val.channel[ch]=(c*cl->channel[ch]+i*val.channel[ch])/255;
1432 i_ppix(im,x+xb,y+yb,&val);
1440 =item i_tt_dump_raster_map_channel(im, bit, xb, yb, channel, smooth)
1442 Function to dump a raster onto a single channel image in color (internal)
1444 im - image to dump raster on
1445 bit - bitmap that contains the text to be dumped to im
1446 xb, yb - coordinates, left edge and baseline
1447 channel - channel to copy to
1448 smooth - boolean (True: antialias on, False: antialias is off)
1455 i_tt_dump_raster_map_channel( i_img* im, TT_Raster_Map* bit, int xb, int yb, int channel, int smooth ) {
1460 mm_log((1,"i_tt_dump_raster_channel(im 0x%x, bit 0x%X, xb %d, yb %d, channel %d)\n",im,bit,xb,yb,channel));
1462 bmap = (char *)bit->bitmap;
1465 for(y=0;y<bit->rows;y++) for(x=0;x<bit->width;x++) {
1466 c=(255*bmap[y*(bit->cols)+x])/4;
1467 i_gpix(im,x+xb,y+yb,&val);
1468 val.channel[channel]=c;
1469 i_ppix(im,x+xb,y+yb,&val);
1472 for(y=0;y<bit->rows;y++) for(x=0;x<bit->width;x++) {
1473 c=( bmap[y*bit->cols+x/8] & (128>>(x%8)) ) ? 255 : 0;
1474 i_gpix(im,x+xb,y+yb,&val);
1475 val.channel[channel]=c;
1476 i_ppix(im,x+xb,y+yb,&val);
1483 =item i_tt_rasterize(handle, bit, cords, points, txt, len, smooth)
1485 interface for generating single channel raster of text (internal)
1487 handle - pointer to font handle
1488 bit - the bitmap that is allocated, rendered into and NOT freed
1489 cords - the bounding box (modified in place)
1490 points - font size to use
1491 txt - string to render
1492 len - length of the string to render
1493 smooth - boolean (True: antialias on, False: antialias is off)
1500 i_tt_rasterize( TT_Fonthandle *handle, TT_Raster_Map *bit, int cords[6], float points, char const* txt, int len, int smooth, int utf8 ) {
1503 TT_Raster_Map small_bit;
1505 /* find or install an instance */
1506 if ( (inst=i_tt_get_instance(handle,points,smooth)) < 0) {
1507 mm_log((1,"i_tt_rasterize: get instance failed\n"));
1511 /* calculate bounding box */
1512 if (!i_tt_bbox_inst( handle, inst, txt, len, cords, utf8 ))
1516 width = cords[2]-cords[0];
1517 height = cords[5]-cords[4];
1519 mm_log((1,"i_tt_rasterize: width=%d, height=%d\n",width, height ));
1521 i_tt_init_raster_map ( bit, width, height, smooth );
1522 i_tt_clear_raster_map( bit );
1523 if ( smooth ) i_tt_init_raster_map( &small_bit, handle->instanceh[inst].imetrics.x_ppem + 32, height, smooth );
1525 if (!i_tt_render_all_glyphs( handle, inst, bit, &small_bit, cords, txt, len,
1528 i_tt_done_raster_map( &small_bit );
1532 /* ascent = ( handle->properties.horizontal->Ascender * handle->instanceh[inst].imetrics.y_ppem ) / handle->properties.header->Units_Per_EM; */
1534 if ( smooth ) i_tt_done_raster_map( &small_bit );
1541 * Exported text rendering interfaces
1546 =item i_tt_cp(handle, im, xb, yb, channel, points, txt, len, smooth, utf8)
1548 Interface to text rendering into a single channel in an image
1550 handle - pointer to font handle
1551 im - image to render text on to
1552 xb, yb - coordinates, left edge and baseline
1553 channel - channel to render into
1554 points - font size to use
1555 txt - string to render
1556 len - length of the string to render
1557 smooth - boolean (True: antialias on, False: antialias is off)
1563 i_tt_cp( TT_Fonthandle *handle, i_img *im, int xb, int yb, int channel, float points, char const* txt, int len, int smooth, int utf8 ) {
1565 int cords[BOUNDING_BOX_COUNT];
1566 int ascent, st_offset;
1570 if (! i_tt_rasterize( handle, &bit, cords, points, txt, len, smooth, utf8 ) ) return 0;
1575 i_tt_dump_raster_map_channel( im, &bit, xb-st_offset , yb-ascent, channel, smooth );
1576 i_tt_done_raster_map( &bit );
1583 =item i_tt_text(handle, im, xb, yb, cl, points, txt, len, smooth, utf8)
1585 Interface to text rendering in a single color onto an image
1587 handle - pointer to font handle
1588 im - image to render text on to
1589 xb, yb - coordinates, left edge and baseline
1590 cl - color to use for text
1591 points - font size to use
1592 txt - string to render
1593 len - length of the string to render
1594 smooth - boolean (True: antialias on, False: antialias is off)
1600 i_tt_text( TT_Fonthandle *handle, i_img *im, int xb, int yb, i_color *cl, float points, char const* txt, int len, int smooth, int utf8) {
1601 int cords[BOUNDING_BOX_COUNT];
1602 int ascent, st_offset;
1607 if (! i_tt_rasterize( handle, &bit, cords, points, txt, len, smooth, utf8 ) ) return 0;
1612 i_tt_dump_raster_map2( im, &bit, xb+st_offset, yb-ascent, cl, smooth );
1613 i_tt_done_raster_map( &bit );
1620 =item i_tt_bbox_inst(handle, inst, txt, len, cords, utf8)
1622 Function to get texts bounding boxes given the instance of the font (internal)
1624 handle - pointer to font handle
1625 inst - font instance
1626 txt - string to measure
1627 len - length of the string to render
1628 cords - the bounding box (modified in place)
1635 i_tt_bbox_inst( TT_Fonthandle *handle, int inst ,const char *txt, int len, int cords[BOUNDING_BOX_COUNT], int utf8 ) {
1636 int i, upm, casc, cdesc, first;
1647 unsigned char *ustr;
1648 ustr=(unsigned char*)txt;
1650 mm_log((1,"i_tt_box_inst(handle 0x%X,inst %d,txt '%.*s', len %d, utf8 %d)\n",handle,inst,len,txt,len, utf8));
1652 upm = handle->properties.header->Units_Per_EM;
1653 gascent = ( handle->properties.horizontal->Ascender * handle->instanceh[inst].imetrics.y_ppem + upm - 1) / upm;
1654 gdescent = ( handle->properties.horizontal->Descender * handle->instanceh[inst].imetrics.y_ppem - upm + 1) / upm;
1659 mm_log((1, "i_tt_box_inst: gascent=%d gdescent=%d\n", gascent, gdescent));
1664 j = i_utf8_advance(&txt, &len);
1666 i_push_error(0, "invalid UTF8 character");
1671 j = (unsigned char)*txt++;
1674 if ( i_tt_get_glyph(handle,inst,j) ) {
1675 TT_Glyph_Metrics *gm = handle->instanceh[inst].gmetrics + TT_HASH(j);
1676 width += gm->advance / 64;
1677 casc = (gm->bbox.yMax+63) / 64;
1678 cdesc = (gm->bbox.yMin-63) / 64;
1680 mm_log((1, "i_tt_box_inst: glyph='%c' casc=%d cdesc=%d\n",
1681 ((j >= ' ' && j <= '~') ? j : '.'), casc, cdesc));
1684 start = gm->bbox.xMin / 64;
1685 ascent = (gm->bbox.yMax+63) / 64;
1686 descent = (gm->bbox.yMin-63) / 64;
1690 /* the right-side bearing - in case the right-side of a
1691 character goes past the right of the advance width,
1692 as is common for italic fonts
1694 rightb = gm->advance - gm->bearingX
1695 - (gm->bbox.xMax - gm->bbox.xMin);
1696 /* fprintf(stderr, "font info last: %d %d %d %d\n",
1697 gm->bbox.xMax, gm->bbox.xMin, gm->advance, rightb); */
1702 ascent = (ascent > casc ? ascent : casc );
1703 descent = (descent < cdesc ? descent : cdesc);
1707 cords[BBOX_NEG_WIDTH]=start;
1708 cords[BBOX_GLOBAL_DESCENT]=gdescent;
1709 cords[BBOX_POS_WIDTH]=width - rightb / 64;
1710 cords[BBOX_GLOBAL_ASCENT]=gascent;
1711 cords[BBOX_DESCENT]=descent;
1712 cords[BBOX_ASCENT]=ascent;
1713 cords[BBOX_ADVANCE_WIDTH] = width;
1715 return BBOX_ADVANCE_WIDTH + 1;
1720 =item i_tt_bbox(handle, points, txt, len, cords, utf8)
1722 Interface to get a strings bounding box
1724 handle - pointer to font handle
1725 points - font size to use
1726 txt - string to render
1727 len - length of the string to render
1728 cords - the bounding box (modified in place)
1734 i_tt_bbox( TT_Fonthandle *handle, float points,char *txt,int len,int cords[6], int utf8) {
1738 mm_log((1,"i_tt_box(handle 0x%X,points %f,txt '%.*s', len %d, utf8 %d)\n",handle,points,len,txt,len, utf8));
1740 if ( (inst=i_tt_get_instance(handle,points,-1)) < 0) {
1741 i_push_errorf(0, "i_tt_get_instance(%g)", points);
1742 mm_log((1,"i_tt_text: get instance failed\n"));
1746 return i_tt_bbox_inst(handle, inst, txt, len, cords, utf8);
1750 =item i_tt_face_name(handle, name_buf, name_buf_size)
1752 Retrieve's the font's postscript name.
1754 This is complicated by the need to handle encodings and so on.
1759 i_tt_face_name(TT_Fonthandle *handle, char *name_buf, size_t name_buf_size) {
1760 TT_Face_Properties props;
1763 TT_UShort platform_id, encoding_id, lang_id, name_id;
1766 int want_index = -1; /* an acceptable but not perfect name */
1771 TT_Get_Face_Properties(handle->face, &props);
1772 name_count = props.num_Names;
1773 for (i = 0; i < name_count; ++i) {
1774 TT_Get_Name_ID(handle->face, i, &platform_id, &encoding_id, &lang_id,
1777 TT_Get_Name_String(handle->face, i, &name, &name_len);
1779 if (platform_id != TT_PLATFORM_APPLE_UNICODE && name_len
1780 && name_id == TT_NAME_ID_PS_NAME) {
1781 int might_want_index = -1;
1782 int might_score = 0;
1783 if ((platform_id == TT_PLATFORM_MACINTOSH && encoding_id == TT_MAC_ID_ROMAN)
1785 (platform_id == TT_PLATFORM_MICROSOFT && encoding_id == TT_MS_LANGID_ENGLISH_UNITED_STATES)) {
1786 /* exactly what we want */
1791 if (platform_id == TT_PLATFORM_MICROSOFT
1792 && (encoding_id & 0xFF) == TT_MS_LANGID_ENGLISH_GENERAL) {
1793 /* any english is good */
1794 might_want_index = i;
1797 /* there might be something in between */
1799 /* anything non-unicode is better than nothing */
1800 might_want_index = i;
1803 if (might_score > score) {
1804 score = might_score;
1805 want_index = might_want_index;
1810 if (want_index != -1) {
1811 TT_Get_Name_String(handle->face, want_index, &name, &name_len);
1813 strncpy(name_buf, name, name_buf_size);
1814 name_buf[name_buf_size-1] = '\0';
1816 return strlen(name) + 1;
1819 i_push_error(0, "no face name present");
1824 void i_tt_dump_names(TT_Fonthandle *handle) {
1825 TT_Face_Properties props;
1828 TT_UShort platform_id, encoding_id, lang_id, name_id;
1832 TT_Get_Face_Properties(handle->face, &props);
1833 name_count = props.num_Names;
1834 for (i = 0; i < name_count; ++i) {
1835 TT_Get_Name_ID(handle->face, i, &platform_id, &encoding_id, &lang_id,
1837 TT_Get_Name_String(handle->face, i, &name, &name_len);
1839 printf("# %d: plat %d enc %d lang %d name %d value ", i, platform_id,
1840 encoding_id, lang_id, name_id);
1841 if (platform_id == TT_PLATFORM_APPLE_UNICODE) {
1842 printf("(unicode)\n");
1845 printf("'%s'\n", name);
1851 i_tt_glyph_name(TT_Fonthandle *handle, unsigned long ch, char *name_buf,
1852 size_t name_buf_size) {
1860 if (!handle->loaded_names) {
1862 mm_log((1, "Loading PS Names"));
1863 handle->load_cond = TT_Load_PS_Names(handle->face, &post);
1864 ++handle->loaded_names;
1867 if (handle->load_cond) {
1868 i_push_errorf(rc, "error loading names (%d)", handle->load_cond);
1872 index = TT_Char_Index(handle->char_map, ch);
1874 i_push_error(0, "no such character");
1878 rc = TT_Get_PS_Name(handle->face, index, &psname);
1881 i_push_error(rc, "error getting name");
1885 strncpy(name_buf, psname, name_buf_size);
1886 name_buf[name_buf_size-1] = '\0';
1888 return strlen(psname) + 1;
1890 mm_log((1, "FTXPOST extension not enabled\n"));
1892 i_push_error(0, "Use of FTXPOST extension disabled");
1898 #endif /* HAVE_LIBTT */
1906 Arnar M. Hrafnkelsson <addi@umich.edu>