18 font.c - implements font handling functions for t1 and truetype fonts
25 fontnum = i_t1_new(path_to_pfb, path_to_afm);
26 i_t1_bbox(fontnum, points, "foo", 3, int cords[6]);
27 rc = i_t1_destroy(fontnum);
31 handle = i_tt_new(path_to_ttf);
32 rc = i_tt_bbox(handle, points, "foo", 3, int cords[6], utf8);
39 font.c implements font creation, rendering, bounding box functions and
42 =head1 FUNCTION REFERENCE
44 Some of these functions are internal.
55 Initialize font rendering libraries if they are avaliable.
61 i_init_fonts(int t1log) {
62 mm_log((1,"Initializing fonts\n"));
77 return(1); /* FIXME: Always true - check the return values of the init_t1 and init_tt functions */
85 static int t1_get_flags(char const *flags);
86 static char *t1_from_utf8(char const *in, int len, int *outlen);
88 static void t1_push_error(void);
90 static int t1_active_fonts = 0;
91 static int t1_initialized = 0;
94 =item i_init_t1(t1log)
96 Initializes the t1lib font rendering engine.
102 i_init_t1(int t1log) {
103 int init_flags = IGNORE_CONFIGFILE|IGNORE_FONTDATABASE;
104 mm_log((1,"init_t1()\n"));
106 if (t1_active_fonts) {
107 mm_log((1, "Cannot re-initialize T1 - active fonts\n"));
111 if (t1_initialized) {
116 init_flags |= LOGFILE;
117 if ((T1_InitLib(init_flags) == NULL)){
118 mm_log((1,"Initialization of t1lib failed\n"));
121 T1_SetLogLevel(T1LOG_DEBUG);
122 i_t1_set_aa(1); /* Default Antialias value */
133 Shuts the t1lib font rendering engine down.
135 This it seems that this function is never used.
148 =item i_t1_new(pfb, afm)
150 Loads the fonts with the given filenames, returns its font id
152 pfb - path to pfb file for font
153 afm - path to afm file for font
159 i_t1_new(char *pfb,char *afm) {
162 mm_log((1,"i_t1_new(pfb %s,afm %s)\n",pfb,(afm?afm:"NULL")));
163 font_id = T1_AddFont(pfb);
165 mm_log((1,"i_t1_new: Failed to load pfb file '%s' - return code %d.\n",pfb,font_id));
170 mm_log((1,"i_t1_new: requesting afm file '%s'.\n",afm));
171 if (T1_SetAfmFileName(font_id,afm)<0) mm_log((1,"i_t1_new: afm loading of '%s' failed.\n",afm));
180 =item i_t1_destroy(font_id)
182 Frees resources for a t1 font with given font id.
184 font_id - number of the font to free
190 i_t1_destroy(int font_id) {
191 mm_log((1,"i_t1_destroy(font_id %d)\n",font_id));
195 return T1_DeleteFont(font_id);
200 =item i_t1_set_aa(st)
202 Sets the antialiasing level of the t1 library.
204 st - 0 = NONE, 1 = LOW, 2 = HIGH.
210 i_t1_set_aa(int st) {
212 unsigned long cst[17];
215 T1_AASetBitsPerPixel( 8 );
216 T1_AASetLevel( T1_AA_NONE );
217 T1_AANSetGrayValues( 0, 255 );
218 mm_log((1,"setting T1 antialias to none\n"));
221 T1_AASetBitsPerPixel( 8 );
222 T1_AASetLevel( T1_AA_LOW );
223 T1_AASetGrayValues( 0,65,127,191,255 );
224 mm_log((1,"setting T1 antialias to low\n"));
227 T1_AASetBitsPerPixel(8);
228 T1_AASetLevel(T1_AA_HIGH);
229 for(i=0;i<17;i++) cst[i]=(i*255)/16;
230 T1_AAHSetGrayValues( cst );
231 mm_log((1,"setting T1 antialias to high\n"));
237 =item i_t1_cp(im, xb, yb, channel, fontnum, points, str, len, align)
239 Interface to text rendering into a single channel in an image
241 im pointer to image structure
242 xb x coordinate of start of string
243 yb y coordinate of start of string ( see align )
244 channel - destination channel
245 fontnum - t1 library font id
246 points - number of points in fontheight
247 str - string to render
249 align - (0 - top of font glyph | 1 - baseline )
255 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) {
259 int mod_flags = t1_get_flags(flags);
261 unsigned int ch_mask_store;
263 if (im == NULL) { mm_log((1,"i_t1_cp: Null image in input\n")); return(0); }
267 char *work = t1_from_utf8(str, len, &worklen);
268 glyph=T1_AASetString( fontnum, work, worklen, 0, mod_flags, points, NULL);
272 glyph=T1_AASetString( fontnum, str, len, 0, mod_flags, points, NULL);
277 mm_log((1,"metrics: ascent: %d descent: %d\n",glyph->metrics.ascent,glyph->metrics.descent));
278 mm_log((1," leftSideBearing: %d rightSideBearing: %d\n",glyph->metrics.leftSideBearing,glyph->metrics.rightSideBearing));
279 mm_log((1," advanceX: %d advanceY: %d\n",glyph->metrics.advanceX,glyph->metrics.advanceY));
280 mm_log((1,"bpp: %d\n",glyph->bpp));
282 xsize=glyph->metrics.rightSideBearing-glyph->metrics.leftSideBearing;
283 ysize=glyph->metrics.ascent-glyph->metrics.descent;
285 mm_log((1,"width: %d height: %d\n",xsize,ysize));
287 ch_mask_store=im->ch_mask;
288 im->ch_mask=1<<channel;
290 if (align==1) { xb+=glyph->metrics.leftSideBearing; yb-=glyph->metrics.ascent; }
292 for(y=0;y<ysize;y++) for(x=0;x<xsize;x++) {
293 val.channel[channel]=glyph->bits[y*xsize+x];
294 i_ppix(im,x+xb,y+yb,&val);
297 im->ch_mask=ch_mask_store;
303 =item i_t1_bbox(handle, fontnum, points, str, len, cords)
305 function to get a strings bounding box given the font id and sizes
307 handle - pointer to font handle
308 fontnum - t1 library font id
309 points - number of points in fontheight
310 str - string to measure
312 cords - the bounding box (modified in place)
318 i_t1_bbox(int fontnum,float points,const char *str,int len,int cords[6], int utf8,char const *flags) {
321 int mod_flags = t1_get_flags(flags);
324 mm_log((1,"i_t1_bbox(fontnum %d,points %.2f,str '%.*s', len %d)\n",fontnum,points,len,str,len));
325 T1_LoadFont(fontnum); /* FIXME: Here a return code is ignored - haw haw haw */
328 char *work = t1_from_utf8(str, len, &worklen);
329 bbox = T1_GetStringBBox(fontnum,work,worklen,0,mod_flags);
333 bbox = T1_GetStringBBox(fontnum,(char *)str,len,0,mod_flags);
335 gbbox = T1_GetFontBBox(fontnum);
336 advance = T1_GetStringWidth(fontnum, (char *)str, len, 0, mod_flags);
338 mm_log((1,"bbox: (%d,%d,%d,%d)\n",
339 (int)(bbox.llx*points/1000),
340 (int)(gbbox.lly*points/1000),
341 (int)(bbox.urx*points/1000),
342 (int)(gbbox.ury*points/1000),
343 (int)(bbox.lly*points/1000),
344 (int)(bbox.ury*points/1000) ));
347 cords[BBOX_NEG_WIDTH]=((float)bbox.llx*points)/1000;
348 cords[BBOX_POS_WIDTH]=((float)bbox.urx*points)/1000;
350 cords[BBOX_GLOBAL_DESCENT]=((float)gbbox.lly*points)/1000;
351 cords[BBOX_GLOBAL_ASCENT]=((float)gbbox.ury*points)/1000;
353 cords[BBOX_DESCENT]=((float)bbox.lly*points)/1000;
354 cords[BBOX_ASCENT]=((float)bbox.ury*points)/1000;
356 cords[BBOX_ADVANCE_WIDTH] = ((float)advance * points)/1000;
357 cords[BBOX_RIGHT_BEARING] =
358 cords[BBOX_ADVANCE_WIDTH] - cords[BBOX_POS_WIDTH];
360 return BBOX_RIGHT_BEARING+1;
365 =item i_t1_text(im, xb, yb, cl, fontnum, points, str, len, align)
367 Interface to text rendering in a single color onto an image
369 im - pointer to image structure
370 xb - x coordinate of start of string
371 yb - y coordinate of start of string ( see align )
372 cl - color to draw the text in
373 fontnum - t1 library font id
374 points - number of points in fontheight
375 str - char pointer to string to render
377 align - (0 - top of font glyph | 1 - baseline )
383 i_t1_text(i_img *im,int xb,int yb,const i_color *cl,int fontnum,float points,const char* str,int len,int align, int utf8, char const *flags) {
385 int xsize,ysize,x,y,ch;
388 int mod_flags = t1_get_flags(flags);
390 if (im == NULL) { mm_log((1,"i_t1_cp: Null image in input\n")); return(0); }
394 char *work = t1_from_utf8(str, len, &worklen);
395 glyph=T1_AASetString( fontnum, work, worklen, 0, mod_flags, points, NULL);
399 /* T1_AASetString() accepts a char * not a const char */
400 glyph=T1_AASetString( fontnum, (char *)str, len, 0, mod_flags, points, NULL);
405 mm_log((1,"metrics: ascent: %d descent: %d\n",glyph->metrics.ascent,glyph->metrics.descent));
406 mm_log((1," leftSideBearing: %d rightSideBearing: %d\n",glyph->metrics.leftSideBearing,glyph->metrics.rightSideBearing));
407 mm_log((1," advanceX: %d advanceY: %d\n",glyph->metrics.advanceX,glyph->metrics.advanceY));
408 mm_log((1,"bpp: %d\n",glyph->bpp));
410 xsize=glyph->metrics.rightSideBearing-glyph->metrics.leftSideBearing;
411 ysize=glyph->metrics.ascent-glyph->metrics.descent;
413 mm_log((1,"width: %d height: %d\n",xsize,ysize));
415 if (align==1) { xb+=glyph->metrics.leftSideBearing; yb-=glyph->metrics.ascent; }
417 for(y=0;y<ysize;y++) for(x=0;x<xsize;x++) {
418 c=glyph->bits[y*xsize+x];
420 i_gpix(im,x+xb,y+yb,&val);
421 for(ch=0;ch<im->channels;ch++) val.channel[ch]=(c*cl->channel[ch]+i*val.channel[ch])/255;
422 i_ppix(im,x+xb,y+yb,&val);
428 =item t1_get_flags(flags)
430 Processes the characters in I<flags> to create a mod_flags value used
431 by some T1Lib functions.
436 t1_get_flags(char const *flags) {
437 int mod_flags = T1_KERNING;
441 case 'u': case 'U': mod_flags |= T1_UNDERLINE; break;
442 case 'o': case 'O': mod_flags |= T1_OVERLINE; break;
443 case 's': case 'S': mod_flags |= T1_OVERSTRIKE; break;
444 /* ignore anything we don't recognize */
452 =item t1_from_utf8(char const *in, int len, int *outlen)
454 Produces an unencoded version of I<in> by dropping any Unicode
457 Returns a newly allocated buffer which should be freed with myfree().
458 Sets *outlen to the number of bytes used in the output string.
464 t1_from_utf8(char const *in, int len, int *outlen) {
465 /* at this point len is from a perl SV, so can't approach MAXINT */
466 char *out = mymalloc(len+1); /* checked 5Nov05 tonyc */
471 c = i_utf8_advance(&in, &len);
474 i_push_error(0, "invalid UTF8 character");
477 /* yeah, just drop them */
489 =item i_t1_has_chars(font_num, text, len, utf8, out)
491 Check if the given characters are defined by the font. Note that len
492 is the number of bytes, not the number of characters (when utf8 is
495 out[char index] will be true if the character exists.
497 Accepts UTF-8, but since T1 can only have 256 characters, any chars
498 with values over 255 will simply be returned as false.
500 Returns the number of characters that were checked.
506 i_t1_has_chars(int font_num, const char *text, int len, int utf8,
510 mm_log((1, "i_t1_has_chars(font_num %d, text %p, len %d, utf8 %d)\n",
511 font_num, text, len, utf8));
514 if (T1_LoadFont(font_num)) {
522 c = i_utf8_advance(&text, &len);
524 i_push_error(0, "invalid UTF8 character");
529 c = (unsigned char)*text++;
534 /* limit of 256 characters for T1 */
538 char const * name = T1_GetCharName(font_num, (unsigned char)c);
541 *out++ = strcmp(name, ".notdef") != 0;
544 mm_log((2, " No name found for character %lx\n", c));
555 =item i_t1_face_name(font_num, name_buf, name_buf_size)
557 Copies the face name of the given C<font_num> to C<name_buf>. Returns
558 the number of characters required to store the name (which can be
559 larger than C<name_buf_size>, including the space required to store
560 the terminating NUL).
562 If name_buf is too small (as specified by name_buf_size) then the name
563 will be truncated. name_buf will always be NUL termintaed.
569 i_t1_face_name(int font_num, char *name_buf, size_t name_buf_size) {
573 if (T1_LoadFont(font_num)) {
577 name = T1_GetFontName(font_num);
580 strncpy(name_buf, name, name_buf_size);
581 name_buf[name_buf_size-1] = '\0';
582 return strlen(name) + 1;
591 i_t1_glyph_name(int font_num, unsigned long ch, char *name_buf,
592 size_t name_buf_size) {
599 if (T1_LoadFont(font_num)) {
603 name = T1_GetCharName(font_num, (unsigned char)ch);
605 if (strcmp(name, ".notdef")) {
606 strncpy(name_buf, name, name_buf_size);
607 name_buf[name_buf_size-1] = '\0';
608 return strlen(name) + 1;
621 t1_push_error(void) {
624 i_push_error(0, "No error");
627 #ifdef T1ERR_SCAN_FONT_FORMAT
628 case T1ERR_SCAN_FONT_FORMAT:
629 i_push_error(T1ERR_SCAN_FONT_FORMAT, "SCAN_FONT_FORMAT");
633 #ifdef T1ERR_SCAN_FILE_OPEN_ERR
634 case T1ERR_SCAN_FILE_OPEN_ERR:
635 i_push_error(T1ERR_SCAN_FILE_OPEN_ERR, "SCAN_FILE_OPEN_ERR");
639 #ifdef T1ERR_SCAN_OUT_OF_MEMORY
640 case T1ERR_SCAN_OUT_OF_MEMORY:
641 i_push_error(T1ERR_SCAN_OUT_OF_MEMORY, "SCAN_OUT_OF_MEMORY");
645 #ifdef T1ERR_SCAN_ERROR
646 case T1ERR_SCAN_ERROR:
647 i_push_error(T1ERR_SCAN_ERROR, "SCAN_ERROR");
651 #ifdef T1ERR_SCAN_FILE_EOF
652 case T1ERR_SCAN_FILE_EOF:
653 i_push_error(T1ERR_SCAN_FILE_EOF, "SCAN_FILE_EOF");
657 #ifdef T1ERR_PATH_ERROR
658 case T1ERR_PATH_ERROR:
659 i_push_error(T1ERR_PATH_ERROR, "PATH_ERROR");
663 #ifdef T1ERR_PARSE_ERROR
664 case T1ERR_PARSE_ERROR:
665 i_push_error(T1ERR_PARSE_ERROR, "PARSE_ERROR");
669 #ifdef T1ERR_TYPE1_ABORT
670 case T1ERR_TYPE1_ABORT:
671 i_push_error(T1ERR_TYPE1_ABORT, "TYPE1_ABORT");
675 #ifdef T1ERR_INVALID_FONTID
676 case T1ERR_INVALID_FONTID:
677 i_push_error(T1ERR_INVALID_FONTID, "INVALID_FONTID");
681 #ifdef T1ERR_INVALID_PARAMETER
682 case T1ERR_INVALID_PARAMETER:
683 i_push_error(T1ERR_INVALID_PARAMETER, "INVALID_PARAMETER");
687 #ifdef T1ERR_OP_NOT_PERMITTED
688 case T1ERR_OP_NOT_PERMITTED:
689 i_push_error(T1ERR_OP_NOT_PERMITTED, "OP_NOT_PERMITTED");
693 #ifdef T1ERR_ALLOC_MEM
694 case T1ERR_ALLOC_MEM:
695 i_push_error(T1ERR_ALLOC_MEM, "ALLOC_MEM");
699 #ifdef T1ERR_FILE_OPEN_ERR
700 case T1ERR_FILE_OPEN_ERR:
701 i_push_error(T1ERR_FILE_OPEN_ERR, "FILE_OPEN_ERR");
705 #ifdef T1ERR_UNSPECIFIED
706 case T1ERR_UNSPECIFIED:
707 i_push_error(T1ERR_UNSPECIFIED, "UNSPECIFIED");
711 #ifdef T1ERR_NO_AFM_DATA
712 case T1ERR_NO_AFM_DATA:
713 i_push_error(T1ERR_NO_AFM_DATA, "NO_AFM_DATA");
719 i_push_error(T1ERR_X11, "X11");
723 #ifdef T1ERR_COMPOSITE_CHAR
724 case T1ERR_COMPOSITE_CHAR:
725 i_push_error(T1ERR_COMPOSITE_CHAR, "COMPOSITE_CHAR");
730 i_push_errorf(T1_errno, "unknown error %d", (int)T1_errno);
734 #endif /* HAVE_LIBT1 */
737 /* Truetype font support */
740 /* These are enabled by default when configuring Freetype 1.x
741 I haven't a clue how to reliably detect it at compile time.
743 We need a compilation probe in Makefile.PL
748 #include <freetype.h>
756 #include <ftxerr18.h>
759 /* some versions of FT1.x don't seem to define this - it's font defined
760 so it won't change */
761 #ifndef TT_MS_LANGID_ENGLISH_GENERAL
762 #define TT_MS_LANGID_ENGLISH_GENERAL 0x0409
765 /* convert a code point into an index in the glyph cache */
766 #define TT_HASH(x) ((x) & 0xFF)
768 typedef struct i_glyph_entry_ {
773 #define TT_NOCHAR (~0UL)
775 struct TT_Instancehandle_ {
776 TT_Instance instance;
777 TT_Instance_Metrics imetrics;
778 TT_Glyph_Metrics gmetrics[256];
779 i_tt_glyph_entry glyphs[256];
785 typedef struct TT_Instancehandle_ TT_Instancehandle;
787 struct TT_Fonthandle_ {
789 TT_Face_Properties properties;
790 TT_Instancehandle instanceh[TT_CHC];
800 #define USTRCT(x) ((x).z)
801 #define TT_VALID( handle ) ( ( handle ).z != NULL )
803 static void i_tt_push_error(TT_Error rc);
807 static int i_tt_get_instance( TT_Fonthandle *handle, int points, int smooth );
808 static void i_tt_init_raster_map( TT_Raster_Map* bit, int width, int height, int smooth );
809 static void i_tt_done_raster_map( TT_Raster_Map *bit );
810 static void i_tt_clear_raster_map( TT_Raster_Map* bit );
811 static void i_tt_blit_or( TT_Raster_Map *dst, TT_Raster_Map *src,int x_off, int y_off );
812 static int i_tt_get_glyph( TT_Fonthandle *handle, int inst, unsigned long j );
814 i_tt_render_glyph( TT_Glyph glyph, TT_Glyph_Metrics* gmetrics,
815 TT_Raster_Map *bit, TT_Raster_Map *small_bit,
816 int x_off, int y_off, int smooth );
818 i_tt_render_all_glyphs( TT_Fonthandle *handle, int inst, TT_Raster_Map *bit,
819 TT_Raster_Map *small_bit, int cords[6],
820 char const* txt, int len, int smooth, int utf8 );
821 static void i_tt_dump_raster_map2( i_img* im, TT_Raster_Map* bit, int xb, int yb, const i_color *cl, int smooth );
822 static void i_tt_dump_raster_map_channel( i_img* im, TT_Raster_Map* bit, int xb, int yb, int channel, int smooth );
824 i_tt_rasterize( TT_Fonthandle *handle, TT_Raster_Map *bit, int cords[6],
825 float points, char const* txt, int len, int smooth, int utf8 );
826 static undef_int i_tt_bbox_inst( TT_Fonthandle *handle, int inst ,const char *txt, int len, int cords[6], int utf8 );
829 /* static globals needed */
831 static TT_Engine engine;
832 static int LTT_dpi = 72; /* FIXME: this ought to be a part of the call interface */
833 static int LTT_hinted = 1; /* FIXME: this too */
844 Initializes the freetype font rendering engine
852 mm_log((1,"init_tt()\n"));
853 error = TT_Init_FreeType( &engine );
855 mm_log((1,"Initialization of freetype failed, code = 0x%x\n",error));
860 error = TT_Init_Post_Extension( engine );
862 mm_log((1, "Initialization of Post extension failed = 0x%x\n", error));
872 =item i_tt_get_instance(handle, points, smooth)
874 Finds a points+smooth instance or if one doesn't exist in the cache
875 allocates room and returns its cache entry
877 fontname - path to the font to load
878 handle - handle to the font.
879 points - points of the requested font
880 smooth - boolean (True: antialias on, False: antialias is off)
887 i_tt_get_instance( TT_Fonthandle *handle, int points, int smooth ) {
891 mm_log((1,"i_tt_get_instance(handle 0x%X, points %d, smooth %d)\n",
892 handle,points,smooth));
894 if (smooth == -1) { /* Smooth doesn't matter for this search */
895 for(i=0;i<TT_CHC;i++) {
896 if (handle->instanceh[i].ptsize==points) {
897 mm_log((1,"i_tt_get_instance: in cache - (non selective smoothing search) returning %d\n",i));
901 smooth=1; /* We will be adding a font - add it as smooth then */
902 } else { /* Smooth doesn't matter for this search */
903 for(i=0;i<TT_CHC;i++) {
904 if (handle->instanceh[i].ptsize == points
905 && handle->instanceh[i].smooth == smooth) {
906 mm_log((1,"i_tt_get_instance: in cache returning %d\n",i));
912 /* Found the instance in the cache - return the cache index */
914 for(idx=0;idx<TT_CHC;idx++) {
915 if (!(handle->instanceh[idx].order)) break; /* find the lru item */
918 mm_log((1,"i_tt_get_instance: lru item is %d\n",idx));
919 mm_log((1,"i_tt_get_instance: lru pointer 0x%X\n",
920 USTRCT(handle->instanceh[idx].instance) ));
922 if ( USTRCT(handle->instanceh[idx].instance) ) {
923 mm_log((1,"i_tt_get_instance: freeing lru item from cache %d\n",idx));
925 /* Free cached glyphs */
927 if ( USTRCT(handle->instanceh[idx].glyphs[i].glyph) )
928 TT_Done_Glyph( handle->instanceh[idx].glyphs[i].glyph );
931 handle->instanceh[idx].glyphs[i].ch = TT_NOCHAR;
932 USTRCT(handle->instanceh[idx].glyphs[i].glyph)=NULL;
935 /* Free instance if needed */
936 TT_Done_Instance( handle->instanceh[idx].instance );
939 /* create and initialize instance */
940 /* FIXME: probably a memory leak on fail */
942 (void) (( error = TT_New_Instance( handle->face, &handle->instanceh[idx].instance ) ) ||
943 ( error = TT_Set_Instance_Resolutions( handle->instanceh[idx].instance, LTT_dpi, LTT_dpi ) ) ||
944 ( error = TT_Set_Instance_CharSize( handle->instanceh[idx].instance, points*64 ) ) );
947 mm_log((1, "Could not create and initialize instance: error 0x%x.\n",error ));
951 /* Now that the instance should the inplace we need to lower all of the
952 ru counts and put `this' one with the highest entry */
954 for(i=0;i<TT_CHC;i++) handle->instanceh[i].order--;
956 handle->instanceh[idx].order=TT_CHC-1;
957 handle->instanceh[idx].ptsize=points;
958 handle->instanceh[idx].smooth=smooth;
959 TT_Get_Instance_Metrics( handle->instanceh[idx].instance, &(handle->instanceh[idx].imetrics) );
961 /* Zero the memory for the glyph storage so they are not thought as
962 cached if they haven't been cached since this new font was loaded */
965 handle->instanceh[idx].glyphs[i].ch = TT_NOCHAR;
966 USTRCT(handle->instanceh[idx].glyphs[i].glyph)=NULL;
974 =item i_tt_new(fontname)
976 Creates a new font handle object, finds a character map and initialise the
977 the font handle's cache
979 fontname - path to the font to load
985 i_tt_new(const char *fontname) {
987 TT_Fonthandle *handle;
989 unsigned short platform,encoding;
993 mm_log((1,"i_tt_new(fontname '%s')\n",fontname));
995 /* allocate memory for the structure */
997 handle = mymalloc( sizeof(TT_Fonthandle) ); /* checked 5Nov05 tonyc */
999 /* load the typeface */
1000 error = TT_Open_Face( engine, fontname, &handle->face );
1002 if ( error == TT_Err_Could_Not_Open_File ) {
1003 mm_log((1, "Could not find/open %s.\n", fontname ));
1006 mm_log((1, "Error while opening %s, error code = 0x%x.\n",fontname,
1009 i_tt_push_error(error);
1013 TT_Get_Face_Properties( handle->face, &(handle->properties) );
1015 /* First, look for a Unicode charmap */
1016 n = handle->properties.num_CharMaps;
1017 USTRCT( handle->char_map )=NULL; /* Invalidate character map */
1019 for ( i = 0; i < n; i++ ) {
1020 TT_Get_CharMap_ID( handle->face, i, &platform, &encoding );
1021 if ( (platform == 3 && encoding == 1 )
1022 || (platform == 0 && encoding == 0 ) ) {
1023 mm_log((2,"i_tt_new - found char map platform %u encoding %u\n",
1024 platform, encoding));
1025 TT_Get_CharMap( handle->face, i, &(handle->char_map) );
1029 if (!USTRCT(handle->char_map) && n != 0) {
1030 /* just use the first one */
1031 TT_Get_CharMap( handle->face, 0, &(handle->char_map));
1034 /* Zero the pointsizes - and ordering */
1036 for(i=0;i<TT_CHC;i++) {
1037 USTRCT(handle->instanceh[i].instance)=NULL;
1038 handle->instanceh[i].order=i;
1039 handle->instanceh[i].ptsize=0;
1040 handle->instanceh[i].smooth=-1;
1044 handle->loaded_names = 0;
1047 mm_log((1,"i_tt_new <- 0x%X\n",handle));
1054 * raster map management
1058 =item i_tt_init_raster_map(bit, width, height, smooth)
1060 Allocates internal memory for the bitmap as needed by the parameters (internal)
1062 bit - bitmap to allocate into
1063 width - width of the bitmap
1064 height - height of the bitmap
1065 smooth - boolean (True: antialias on, False: antialias is off)
1072 i_tt_init_raster_map( TT_Raster_Map* bit, int width, int height, int smooth ) {
1074 mm_log((1,"i_tt_init_raster_map( bit 08x%08X, width %d, height %d, smooth %d)\n", bit, width, height, smooth));
1077 bit->width = ( width + 3 ) & -4;
1078 bit->flow = TT_Flow_Down;
1081 bit->cols = bit->width;
1082 bit->size = bit->rows * bit->width;
1084 bit->cols = ( bit->width + 7 ) / 8; /* convert to # of bytes */
1085 bit->size = bit->rows * bit->cols; /* number of bytes in buffer */
1088 /* rows can be 0 for some glyphs, for example ' ' */
1089 if (bit->rows && bit->size / bit->rows != bit->cols) {
1090 m_fatal(0, "Integer overflow calculating bitmap size (%d, %d)\n",
1091 bit->width, bit->rows);
1094 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 ));
1096 bit->bitmap = (void *) mymalloc( bit->size ); /* checked 6Nov05 tonyc */
1097 if ( !bit->bitmap ) m_fatal(0,"Not enough memory to allocate bitmap (%d)!\n",bit->size );
1102 =item i_tt_clear_raster_map(bit)
1104 Frees the bitmap data and sets pointer to NULL (internal)
1106 bit - bitmap to free
1113 i_tt_done_raster_map( TT_Raster_Map *bit ) {
1114 myfree( bit->bitmap );
1120 =item i_tt_clear_raster_map(bit)
1122 Clears the specified bitmap (internal)
1124 bit - bitmap to zero
1132 i_tt_clear_raster_map( TT_Raster_Map* bit ) {
1133 memset( bit->bitmap, 0, bit->size );
1138 =item i_tt_blit_or(dst, src, x_off, y_off)
1140 function that blits one raster map into another (internal)
1142 dst - destination bitmap
1144 x_off - x offset into the destination bitmap
1145 y_off - y offset into the destination bitmap
1152 i_tt_blit_or( TT_Raster_Map *dst, TT_Raster_Map *src,int x_off, int y_off ) {
1157 x1 = x_off < 0 ? -x_off : 0;
1158 y1 = y_off < 0 ? -y_off : 0;
1160 x2 = (int)dst->cols - x_off;
1161 if ( x2 > src->cols ) x2 = src->cols;
1163 y2 = (int)dst->rows - y_off;
1164 if ( y2 > src->rows ) y2 = src->rows;
1166 if ( x1 >= x2 ) return;
1168 /* do the real work now */
1170 for ( y = y1; y < y2; ++y ) {
1171 s = ( (char*)src->bitmap ) + y * src->cols + x1;
1172 d = ( (char*)dst->bitmap ) + ( y + y_off ) * dst->cols + x1 + x_off;
1174 for ( x = x1; x < x2; ++x ) {
1183 /* useful for debugging */
1186 static void dump_raster_map(FILE *out, TT_Raster_Map *bit ) {
1188 fprintf(out, "cols %d rows %d flow %d\n", bit->cols, bit->rows, bit->flow);
1189 for (y = 0; y < bit->rows; ++y) {
1190 fprintf(out, "%2d:", y);
1191 for (x = 0; x < bit->cols; ++x) {
1192 if ((x & 7) == 0 && x) putc(' ', out);
1193 fprintf(out, "%02x", ((unsigned char *)bit->bitmap)[y*bit->cols+x]);
1202 =item i_tt_get_glyph(handle, inst, j)
1204 Function to see if a glyph exists and if so cache it (internal)
1206 handle - pointer to font handle
1207 inst - font instance
1208 j - charcode of glyph
1215 i_tt_get_glyph( TT_Fonthandle *handle, int inst, unsigned long j) {
1216 unsigned short load_flags, code;
1219 mm_log((1, "i_tt_get_glyph(handle 0x%X, inst %d, j %d (%c))\n",
1220 handle,inst,j, ((j >= ' ' && j <= '~') ? j : '.')));
1222 /*mm_log((1, "handle->instanceh[inst].glyphs[j]=0x%08X\n",handle->instanceh[inst].glyphs[j] ));*/
1224 if ( TT_VALID(handle->instanceh[inst].glyphs[TT_HASH(j)].glyph)
1225 && handle->instanceh[inst].glyphs[TT_HASH(j)].ch == j) {
1226 mm_log((1,"i_tt_get_glyph: %d in cache\n",j));
1230 if ( TT_VALID(handle->instanceh[inst].glyphs[TT_HASH(j)].glyph) ) {
1231 /* clean up the entry */
1232 TT_Done_Glyph( handle->instanceh[inst].glyphs[TT_HASH(j)].glyph );
1233 USTRCT( handle->instanceh[inst].glyphs[TT_HASH(j)].glyph ) = NULL;
1234 handle->instanceh[inst].glyphs[TT_HASH(j)].ch = TT_NOCHAR;
1237 /* Ok - it wasn't cached - try to get it in */
1238 load_flags = TTLOAD_SCALE_GLYPH;
1239 if ( LTT_hinted ) load_flags |= TTLOAD_HINT_GLYPH;
1241 if ( !TT_VALID(handle->char_map) ) {
1242 code = (j - ' ' + 1) < 0 ? 0 : (j - ' ' + 1);
1243 if ( code >= handle->properties.num_Glyphs ) code = 0;
1244 } else code = TT_Char_Index( handle->char_map, j );
1246 if ( (error = TT_New_Glyph( handle->face, &handle->instanceh[inst].glyphs[TT_HASH(j)].glyph)) ) {
1247 mm_log((1, "Cannot allocate and load glyph: error 0x%x.\n", error ));
1248 i_push_error(error, "TT_New_Glyph()");
1251 if ( (error = TT_Load_Glyph( handle->instanceh[inst].instance, handle->instanceh[inst].glyphs[TT_HASH(j)].glyph, code, load_flags)) ) {
1252 mm_log((1, "Cannot allocate and load glyph: error 0x%x.\n", error ));
1254 TT_Done_Glyph( handle->instanceh[inst].glyphs[TT_HASH(j)].glyph );
1255 USTRCT( handle->instanceh[inst].glyphs[TT_HASH(j)].glyph ) = NULL;
1256 i_push_error(error, "TT_Load_Glyph()");
1260 /* At this point the glyph should be allocated and loaded */
1261 handle->instanceh[inst].glyphs[TT_HASH(j)].ch = j;
1263 /* Next get the glyph metrics */
1264 error = TT_Get_Glyph_Metrics( handle->instanceh[inst].glyphs[TT_HASH(j)].glyph,
1265 &handle->instanceh[inst].gmetrics[TT_HASH(j)] );
1267 mm_log((1, "TT_Get_Glyph_Metrics: error 0x%x.\n", error ));
1268 TT_Done_Glyph( handle->instanceh[inst].glyphs[TT_HASH(j)].glyph );
1269 USTRCT( handle->instanceh[inst].glyphs[TT_HASH(j)].glyph ) = NULL;
1270 handle->instanceh[inst].glyphs[TT_HASH(j)].ch = TT_NOCHAR;
1271 i_push_error(error, "TT_Get_Glyph_Metrics()");
1279 =item i_tt_has_chars(handle, text, len, utf8, out)
1281 Check if the given characters are defined by the font. Note that len
1282 is the number of bytes, not the number of characters (when utf8 is
1285 Returns the number of characters that were checked.
1291 i_tt_has_chars(TT_Fonthandle *handle, char const *text, int len, int utf8,
1294 mm_log((1, "i_tt_has_chars(handle %p, text %p, len %d, utf8 %d)\n",
1295 handle, text, len, utf8));
1301 c = i_utf8_advance(&text, &len);
1303 i_push_error(0, "invalid UTF8 character");
1308 c = (unsigned char)*text++;
1312 if (TT_VALID(handle->char_map)) {
1313 index = TT_Char_Index(handle->char_map, c);
1316 index = (c - ' ' + 1) < 0 ? 0 : (c - ' ' + 1);
1317 if (index >= handle->properties.num_Glyphs)
1320 *out++ = index != 0;
1328 =item i_tt_destroy(handle)
1330 Clears the data taken by a font including all cached data such as
1333 handle - pointer to font handle
1339 i_tt_destroy( TT_Fonthandle *handle) {
1340 TT_Close_Face( handle->face );
1343 /* FIXME: Should these be freed automatically by the library?
1345 TT_Done_Instance( instance );
1347 i_tt_done_glyphs( void ) {
1350 if ( !glyphs ) return;
1352 for ( i = 0; i < 256; ++i ) TT_Done_Glyph( glyphs[i] );
1362 * FreeType Rendering functions
1367 =item i_tt_render_glyph(handle, gmetrics, bit, smallbit, x_off, y_off, smooth)
1369 Renders a single glyph into the bit rastermap (internal)
1371 handle - pointer to font handle
1372 gmetrics - the metrics for the glyph to be rendered
1373 bit - large bitmap that is the destination for the text
1374 smallbit - small bitmap that is used only if smooth is true
1375 x_off - x offset of glyph
1376 y_off - y offset of glyph
1377 smooth - boolean (True: antialias on, False: antialias is off)
1384 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 ) {
1386 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",
1387 USTRCT(glyph), gmetrics, bit, small_bit, x_off,y_off,smooth));
1389 if ( !smooth ) TT_Get_Glyph_Bitmap( glyph, bit, x_off * 64, y_off * 64);
1391 TT_F26Dot6 xmin, ymin, xmax, ymax;
1393 xmin = gmetrics->bbox.xMin & -64;
1394 ymin = gmetrics->bbox.yMin & -64;
1395 xmax = (gmetrics->bbox.xMax + 63) & -64;
1396 ymax = (gmetrics->bbox.yMax + 63) & -64;
1398 i_tt_clear_raster_map( small_bit );
1399 TT_Get_Glyph_Pixmap( glyph, small_bit, -xmin, -ymin );
1400 i_tt_blit_or( bit, small_bit, xmin/64 + x_off, -ymin/64 - y_off );
1406 =item i_tt_render_all_glyphs(handle, inst, bit, small_bit, cords, txt, len, smooth)
1408 calls i_tt_render_glyph to render each glyph into the bit rastermap (internal)
1410 handle - pointer to font handle
1411 inst - font instance
1412 bit - large bitmap that is the destination for the text
1413 smallbit - small bitmap that is used only if smooth is true
1414 txt - string to render
1415 len - length of the string to render
1416 smooth - boolean (True: antialias on, False: antialias is off)
1423 i_tt_render_all_glyphs( TT_Fonthandle *handle, int inst, TT_Raster_Map *bit,
1424 TT_Raster_Map *small_bit, int cords[6],
1425 char const* txt, int len, int smooth, int utf8 ) {
1429 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",
1430 handle, inst, bit, small_bit, len, txt, len, smooth, utf8));
1433 y=-( handle->properties.horizontal->Descender * handle->instanceh[inst].imetrics.y_ppem )/(handle->properties.header->Units_Per_EM);
1436 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 */
1441 j = i_utf8_advance(&txt, &len);
1443 i_push_error(0, "invalid UTF8 character");
1448 j = (unsigned char)*txt++;
1451 if ( !i_tt_get_glyph(handle,inst,j) )
1453 i_tt_render_glyph( handle->instanceh[inst].glyphs[TT_HASH(j)].glyph,
1454 &handle->instanceh[inst].gmetrics[TT_HASH(j)], bit,
1455 small_bit, x, y, smooth );
1456 x += handle->instanceh[inst].gmetrics[TT_HASH(j)].advance / 64;
1464 * Functions to render rasters (single channel images) onto images
1468 =item i_tt_dump_raster_map2(im, bit, xb, yb, cl, smooth)
1470 Function to dump a raster onto an image in color used by i_tt_text() (internal).
1472 im - image to dump raster on
1473 bit - bitmap that contains the text to be dumped to im
1474 xb, yb - coordinates, left edge and baseline
1475 cl - color to use for text
1476 smooth - boolean (True: antialias on, False: antialias is off)
1483 i_tt_dump_raster_map2( i_img* im, TT_Raster_Map* bit, int xb, int yb, const i_color *cl, int smooth ) {
1487 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));
1489 bmap = (char *)bit->bitmap;
1493 for(y=0;y<bit->rows;y++) for(x=0;x<bit->width;x++) {
1494 c=(255*bmap[y*(bit->cols)+x])/4;
1496 i_gpix(im,x+xb,y+yb,&val);
1497 for(ch=0;ch<im->channels;ch++) val.channel[ch]=(c*cl->channel[ch]+i*val.channel[ch])/255;
1498 i_ppix(im,x+xb,y+yb,&val);
1503 for(y=0;y<bit->rows;y++) for(x=0;x<bit->width;x++) {
1504 c=( bmap[y*bit->cols+x/8] & (128>>(x%8)) ) ? 255 : 0;
1506 i_gpix(im,x+xb,y+yb,&val);
1507 for(ch=0;ch<im->channels;ch++) val.channel[ch]=(c*cl->channel[ch]+i*val.channel[ch])/255;
1508 i_ppix(im,x+xb,y+yb,&val);
1516 =item i_tt_dump_raster_map_channel(im, bit, xb, yb, channel, smooth)
1518 Function to dump a raster onto a single channel image in color (internal)
1520 im - image to dump raster on
1521 bit - bitmap that contains the text to be dumped to im
1522 xb, yb - coordinates, left edge and baseline
1523 channel - channel to copy to
1524 smooth - boolean (True: antialias on, False: antialias is off)
1531 i_tt_dump_raster_map_channel( i_img* im, TT_Raster_Map* bit, int xb, int yb, int channel, int smooth ) {
1536 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));
1538 bmap = (char *)bit->bitmap;
1541 for(y=0;y<bit->rows;y++) for(x=0;x<bit->width;x++) {
1542 c=(255*bmap[y*(bit->cols)+x])/4;
1543 i_gpix(im,x+xb,y+yb,&val);
1544 val.channel[channel]=c;
1545 i_ppix(im,x+xb,y+yb,&val);
1548 for(y=0;y<bit->rows;y++) for(x=0;x<bit->width;x++) {
1549 c=( bmap[y*bit->cols+x/8] & (128>>(x%8)) ) ? 255 : 0;
1550 i_gpix(im,x+xb,y+yb,&val);
1551 val.channel[channel]=c;
1552 i_ppix(im,x+xb,y+yb,&val);
1559 =item i_tt_rasterize(handle, bit, cords, points, txt, len, smooth)
1561 interface for generating single channel raster of text (internal)
1563 handle - pointer to font handle
1564 bit - the bitmap that is allocated, rendered into and NOT freed
1565 cords - the bounding box (modified in place)
1566 points - font size to use
1567 txt - string to render
1568 len - length of the string to render
1569 smooth - boolean (True: antialias on, False: antialias is off)
1576 i_tt_rasterize( TT_Fonthandle *handle, TT_Raster_Map *bit, int cords[6], float points, char const* txt, int len, int smooth, int utf8 ) {
1579 TT_Raster_Map small_bit;
1581 /* find or install an instance */
1582 if ( (inst=i_tt_get_instance(handle,points,smooth)) < 0) {
1583 mm_log((1,"i_tt_rasterize: get instance failed\n"));
1587 /* calculate bounding box */
1588 if (!i_tt_bbox_inst( handle, inst, txt, len, cords, utf8 ))
1592 width = cords[2]-cords[0];
1593 height = cords[5]-cords[4];
1595 mm_log((1,"i_tt_rasterize: width=%d, height=%d\n",width, height ));
1597 i_tt_init_raster_map ( bit, width, height, smooth );
1598 i_tt_clear_raster_map( bit );
1599 if ( smooth ) i_tt_init_raster_map( &small_bit, handle->instanceh[inst].imetrics.x_ppem + 32, height, smooth );
1601 if (!i_tt_render_all_glyphs( handle, inst, bit, &small_bit, cords, txt, len,
1604 i_tt_done_raster_map( &small_bit );
1608 if ( smooth ) i_tt_done_raster_map( &small_bit );
1615 * Exported text rendering interfaces
1620 =item i_tt_cp(handle, im, xb, yb, channel, points, txt, len, smooth, utf8)
1622 Interface to text rendering into a single channel in an image
1624 handle - pointer to font handle
1625 im - image to render text on to
1626 xb, yb - coordinates, left edge and baseline
1627 channel - channel to render into
1628 points - font size to use
1629 txt - string to render
1630 len - length of the string to render
1631 smooth - boolean (True: antialias on, False: antialias is off)
1637 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, int align ) {
1639 int cords[BOUNDING_BOX_COUNT];
1640 int ascent, st_offset, y;
1644 if (! i_tt_rasterize( handle, &bit, cords, points, txt, len, smooth, utf8 ) ) return 0;
1646 ascent=cords[BBOX_ASCENT];
1647 st_offset=cords[BBOX_NEG_WIDTH];
1648 y = align ? yb-ascent : yb;
1650 i_tt_dump_raster_map_channel( im, &bit, xb-st_offset , y, channel, smooth );
1651 i_tt_done_raster_map( &bit );
1658 =item i_tt_text(handle, im, xb, yb, cl, points, txt, len, smooth, utf8)
1660 Interface to text rendering in a single color onto an image
1662 handle - pointer to font handle
1663 im - image to render text on to
1664 xb, yb - coordinates, left edge and baseline
1665 cl - color to use for text
1666 points - font size to use
1667 txt - string to render
1668 len - length of the string to render
1669 smooth - boolean (True: antialias on, False: antialias is off)
1675 i_tt_text( TT_Fonthandle *handle, i_img *im, int xb, int yb, const i_color *cl, float points, char const* txt, int len, int smooth, int utf8, int align) {
1676 int cords[BOUNDING_BOX_COUNT];
1677 int ascent, st_offset, y;
1682 if (! i_tt_rasterize( handle, &bit, cords, points, txt, len, smooth, utf8 ) ) return 0;
1684 ascent=cords[BBOX_ASCENT];
1685 st_offset=cords[BBOX_NEG_WIDTH];
1686 y = align ? yb-ascent : yb;
1688 i_tt_dump_raster_map2( im, &bit, xb+st_offset, y, cl, smooth );
1689 i_tt_done_raster_map( &bit );
1696 =item i_tt_bbox_inst(handle, inst, txt, len, cords, utf8)
1698 Function to get texts bounding boxes given the instance of the font (internal)
1700 handle - pointer to font handle
1701 inst - font instance
1702 txt - string to measure
1703 len - length of the string to render
1704 cords - the bounding box (modified in place)
1711 i_tt_bbox_inst( TT_Fonthandle *handle, int inst ,const char *txt, int len, int cords[BOUNDING_BOX_COUNT], int utf8 ) {
1712 int upm, casc, cdesc, first;
1723 unsigned char *ustr;
1724 ustr=(unsigned char*)txt;
1726 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));
1728 upm = handle->properties.header->Units_Per_EM;
1729 gascent = ( handle->properties.horizontal->Ascender * handle->instanceh[inst].imetrics.y_ppem + upm - 1) / upm;
1730 gdescent = ( handle->properties.horizontal->Descender * handle->instanceh[inst].imetrics.y_ppem - upm + 1) / upm;
1735 mm_log((1, "i_tt_box_inst: gascent=%d gdescent=%d\n", gascent, gdescent));
1740 j = i_utf8_advance(&txt, &len);
1742 i_push_error(0, "invalid UTF8 character");
1747 j = (unsigned char)*txt++;
1750 if ( i_tt_get_glyph(handle,inst,j) ) {
1751 TT_Glyph_Metrics *gm = handle->instanceh[inst].gmetrics + TT_HASH(j);
1752 width += gm->advance / 64;
1753 casc = (gm->bbox.yMax+63) / 64;
1754 cdesc = (gm->bbox.yMin-63) / 64;
1756 mm_log((1, "i_tt_box_inst: glyph='%c' casc=%d cdesc=%d\n",
1757 ((j >= ' ' && j <= '~') ? j : '.'), casc, cdesc));
1760 start = gm->bbox.xMin / 64;
1761 ascent = (gm->bbox.yMax+63) / 64;
1762 descent = (gm->bbox.yMin-63) / 64;
1765 if (!len) { /* if at end of string */
1766 /* the right-side bearing - in case the right-side of a
1767 character goes past the right of the advance width,
1768 as is common for italic fonts
1770 rightb = gm->advance - gm->bearingX
1771 - (gm->bbox.xMax - gm->bbox.xMin);
1772 /* fprintf(stderr, "font info last: %d %d %d %d\n",
1773 gm->bbox.xMax, gm->bbox.xMin, gm->advance, rightb); */
1776 ascent = (ascent > casc ? ascent : casc );
1777 descent = (descent < cdesc ? descent : cdesc);
1781 cords[BBOX_NEG_WIDTH]=start;
1782 cords[BBOX_GLOBAL_DESCENT]=gdescent;
1783 cords[BBOX_POS_WIDTH]=width;
1785 cords[BBOX_POS_WIDTH] -= rightb / 64;
1786 cords[BBOX_GLOBAL_ASCENT]=gascent;
1787 cords[BBOX_DESCENT]=descent;
1788 cords[BBOX_ASCENT]=ascent;
1789 cords[BBOX_ADVANCE_WIDTH] = width;
1790 cords[BBOX_RIGHT_BEARING] = rightb / 64;
1792 return BBOX_RIGHT_BEARING + 1;
1797 =item i_tt_bbox(handle, points, txt, len, cords, utf8)
1799 Interface to get a strings bounding box
1801 handle - pointer to font handle
1802 points - font size to use
1803 txt - string to render
1804 len - length of the string to render
1805 cords - the bounding box (modified in place)
1811 i_tt_bbox( TT_Fonthandle *handle, float points,const char *txt,int len,int cords[6], int utf8) {
1815 mm_log((1,"i_tt_box(handle 0x%X,points %f,txt '%.*s', len %d, utf8 %d)\n",handle,points,len,txt,len, utf8));
1817 if ( (inst=i_tt_get_instance(handle,points,-1)) < 0) {
1818 i_push_errorf(0, "i_tt_get_instance(%g)", points);
1819 mm_log((1,"i_tt_text: get instance failed\n"));
1823 return i_tt_bbox_inst(handle, inst, txt, len, cords, utf8);
1827 =item i_tt_face_name(handle, name_buf, name_buf_size)
1829 Retrieve's the font's postscript name.
1831 This is complicated by the need to handle encodings and so on.
1836 i_tt_face_name(TT_Fonthandle *handle, char *name_buf, size_t name_buf_size) {
1837 TT_Face_Properties props;
1840 TT_UShort platform_id, encoding_id, lang_id, name_id;
1843 int want_index = -1; /* an acceptable but not perfect name */
1848 TT_Get_Face_Properties(handle->face, &props);
1849 name_count = props.num_Names;
1850 for (i = 0; i < name_count; ++i) {
1851 TT_Get_Name_ID(handle->face, i, &platform_id, &encoding_id, &lang_id,
1854 TT_Get_Name_String(handle->face, i, &name, &name_len);
1856 if (platform_id != TT_PLATFORM_APPLE_UNICODE && name_len
1857 && name_id == TT_NAME_ID_PS_NAME) {
1858 int might_want_index = -1;
1859 int might_score = 0;
1860 if ((platform_id == TT_PLATFORM_MACINTOSH && encoding_id == TT_MAC_ID_ROMAN)
1862 (platform_id == TT_PLATFORM_MICROSOFT && encoding_id == TT_MS_LANGID_ENGLISH_UNITED_STATES)) {
1863 /* exactly what we want */
1868 if (platform_id == TT_PLATFORM_MICROSOFT
1869 && (encoding_id & 0xFF) == TT_MS_LANGID_ENGLISH_GENERAL) {
1870 /* any english is good */
1871 might_want_index = i;
1874 /* there might be something in between */
1876 /* anything non-unicode is better than nothing */
1877 might_want_index = i;
1880 if (might_score > score) {
1881 score = might_score;
1882 want_index = might_want_index;
1887 if (want_index != -1) {
1888 TT_Get_Name_String(handle->face, want_index, &name, &name_len);
1890 strncpy(name_buf, name, name_buf_size);
1891 name_buf[name_buf_size-1] = '\0';
1893 return strlen(name) + 1;
1896 i_push_error(0, "no face name present");
1901 void i_tt_dump_names(TT_Fonthandle *handle) {
1902 TT_Face_Properties props;
1905 TT_UShort platform_id, encoding_id, lang_id, name_id;
1909 TT_Get_Face_Properties(handle->face, &props);
1910 name_count = props.num_Names;
1911 for (i = 0; i < name_count; ++i) {
1912 TT_Get_Name_ID(handle->face, i, &platform_id, &encoding_id, &lang_id,
1914 TT_Get_Name_String(handle->face, i, &name, &name_len);
1916 printf("# %d: plat %d enc %d lang %d name %d value ", i, platform_id,
1917 encoding_id, lang_id, name_id);
1918 if (platform_id == TT_PLATFORM_APPLE_UNICODE) {
1919 printf("(unicode)\n");
1922 printf("'%s'\n", name);
1928 i_tt_glyph_name(TT_Fonthandle *handle, unsigned long ch, char *name_buf,
1929 size_t name_buf_size) {
1937 if (!handle->loaded_names) {
1939 mm_log((1, "Loading PS Names"));
1940 handle->load_cond = TT_Load_PS_Names(handle->face, &post);
1941 ++handle->loaded_names;
1944 if (handle->load_cond) {
1945 i_push_errorf(rc, "error loading names (%d)", handle->load_cond);
1949 index = TT_Char_Index(handle->char_map, ch);
1951 i_push_error(0, "no such character");
1955 rc = TT_Get_PS_Name(handle->face, index, &psname);
1958 i_push_error(rc, "error getting name");
1962 strncpy(name_buf, psname, name_buf_size);
1963 name_buf[name_buf_size-1] = '\0';
1965 return strlen(psname) + 1;
1967 mm_log((1, "FTXPOST extension not enabled\n"));
1969 i_push_error(0, "Use of FTXPOST extension disabled");
1976 =item i_tt_push_error(code)
1978 Push an error message and code onto the Imager error stack.
1983 i_tt_push_error(TT_Error rc) {
1985 TT_String const *msg = TT_ErrToString18(rc);
1987 i_push_error(rc, msg);
1989 i_push_errorf(rc, "Error code 0x%04x", (unsigned)rc);
1993 #endif /* HAVE_LIBTT */
2001 Arnar M. Hrafnkelsson <addi@umich.edu>