X-Git-Url: http://git.imager.perl.org/imager.git/blobdiff_plain/3799c4d10a16068029e8d7abcad0ccddcaa47e94..37f231bde1e9358268d00344fe55ccc686df931e:/font.c diff --git a/font.c b/font.c index 5a40feb1..a162f70d 100644 --- a/font.c +++ b/font.c @@ -1,4 +1,5 @@ -#include "image.h" +#include "imager.h" +#include "imrender.h" #include #include @@ -7,6 +8,10 @@ #include #include +#ifdef HAVE_LIBT1 +#endif + + /* =head1 NAME @@ -18,7 +23,7 @@ font.c - implements font handling functions for t1 and truetype fonts #ifdef HAVE_LIBT1 fontnum = i_t1_new(path_to_pfb, path_to_afm); - i_t1_bbox(fontnum, points, "foo", 3, int cords[6]); + i_t1_bbox(fontnum, points, "foo", 3, i_img_dim cords[BOUNDING_BOX_COUNT]); rc = i_t1_destroy(fontnum); #endif @@ -44,642 +49,17 @@ Some of these functions are internal. */ -/* -=item i_init_fonts() - -Initialize font rendering libraries if they are avaliable. - -=cut -*/ - -undef_int -i_init_fonts(int t1log) { - mm_log((1,"Initializing fonts\n")); - -#ifdef HAVE_LIBT1 - i_init_t1(t1log); -#endif - -#ifdef HAVE_LIBTT - i_init_tt(); -#endif - -#ifdef HAVE_FT2 - if (!i_ft2_init()) - return 0; -#endif - - return(1); /* FIXME: Always true - check the return values of the init_t1 and init_tt functions */ -} - - - - -#ifdef HAVE_LIBT1 - -static int t1_get_flags(char const *flags); -static char *t1_from_utf8(char const *in, int len, int *outlen); - -static void t1_push_error(void); - -/* -=item i_init_t1(t1log) - -Initializes the t1lib font rendering engine. - -=cut -*/ - -undef_int -i_init_t1(int t1log) { - int init_flags = IGNORE_CONFIGFILE|IGNORE_FONTDATABASE; - mm_log((1,"init_t1()\n")); - - if (t1log) - init_flags |= LOGFILE; - if ((T1_InitLib(init_flags) == NULL)){ - mm_log((1,"Initialization of t1lib failed\n")); - return(1); - } - T1_SetLogLevel(T1LOG_DEBUG); - i_t1_set_aa(1); /* Default Antialias value */ - return(0); -} - - -/* -=item i_close_t1() - -Shuts the t1lib font rendering engine down. - - This it seems that this function is never used. - -=cut -*/ - -void -i_close_t1(void) { - T1_CloseLib(); -} - - -/* -=item i_t1_new(pfb, afm) - -Loads the fonts with the given filenames, returns its font id - - pfb - path to pfb file for font - afm - path to afm file for font - -=cut -*/ - -int -i_t1_new(char *pfb,char *afm) { - int font_id; - - mm_log((1,"i_t1_new(pfb %s,afm %s)\n",pfb,(afm?afm:"NULL"))); - font_id = T1_AddFont(pfb); - if (font_id<0) { - mm_log((1,"i_t1_new: Failed to load pfb file '%s' - return code %d.\n",pfb,font_id)); - return font_id; - } - - if (afm != NULL) { - mm_log((1,"i_t1_new: requesting afm file '%s'.\n",afm)); - if (T1_SetAfmFileName(font_id,afm)<0) mm_log((1,"i_t1_new: afm loading of '%s' failed.\n",afm)); - } - - return font_id; -} - -/* -=item i_t1_destroy(font_id) - -Frees resources for a t1 font with given font id. - - font_id - number of the font to free - -=cut -*/ - -int -i_t1_destroy(int font_id) { - mm_log((1,"i_t1_destroy(font_id %d)\n",font_id)); - return T1_DeleteFont(font_id); -} - - -/* -=item i_t1_set_aa(st) - -Sets the antialiasing level of the t1 library. - - st - 0 = NONE, 1 = LOW, 2 = HIGH. - -=cut -*/ - -void -i_t1_set_aa(int st) { - int i; - unsigned long cst[17]; - switch(st) { - case 0: - T1_AASetBitsPerPixel( 8 ); - T1_AASetLevel( T1_AA_NONE ); - T1_AANSetGrayValues( 0, 255 ); - mm_log((1,"setting T1 antialias to none\n")); - break; - case 1: - T1_AASetBitsPerPixel( 8 ); - T1_AASetLevel( T1_AA_LOW ); - T1_AASetGrayValues( 0,65,127,191,255 ); - mm_log((1,"setting T1 antialias to low\n")); - break; - case 2: - T1_AASetBitsPerPixel(8); - T1_AASetLevel(T1_AA_HIGH); - for(i=0;i<17;i++) cst[i]=(i*255)/16; - T1_AAHSetGrayValues( cst ); - mm_log((1,"setting T1 antialias to high\n")); - } -} - - -/* -=item i_t1_cp(im, xb, yb, channel, fontnum, points, str, len, align) - -Interface to text rendering into a single channel in an image - - im pointer to image structure - xb x coordinate of start of string - yb y coordinate of start of string ( see align ) - channel - destination channel - fontnum - t1 library font id - points - number of points in fontheight - str - string to render - len - string length - align - (0 - top of font glyph | 1 - baseline ) - -=cut -*/ - -undef_int -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) { - GLYPH *glyph; - int xsize,ysize,x,y; - i_color val; - int mod_flags = t1_get_flags(flags); - - unsigned int ch_mask_store; - - if (im == NULL) { mm_log((1,"i_t1_cp: Null image in input\n")); return(0); } - - if (utf8) { - int worklen; - char *work = t1_from_utf8(str, len, &worklen); - glyph=T1_AASetString( fontnum, work, worklen, 0, mod_flags, points, NULL); - myfree(work); - } - else { - glyph=T1_AASetString( fontnum, str, len, 0, mod_flags, points, NULL); - } - if (glyph == NULL) - return 0; - - mm_log((1,"metrics: ascent: %d descent: %d\n",glyph->metrics.ascent,glyph->metrics.descent)); - mm_log((1," leftSideBearing: %d rightSideBearing: %d\n",glyph->metrics.leftSideBearing,glyph->metrics.rightSideBearing)); - mm_log((1," advanceX: %d advanceY: %d\n",glyph->metrics.advanceX,glyph->metrics.advanceY)); - mm_log((1,"bpp: %d\n",glyph->bpp)); - - xsize=glyph->metrics.rightSideBearing-glyph->metrics.leftSideBearing; - ysize=glyph->metrics.ascent-glyph->metrics.descent; - - mm_log((1,"width: %d height: %d\n",xsize,ysize)); - - ch_mask_store=im->ch_mask; - im->ch_mask=1<metrics.leftSideBearing; yb-=glyph->metrics.ascent; } - - for(y=0;ybits[y*xsize+x]; - i_ppix(im,x+xb,y+yb,&val); - } - - im->ch_mask=ch_mask_store; - return 1; -} - - -/* -=item i_t1_bbox(handle, fontnum, points, str, len, cords) - -function to get a strings bounding box given the font id and sizes - - handle - pointer to font handle - fontnum - t1 library font id - points - number of points in fontheight - str - string to measure - len - string length - cords - the bounding box (modified in place) - -=cut -*/ - -int -i_t1_bbox(int fontnum,float points,char *str,int len,int cords[6], int utf8,char const *flags) { - BBox bbox; - BBox gbbox; - int mod_flags = t1_get_flags(flags); - int advance; - - mm_log((1,"i_t1_bbox(fontnum %d,points %.2f,str '%.*s', len %d)\n",fontnum,points,len,str,len)); - T1_LoadFont(fontnum); /* FIXME: Here a return code is ignored - haw haw haw */ - if (utf8) { - int worklen; - char *work = t1_from_utf8(str, len, &worklen); - bbox = T1_GetStringBBox(fontnum,work,worklen,0,mod_flags); - myfree(work); - } - else { - bbox = T1_GetStringBBox(fontnum,str,len,0,mod_flags); - } - gbbox = T1_GetFontBBox(fontnum); - advance = T1_GetStringWidth(fontnum, str, len, 0, mod_flags); - - mm_log((1,"bbox: (%d,%d,%d,%d)\n", - (int)(bbox.llx*points/1000), - (int)(gbbox.lly*points/1000), - (int)(bbox.urx*points/1000), - (int)(gbbox.ury*points/1000), - (int)(bbox.lly*points/1000), - (int)(bbox.ury*points/1000) )); - - - cords[BBOX_NEG_WIDTH]=((float)bbox.llx*points)/1000; - cords[BBOX_POS_WIDTH]=((float)bbox.urx*points)/1000; - - cords[BBOX_GLOBAL_DESCENT]=((float)gbbox.lly*points)/1000; - cords[BBOX_GLOBAL_ASCENT]=((float)gbbox.ury*points)/1000; - - cords[BBOX_DESCENT]=((float)bbox.lly*points)/1000; - cords[BBOX_ASCENT]=((float)bbox.ury*points)/1000; - - cords[BBOX_ADVANCE_WIDTH] = ((float)advance * points)/1000; - - return BBOX_ADVANCE_WIDTH+1; -} - - -/* -=item i_t1_text(im, xb, yb, cl, fontnum, points, str, len, align) - -Interface to text rendering in a single color onto an image - - im - pointer to image structure - xb - x coordinate of start of string - yb - y coordinate of start of string ( see align ) - cl - color to draw the text in - fontnum - t1 library font id - points - number of points in fontheight - str - char pointer to string to render - len - string length - align - (0 - top of font glyph | 1 - baseline ) - -=cut -*/ - -undef_int -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) { - GLYPH *glyph; - int xsize,ysize,x,y,ch; - i_color val; - unsigned char c,i; - int mod_flags = t1_get_flags(flags); - - if (im == NULL) { mm_log((1,"i_t1_cp: Null image in input\n")); return(0); } - - if (utf8) { - int worklen; - char *work = t1_from_utf8(str, len, &worklen); - glyph=T1_AASetString( fontnum, work, worklen, 0, mod_flags, points, NULL); - myfree(work); - } - else { - glyph=T1_AASetString( fontnum, str, len, 0, mod_flags, points, NULL); - } - if (glyph == NULL) - return 0; - - mm_log((1,"metrics: ascent: %d descent: %d\n",glyph->metrics.ascent,glyph->metrics.descent)); - mm_log((1," leftSideBearing: %d rightSideBearing: %d\n",glyph->metrics.leftSideBearing,glyph->metrics.rightSideBearing)); - mm_log((1," advanceX: %d advanceY: %d\n",glyph->metrics.advanceX,glyph->metrics.advanceY)); - mm_log((1,"bpp: %d\n",glyph->bpp)); - - xsize=glyph->metrics.rightSideBearing-glyph->metrics.leftSideBearing; - ysize=glyph->metrics.ascent-glyph->metrics.descent; - - mm_log((1,"width: %d height: %d\n",xsize,ysize)); - - if (align==1) { xb+=glyph->metrics.leftSideBearing; yb-=glyph->metrics.ascent; } - - for(y=0;ybits[y*xsize+x]; - i=255-c; - i_gpix(im,x+xb,y+yb,&val); - for(ch=0;chchannels;ch++) val.channel[ch]=(c*cl->channel[ch]+i*val.channel[ch])/255; - i_ppix(im,x+xb,y+yb,&val); - } - return 1; -} - -/* -=item t1_get_flags(flags) - -Processes the characters in I to create a mod_flags value used -by some T1Lib functions. - -=cut - */ -static int -t1_get_flags(char const *flags) { - int mod_flags = T1_KERNING; - - while (*flags) { - switch (*flags++) { - case 'u': case 'U': mod_flags |= T1_UNDERLINE; break; - case 'o': case 'O': mod_flags |= T1_OVERLINE; break; - case 's': case 'S': mod_flags |= T1_OVERSTRIKE; break; - /* ignore anything we don't recognize */ - } - } - - return mod_flags; -} - -/* -=item t1_from_utf8(char const *in, int len, int *outlen) - -Produces an unencoded version of I by dropping any Unicode -character over 255. - -Returns a newly allocated buffer which should be freed with myfree(). -Sets *outlen to the number of bytes used in the output string. - -=cut -*/ - -static char * -t1_from_utf8(char const *in, int len, int *outlen) { - char *out = mymalloc(len+1); - char *p = out; - unsigned long c; - - while (len) { - c = i_utf8_advance(&in, &len); - if (c == ~0UL) { - myfree(out); - i_push_error(0, "invalid UTF8 character"); - return 0; - } - /* yeah, just drop them */ - if (c < 0x100) { - *p++ = (char)c; - } - } - *p = '\0'; - *outlen = p - out; - - return out; -} - -/* -=item i_t1_has_chars(font_num, text, len, utf8, out) - -Check if the given characters are defined by the font. Note that len -is the number of bytes, not the number of characters (when utf8 is -non-zero). - -out[char index] will be true if the character exists. - -Accepts UTF-8, but since T1 can only have 256 characters, any chars -with values over 255 will simply be returned as false. - -Returns the number of characters that were checked. - -=cut -*/ - -int -i_t1_has_chars(int font_num, const char *text, int len, int utf8, - char *out) { - int count = 0; - - mm_log((1, "i_t1_has_chars(font_num %d, text %p, len %d, utf8 %d)\n", - font_num, text, len, utf8)); - - i_clear_error(); - if (T1_LoadFont(font_num)) { - t1_push_error(); - return 0; - } - - while (len) { - unsigned long c; - int index; - if (utf8) { - c = i_utf8_advance(&text, &len); - if (c == ~0UL) { - i_push_error(0, "invalid UTF8 character"); - return 0; - } - } - else { - c = (unsigned char)*text++; - --len; - } - - if (c >= 0x100) { - /* limit of 256 characters for T1 */ - *out++ = 0; - } - else { - char const * name = T1_GetCharName(font_num, (unsigned char)c); - - if (name) { - *out++ = strcmp(name, ".notdef") != 0; - } - else { - mm_log((2, " No name found for character %lx\n", c)); - *out++ = 0; - } - } - ++count; - } - - return count; -} - -/* -=item i_t1_face_name(font_num, name_buf, name_buf_size) - -Copies the face name of the given C to C. Returns -the number of characters required to store the name (which can be -larger than C, including the space required to store -the terminating NUL). - -If name_buf is too small (as specified by name_buf_size) then the name -will be truncated. name_buf will always be NUL termintaed. - -=cut -*/ - -int -i_t1_face_name(int font_num, char *name_buf, size_t name_buf_size) { - char *name; - - T1_errno = 0; - if (T1_LoadFont(font_num)) { - t1_push_error(); - return 0; - } - name = T1_GetFontName(font_num); - - if (name) { - strncpy(name_buf, name, name_buf_size); - name_buf[name_buf_size-1] = '\0'; - return strlen(name) + 1; - } - else { - t1_push_error(); - return 0; - } -} - -int -i_t1_glyph_name(int font_num, unsigned long ch, char *name_buf, - size_t name_buf_size) { - char *name; - - i_clear_error(); - if (ch > 0xFF) { - return 0; - } - if (T1_LoadFont(font_num)) { - t1_push_error(); - return 0; - } - name = T1_GetCharName(font_num, (unsigned char)ch); - if (name) { - if (strcmp(name, ".notdef")) { - strncpy(name_buf, name, name_buf_size); - name_buf[name_buf_size-1] = '\0'; - return strlen(name) + 1; - } - else { - return 0; - } - } - else { - t1_push_error(); - return 0; - } -} - -static void -t1_push_error(void) { - switch (T1_errno) { - case 0: - i_push_error(0, "No error"); - break; - - case T1ERR_SCAN_FONT_FORMAT: - i_push_error(T1ERR_SCAN_FONT_FORMAT, "SCAN_FONT_FORMAT"); - break; - - case T1ERR_SCAN_FILE_OPEN_ERR: - i_push_error(T1ERR_SCAN_FILE_OPEN_ERR, "SCAN_FILE_OPEN_ERR"); - break; - - case T1ERR_SCAN_OUT_OF_MEMORY: - i_push_error(T1ERR_SCAN_OUT_OF_MEMORY, "SCAN_OUT_OF_MEMORY"); - break; - - case T1ERR_SCAN_ERROR: - i_push_error(T1ERR_SCAN_ERROR, "SCAN_ERROR"); - break; - - case T1ERR_SCAN_FILE_EOF: - i_push_error(T1ERR_SCAN_FILE_EOF, "SCAN_FILE_EOF"); - break; - - case T1ERR_PATH_ERROR: - i_push_error(T1ERR_PATH_ERROR, "PATH_ERROR"); - break; - - case T1ERR_PARSE_ERROR: - i_push_error(T1ERR_PARSE_ERROR, "PARSE_ERROR"); - break; - - case T1ERR_TYPE1_ABORT: - i_push_error(T1ERR_TYPE1_ABORT, "TYPE1_ABORT"); - break; - - case T1ERR_INVALID_FONTID: - i_push_error(T1ERR_INVALID_FONTID, "INVALID_FONTID"); - break; - - case T1ERR_INVALID_PARAMETER: - i_push_error(T1ERR_INVALID_PARAMETER, "INVALID_PARAMETER"); - break; - - case T1ERR_OP_NOT_PERMITTED: - i_push_error(T1ERR_OP_NOT_PERMITTED, "OP_NOT_PERMITTED"); - break; - - case T1ERR_ALLOC_MEM: - i_push_error(T1ERR_ALLOC_MEM, "ALLOC_MEM"); - break; - - case T1ERR_FILE_OPEN_ERR: - i_push_error(T1ERR_FILE_OPEN_ERR, "FILE_OPEN_ERR"); - break; - - case T1ERR_UNSPECIFIED: - i_push_error(T1ERR_UNSPECIFIED, "UNSPECIFIED"); - break; - - case T1ERR_NO_AFM_DATA: - i_push_error(T1ERR_NO_AFM_DATA, "NO_AFM_DATA"); - break; - - case T1ERR_X11: - i_push_error(T1ERR_X11, "X11"); - break; - - case T1ERR_COMPOSITE_CHAR: - i_push_error(T1ERR_COMPOSITE_CHAR, "COMPOSITE_CHAR"); - break; - - default: - i_push_errorf(T1_errno, "unknown error %d", (int)T1_errno); - } -} - -#endif /* HAVE_LIBT1 */ - /* Truetype font support */ #ifdef HAVE_LIBTT -/* This is enabled by default when configuring Freetype 1.x +/* These are enabled by default when configuring Freetype 1.x I haven't a clue how to reliably detect it at compile time. We need a compilation probe in Makefile.PL */ #define FTXPOST 1 +#define FTXERR18 1 #include #define TT_CHC 5 @@ -688,6 +68,16 @@ t1_push_error(void) { #include #endif +#ifdef FTXERR18 +#include +#endif + +/* some versions of FT1.x don't seem to define this - it's font defined + so it won't change */ +#ifndef TT_MS_LANGID_ENGLISH_GENERAL +#define TT_MS_LANGID_ENGLISH_GENERAL 0x0409 +#endif + /* convert a code point into an index in the glyph cache */ #define TT_HASH(x) ((x) & 0xFF) @@ -704,8 +94,8 @@ struct TT_Instancehandle_ { TT_Glyph_Metrics gmetrics[256]; i_tt_glyph_entry glyphs[256]; int smooth; - int ptsize; int order; + i_img_dim ptsize; }; typedef struct TT_Instancehandle_ TT_Instancehandle; @@ -726,33 +116,35 @@ struct TT_Fonthandle_ { #define USTRCT(x) ((x).z) #define TT_VALID( handle ) ( ( handle ).z != NULL ) +static void i_tt_push_error(TT_Error rc); /* Prototypes */ -static int i_tt_get_instance( TT_Fonthandle *handle, int points, int smooth ); -static void i_tt_init_raster_map( TT_Raster_Map* bit, int width, int height, int smooth ); +static int i_tt_get_instance( TT_Fonthandle *handle, i_img_dim points, int smooth ); +static void i_tt_init_raster_map( TT_Raster_Map* bit, i_img_dim width, i_img_dim height, int smooth ); static void i_tt_done_raster_map( TT_Raster_Map *bit ); static void i_tt_clear_raster_map( TT_Raster_Map* bit ); -static void i_tt_blit_or( TT_Raster_Map *dst, TT_Raster_Map *src,int x_off, int y_off ); +static void i_tt_blit_or( TT_Raster_Map *dst, TT_Raster_Map *src,i_img_dim x_off, i_img_dim y_off ); static int i_tt_get_glyph( TT_Fonthandle *handle, int inst, unsigned long j ); static void 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 ); + i_img_dim x_off, i_img_dim y_off, int smooth ); static int i_tt_render_all_glyphs( TT_Fonthandle *handle, int inst, TT_Raster_Map *bit, - TT_Raster_Map *small_bit, int cords[6], - char const* txt, int len, int smooth, int utf8 ); -static void i_tt_dump_raster_map2( i_img* im, TT_Raster_Map* bit, int xb, int yb, i_color *cl, int smooth ); -static void i_tt_dump_raster_map_channel( i_img* im, TT_Raster_Map* bit, int xb, int yb, int channel, int smooth ); + TT_Raster_Map *small_bit, i_img_dim cords[6], + char const* txt, size_t len, int smooth, int utf8 ); +static void i_tt_dump_raster_map2( i_img* im, TT_Raster_Map* bit, i_img_dim xb, i_img_dim yb, const i_color *cl, int smooth ); +static void i_tt_dump_raster_map_channel( i_img* im, TT_Raster_Map* bit, i_img_dim xb, i_img_dim yb, int channel, int smooth ); static int -i_tt_rasterize( TT_Fonthandle *handle, TT_Raster_Map *bit, int cords[6], - float points, char const* txt, int len, int smooth, int utf8 ); -static undef_int i_tt_bbox_inst( TT_Fonthandle *handle, int inst ,const char *txt, int len, int cords[6], int utf8 ); +i_tt_rasterize( TT_Fonthandle *handle, TT_Raster_Map *bit, i_img_dim cords[6], + double points, char const* txt, size_t len, int smooth, int utf8 ); +static undef_int i_tt_bbox_inst( TT_Fonthandle *handle, int inst ,const char *txt, size_t len, i_img_dim cords[6], int utf8 ); /* static globals needed */ +static int TT_initialized = 0; static TT_Engine engine; static int LTT_dpi = 72; /* FIXME: this ought to be a part of the call interface */ static int LTT_hinted = 1; /* FIXME: this too */ @@ -771,24 +163,46 @@ Initializes the freetype font rendering engine =cut */ -undef_int -i_init_tt() { +static undef_int +i_init_tt(void) { TT_Error error; + TT_Byte palette[] = { 0, 64, 127, 191, 255 }; + + i_clear_error(); + mm_log((1,"init_tt()\n")); error = TT_Init_FreeType( &engine ); if ( error ){ - mm_log((1,"Initialization of freetype failed, code = 0x%x\n",error)); + mm_log((1,"Initialization of freetype failed, code = 0x%x\n", + (unsigned)error)); + i_tt_push_error(error); + i_push_error(0, "Could not initialize freetype 1.x"); return(1); } #ifdef FTXPOST error = TT_Init_Post_Extension( engine ); if (error) { - mm_log((1, "Initialization of Post extension failed = 0x%x\n", error)); + mm_log((1, "Initialization of Post extension failed = 0x%x\n", + (unsigned)error)); + + i_tt_push_error(error); + i_push_error(0, "Could not initialize FT 1.x POST extension"); return 1; } #endif + error = TT_Set_Raster_Gray_Palette(engine, palette); + if (error) { + mm_log((1, "Initialization of gray levels failed = 0x%x\n", + (unsigned)error)); + i_tt_push_error(error); + i_push_error(0, "Could not initialize FT 1.x POST extension"); + return 1; + } + + TT_initialized = 1; + return(0); } @@ -809,12 +223,12 @@ allocates room and returns its cache entry static int -i_tt_get_instance( TT_Fonthandle *handle, int points, int smooth ) { +i_tt_get_instance( TT_Fonthandle *handle, i_img_dim points, int smooth ) { int i,idx; TT_Error error; - mm_log((1,"i_tt_get_instance(handle 0x%X, points %d, smooth %d)\n", - handle,points,smooth)); + mm_log((1,"i_tt_get_instance(handle %p, points %" i_DF ", smooth %d)\n", + handle, i_DFc(points), smooth)); if (smooth == -1) { /* Smooth doesn't matter for this search */ for(i=0;iinstanceh[idx].instance) )); if ( USTRCT(handle->instanceh[idx].instance) ) { @@ -869,7 +283,8 @@ i_tt_get_instance( TT_Fonthandle *handle, int points, int smooth ) { ( error = TT_Set_Instance_CharSize( handle->instanceh[idx].instance, points*64 ) ) ); if ( error ) { - mm_log((1, "Could not create and initialize instance: error 0x%x.\n",error )); + mm_log((1, "Could not create and initialize instance: error %x.\n", + (unsigned)error )); return -1; } @@ -907,17 +322,24 @@ the font handle's cache */ TT_Fonthandle* -i_tt_new(char *fontname) { +i_tt_new(const char *fontname) { TT_Error error; TT_Fonthandle *handle; unsigned short i,n; unsigned short platform,encoding; + + if (!TT_initialized && i_init_tt()) { + i_push_error(0, "Could not initialize FT1 engine"); + return NULL; + } + + i_clear_error(); mm_log((1,"i_tt_new(fontname '%s')\n",fontname)); /* allocate memory for the structure */ - handle = mymalloc( sizeof(TT_Fonthandle) ); + handle = mymalloc( sizeof(TT_Fonthandle) ); /* checked 5Nov05 tonyc */ /* load the typeface */ error = TT_Open_Face( engine, fontname, &handle->face ); @@ -927,8 +349,9 @@ i_tt_new(char *fontname) { } else { mm_log((1, "Error while opening %s, error code = 0x%x.\n",fontname, - error )); + (unsigned)error )); } + i_tt_push_error(error); return NULL; } @@ -966,7 +389,7 @@ i_tt_new(char *fontname) { handle->loaded_names = 0; #endif - mm_log((1,"i_tt_new <- 0x%X\n",handle)); + mm_log((1,"i_tt_new <- %p\n",handle)); return handle; } @@ -991,9 +414,10 @@ Allocates internal memory for the bitmap as needed by the parameters (internal) static void -i_tt_init_raster_map( TT_Raster_Map* bit, int width, int height, int smooth ) { +i_tt_init_raster_map( TT_Raster_Map* bit, i_img_dim width, i_img_dim height, int smooth ) { - mm_log((1,"i_tt_init_raster_map( bit 08x%08X, width %d, height %d, smooth %d)\n", bit, width, height, smooth)); + mm_log((1,"i_tt_init_raster_map( bit %p, width %" i_DF ", height %" i_DF + ", smooth %d)\n", bit, i_DFc(width), i_DFc(height), smooth)); bit->rows = height; bit->width = ( width + 3 ) & -4; @@ -1006,11 +430,17 @@ i_tt_init_raster_map( TT_Raster_Map* bit, int width, int height, int smooth ) { bit->cols = ( bit->width + 7 ) / 8; /* convert to # of bytes */ bit->size = bit->rows * bit->cols; /* number of bytes in buffer */ } + + /* rows can be 0 for some glyphs, for example ' ' */ + if (bit->rows && bit->size / bit->rows != bit->cols) { + i_fatal(0, "Integer overflow calculating bitmap size (%d, %d)\n", + bit->width, bit->rows); + } - 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 )); + mm_log((1,"i_tt_init_raster_map: bit->width %d, bit->cols %d, bit->rows %d, bit->size %ld)\n", bit->width, bit->cols, bit->rows, bit->size )); - bit->bitmap = (void *) mymalloc( bit->size ); - if ( !bit->bitmap ) m_fatal(0,"Not enough memory to allocate bitmap (%d)!\n",bit->size ); + bit->bitmap = (void *) mymalloc( bit->size ); /* checked 6Nov05 tonyc */ + if ( !bit->bitmap ) i_fatal(0,"Not enough memory to allocate bitmap (%d)!\n",bit->size ); } @@ -1065,10 +495,10 @@ function that blits one raster map into another (internal) static void -i_tt_blit_or( TT_Raster_Map *dst, TT_Raster_Map *src,int x_off, int y_off ) { - int x, y; - int x1, x2, y1, y2; - char *s, *d; +i_tt_blit_or( TT_Raster_Map *dst, TT_Raster_Map *src,i_img_dim x_off, i_img_dim y_off ) { + i_img_dim x, y; + i_img_dim x1, x2, y1, y2; + unsigned char *s, *d; x1 = x_off < 0 ? -x_off : 0; y1 = y_off < 0 ? -y_off : 0; @@ -1084,8 +514,8 @@ i_tt_blit_or( TT_Raster_Map *dst, TT_Raster_Map *src,int x_off, int y_off ) { /* do the real work now */ for ( y = y1; y < y2; ++y ) { - s = ( (char*)src->bitmap ) + y * src->cols + x1; - d = ( (char*)dst->bitmap ) + ( y + y_off ) * dst->cols + x1 + x_off; + s = ( (unsigned char*)src->bitmap ) + y * src->cols + x1; + d = ( (unsigned char*)dst->bitmap ) + ( y + y_off ) * dst->cols + x1 + x_off; for ( x = x1; x < x2; ++x ) { if (*s > *d) @@ -1132,14 +562,14 @@ i_tt_get_glyph( TT_Fonthandle *handle, int inst, unsigned long j) { unsigned short load_flags, code; TT_Error error; - mm_log((1, "i_tt_get_glyph(handle 0x%X, inst %d, j %d (%c))\n", - handle,inst,j, ((j >= ' ' && j <= '~') ? j : '.'))); + mm_log((1, "i_tt_get_glyph(handle %p, inst %d, j %lu (%c))\n", + handle,inst,j, (int)((j >= ' ' && j <= '~') ? j : '.'))); /*mm_log((1, "handle->instanceh[inst].glyphs[j]=0x%08X\n",handle->instanceh[inst].glyphs[j] ));*/ if ( TT_VALID(handle->instanceh[inst].glyphs[TT_HASH(j)].glyph) && handle->instanceh[inst].glyphs[TT_HASH(j)].ch == j) { - mm_log((1,"i_tt_get_glyph: %d in cache\n",j)); + mm_log((1,"i_tt_get_glyph: %lu in cache\n",j)); return 1; } @@ -1160,12 +590,12 @@ i_tt_get_glyph( TT_Fonthandle *handle, int inst, unsigned long j) { } else code = TT_Char_Index( handle->char_map, j ); if ( (error = TT_New_Glyph( handle->face, &handle->instanceh[inst].glyphs[TT_HASH(j)].glyph)) ) { - mm_log((1, "Cannot allocate and load glyph: error 0x%x.\n", error )); + mm_log((1, "Cannot allocate and load glyph: error %#x.\n", (unsigned)error )); i_push_error(error, "TT_New_Glyph()"); return 0; } if ( (error = TT_Load_Glyph( handle->instanceh[inst].instance, handle->instanceh[inst].glyphs[TT_HASH(j)].glyph, code, load_flags)) ) { - mm_log((1, "Cannot allocate and load glyph: error 0x%x.\n", error )); + mm_log((1, "Cannot allocate and load glyph: error %#x.\n", (unsigned)error )); /* Don't leak */ TT_Done_Glyph( handle->instanceh[inst].glyphs[TT_HASH(j)].glyph ); USTRCT( handle->instanceh[inst].glyphs[TT_HASH(j)].glyph ) = NULL; @@ -1180,7 +610,7 @@ i_tt_get_glyph( TT_Fonthandle *handle, int inst, unsigned long j) { error = TT_Get_Glyph_Metrics( handle->instanceh[inst].glyphs[TT_HASH(j)].glyph, &handle->instanceh[inst].gmetrics[TT_HASH(j)] ); if (error) { - mm_log((1, "TT_Get_Glyph_Metrics: error 0x%x.\n", error )); + mm_log((1, "TT_Get_Glyph_Metrics: error %#x.\n", (unsigned)error )); TT_Done_Glyph( handle->instanceh[inst].glyphs[TT_HASH(j)].glyph ); USTRCT( handle->instanceh[inst].glyphs[TT_HASH(j)].glyph ) = NULL; handle->instanceh[inst].glyphs[TT_HASH(j)].ch = TT_NOCHAR; @@ -1203,13 +633,12 @@ Returns the number of characters that were checked. =cut */ -int -i_tt_has_chars(TT_Fonthandle *handle, char const *text, int len, int utf8, +size_t +i_tt_has_chars(TT_Fonthandle *handle, char const *text, size_t len, int utf8, char *out) { - int count = 0; - int inst; - mm_log((1, "i_tt_has_chars(handle %p, text %p, len %d, utf8 %d)\n", - handle, text, len, utf8)); + size_t count = 0; + mm_log((1, "i_tt_has_chars(handle %p, text %p, len %ld, utf8 %d)\n", + handle, text, (long)len, utf8)); while (len) { unsigned long c; @@ -1298,10 +727,11 @@ Renders a single glyph into the bit rastermap (internal) static void -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 ) { +i_tt_render_glyph( TT_Glyph glyph, TT_Glyph_Metrics* gmetrics, TT_Raster_Map *bit, TT_Raster_Map *small_bit, i_img_dim x_off, i_img_dim y_off, int smooth ) { - 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", - USTRCT(glyph), gmetrics, bit, small_bit, x_off,y_off,smooth)); + mm_log((1,"i_tt_render_glyph(glyph %p, gmetrics %p, bit %p, small_bit %p, x_off %" i_DF ", y_off %" i_DF ", smooth %d)\n", + USTRCT(glyph), gmetrics, bit, small_bit, i_DFc(x_off), + i_DFc(y_off), smooth)); if ( !smooth ) TT_Get_Glyph_Bitmap( glyph, bit, x_off * 64, y_off * 64); else { @@ -1338,14 +768,13 @@ calls i_tt_render_glyph to render each glyph into the bit rastermap (internal) static int i_tt_render_all_glyphs( TT_Fonthandle *handle, int inst, TT_Raster_Map *bit, - TT_Raster_Map *small_bit, int cords[6], - char const* txt, int len, int smooth, int utf8 ) { + TT_Raster_Map *small_bit, i_img_dim cords[6], + char const* txt, size_t len, int smooth, int utf8 ) { unsigned long j; - int i; TT_F26Dot6 x,y; - 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", - handle, inst, bit, small_bit, len, txt, len, smooth, utf8)); + mm_log((1,"i_tt_render_all_glyphs( handle %p, inst %d, bit %p, small_bit %p, txt '%.*s', len %ld, smooth %d, utf8 %d)\n", + handle, inst, bit, small_bit, (int)len, txt, (long)len, smooth, utf8)); /* y=-( handle->properties.horizontal->Descender * handle->instanceh[inst].imetrics.y_ppem )/(handle->properties.header->Units_Per_EM); @@ -1398,32 +827,37 @@ Function to dump a raster onto an image in color used by i_tt_text() (internal). static void -i_tt_dump_raster_map2( i_img* im, TT_Raster_Map* bit, int xb, int yb, i_color *cl, int smooth ) { - char *bmap; - i_color val; - int c, i, ch, x, y; - 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)); +i_tt_dump_raster_map2( i_img* im, TT_Raster_Map* bit, i_img_dim xb, i_img_dim yb, const i_color *cl, int smooth ) { + unsigned char *bmap; + i_img_dim x, y; + mm_log((1,"i_tt_dump_raster_map2(im %p, bit %p, xb %" i_DF ", yb %" i_DF ", cl %p)\n", + im, bit, i_DFc(xb), i_DFc(yb), cl)); - bmap = (char *)bit->bitmap; + bmap = bit->bitmap; if ( smooth ) { - for(y=0;yrows;y++) for(x=0;xwidth;x++) { - c=(255*bmap[y*(bit->cols)+x])/4; - i=255-c; - i_gpix(im,x+xb,y+yb,&val); - for(ch=0;chchannels;ch++) val.channel[ch]=(c*cl->channel[ch]+i*val.channel[ch])/255; - i_ppix(im,x+xb,y+yb,&val); + i_render r; + i_render_init(&r, im, bit->cols); + for(y=0;yrows;y++) { + i_render_color(&r, xb, yb+y, bit->cols, bmap + y*bit->cols, cl); } - + i_render_done(&r); } else { - - for(y=0;yrows;y++) for(x=0;xwidth;x++) { - c=( bmap[y*bit->cols+x/8] & (128>>(x%8)) ) ? 255 : 0; - i=255-c; - i_gpix(im,x+xb,y+yb,&val); - for(ch=0;chchannels;ch++) val.channel[ch]=(c*cl->channel[ch]+i*val.channel[ch])/255; - i_ppix(im,x+xb,y+yb,&val); + for(y=0;yrows;y++) { + unsigned mask = 0x80; + unsigned char *p = bmap + y * bit->cols; + + for(x = 0; x < bit->width; x++) { + if (*p & mask) { + i_ppix(im, x+xb, y+yb, cl); + } + mask >>= 1; + if (!mask) { + mask = 0x80; + ++p; + } + } } } @@ -1446,30 +880,43 @@ Function to dump a raster onto a single channel image in color (internal) static void -i_tt_dump_raster_map_channel( i_img* im, TT_Raster_Map* bit, int xb, int yb, int channel, int smooth ) { - char *bmap; +i_tt_dump_raster_map_channel( i_img* im, TT_Raster_Map* bit, i_img_dim xb, i_img_dim yb, int channel, int smooth ) { + unsigned char *bmap; i_color val; - int c,x,y; + int c; + i_img_dim x,y; + int old_mask = im->ch_mask; + im->ch_mask = 1 << channel; - 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)); + mm_log((1,"i_tt_dump_raster_channel(im %p, bit %p, xb %" i_DF ", yb %" i_DF ", channel %d)\n", + im, bit, i_DFc(xb), i_DFc(yb), channel)); - bmap = (char *)bit->bitmap; + bmap = bit->bitmap; if ( smooth ) { for(y=0;yrows;y++) for(x=0;xwidth;x++) { - c=(255*bmap[y*(bit->cols)+x])/4; - i_gpix(im,x+xb,y+yb,&val); - val.channel[channel]=c; + c = bmap[y*(bit->cols)+x]; + val.channel[channel] = c; i_ppix(im,x+xb,y+yb,&val); } } else { - for(y=0;yrows;y++) for(x=0;xwidth;x++) { - c=( bmap[y*bit->cols+x/8] & (128>>(x%8)) ) ? 255 : 0; - i_gpix(im,x+xb,y+yb,&val); - val.channel[channel]=c; - i_ppix(im,x+xb,y+yb,&val); + for(y=0;yrows;y++) { + unsigned mask = 0x80; + unsigned char *p = bmap + y * bit->cols; + + for(x=0;xwidth;x++) { + val.channel[channel] = (*p & mask) ? 255 : 0; + i_ppix(im,x+xb,y+yb,&val); + + mask >>= 1; + if (!mask) { + ++p; + mask = 0x80; + } + } } } + im->ch_mask = old_mask; } @@ -1491,9 +938,9 @@ interface for generating single channel raster of text (internal) static int -i_tt_rasterize( TT_Fonthandle *handle, TT_Raster_Map *bit, int cords[6], float points, char const* txt, int len, int smooth, int utf8 ) { +i_tt_rasterize( TT_Fonthandle *handle, TT_Raster_Map *bit, i_img_dim cords[6], double points, char const* txt, size_t len, int smooth, int utf8 ) { int inst; - int width, height; + i_img_dim width, height; TT_Raster_Map small_bit; /* find or install an instance */ @@ -1510,7 +957,8 @@ i_tt_rasterize( TT_Fonthandle *handle, TT_Raster_Map *bit, int cords[6], float p width = cords[2]-cords[0]; height = cords[5]-cords[4]; - mm_log((1,"i_tt_rasterize: width=%d, height=%d\n",width, height )); + mm_log((1,"i_tt_rasterize: width=%" i_DF ", height=%" i_DF "\n", + i_DFc(width), i_DFc(height) )); i_tt_init_raster_map ( bit, width, height, smooth ); i_tt_clear_raster_map( bit ); @@ -1523,8 +971,6 @@ i_tt_rasterize( TT_Fonthandle *handle, TT_Raster_Map *bit, int cords[6], float p return 0; } - /* ascent = ( handle->properties.horizontal->Ascender * handle->instanceh[inst].imetrics.y_ppem ) / handle->properties.header->Units_Per_EM; */ - if ( smooth ) i_tt_done_raster_map( &small_bit ); return 1; } @@ -1554,19 +1000,20 @@ Interface to text rendering into a single channel in an image */ undef_int -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 ) { +i_tt_cp( TT_Fonthandle *handle, i_img *im, i_img_dim xb, i_img_dim yb, int channel, double points, char const* txt, size_t len, int smooth, int utf8, int align ) { - int cords[BOUNDING_BOX_COUNT]; - int ascent, st_offset; + i_img_dim cords[BOUNDING_BOX_COUNT]; + i_img_dim ascent, st_offset, y; TT_Raster_Map bit; i_clear_error(); if (! i_tt_rasterize( handle, &bit, cords, points, txt, len, smooth, utf8 ) ) return 0; - ascent=cords[5]; - st_offset=cords[0]; + ascent=cords[BBOX_ASCENT]; + st_offset=cords[BBOX_NEG_WIDTH]; + y = align ? yb-ascent : yb; - i_tt_dump_raster_map_channel( im, &bit, xb-st_offset , yb-ascent, channel, smooth ); + i_tt_dump_raster_map_channel( im, &bit, xb-st_offset , y, channel, smooth ); i_tt_done_raster_map( &bit ); return 1; @@ -1591,19 +1038,20 @@ Interface to text rendering in a single color onto an image */ undef_int -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) { - int cords[BOUNDING_BOX_COUNT]; - int ascent, st_offset; +i_tt_text( TT_Fonthandle *handle, i_img *im, i_img_dim xb, i_img_dim yb, const i_color *cl, double points, char const* txt, size_t len, int smooth, int utf8, int align) { + i_img_dim cords[BOUNDING_BOX_COUNT]; + i_img_dim ascent, st_offset, y; TT_Raster_Map bit; i_clear_error(); if (! i_tt_rasterize( handle, &bit, cords, points, txt, len, smooth, utf8 ) ) return 0; - ascent=cords[5]; - st_offset=cords[0]; + ascent=cords[BBOX_ASCENT]; + st_offset=cords[BBOX_NEG_WIDTH]; + y = align ? yb-ascent : yb; - i_tt_dump_raster_map2( im, &bit, xb+st_offset, yb-ascent, cl, smooth ); + i_tt_dump_raster_map2( im, &bit, xb+st_offset, y, cl, smooth ); i_tt_done_raster_map( &bit ); return 1; @@ -1626,11 +1074,11 @@ Function to get texts bounding boxes given the instance of the font (internal) static undef_int -i_tt_bbox_inst( TT_Fonthandle *handle, int inst ,const char *txt, int len, int cords[BOUNDING_BOX_COUNT], int utf8 ) { - int i, upm, casc, cdesc, first; +i_tt_bbox_inst( TT_Fonthandle *handle, int inst ,const char *txt, size_t len, i_img_dim cords[BOUNDING_BOX_COUNT], int utf8 ) { + int upm, casc, cdesc, first; int start = 0; - int width = 0; + i_img_dim width = 0; int gdescent = 0; int gascent = 0; int descent = 0; @@ -1641,7 +1089,8 @@ i_tt_bbox_inst( TT_Fonthandle *handle, int inst ,const char *txt, int len, int c unsigned char *ustr; ustr=(unsigned char*)txt; - 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)); + mm_log((1,"i_tt_box_inst(handle %p,inst %d,txt '%.*s', len %ld, utf8 %d)\n", + handle, inst, (int)len, txt, (long)len, utf8)); upm = handle->properties.header->Units_Per_EM; gascent = ( handle->properties.horizontal->Ascender * handle->instanceh[inst].imetrics.y_ppem + upm - 1) / upm; @@ -1672,7 +1121,7 @@ i_tt_bbox_inst( TT_Fonthandle *handle, int inst ,const char *txt, int len, int c cdesc = (gm->bbox.yMin-63) / 64; mm_log((1, "i_tt_box_inst: glyph='%c' casc=%d cdesc=%d\n", - ((j >= ' ' && j <= '~') ? j : '.'), casc, cdesc)); + (int)((j >= ' ' && j <= '~') ? j : '.'), casc, cdesc)); if (first) { start = gm->bbox.xMin / 64; @@ -1680,7 +1129,7 @@ i_tt_bbox_inst( TT_Fonthandle *handle, int inst ,const char *txt, int len, int c descent = (gm->bbox.yMin-63) / 64; first = 0; } - if (i == len-1) { + if (!len) { /* if at end of string */ /* the right-side bearing - in case the right-side of a character goes past the right of the advance width, as is common for italic fonts @@ -1689,8 +1138,6 @@ i_tt_bbox_inst( TT_Fonthandle *handle, int inst ,const char *txt, int len, int c - (gm->bbox.xMax - gm->bbox.xMin); /* fprintf(stderr, "font info last: %d %d %d %d\n", gm->bbox.xMax, gm->bbox.xMin, gm->advance, rightb); */ - if (rightb > 0) - rightb = 0; } ascent = (ascent > casc ? ascent : casc ); @@ -1700,13 +1147,16 @@ i_tt_bbox_inst( TT_Fonthandle *handle, int inst ,const char *txt, int len, int c cords[BBOX_NEG_WIDTH]=start; cords[BBOX_GLOBAL_DESCENT]=gdescent; - cords[BBOX_POS_WIDTH]=width - rightb / 64; + cords[BBOX_POS_WIDTH]=width; + if (rightb < 0) + cords[BBOX_POS_WIDTH] -= rightb / 64; cords[BBOX_GLOBAL_ASCENT]=gascent; cords[BBOX_DESCENT]=descent; cords[BBOX_ASCENT]=ascent; cords[BBOX_ADVANCE_WIDTH] = width; + cords[BBOX_RIGHT_BEARING] = rightb / 64; - return BBOX_ADVANCE_WIDTH + 1; + return BBOX_RIGHT_BEARING + 1; } @@ -1725,11 +1175,12 @@ Interface to get a strings bounding box */ undef_int -i_tt_bbox( TT_Fonthandle *handle, float points,char *txt,int len,int cords[6], int utf8) { +i_tt_bbox( TT_Fonthandle *handle, double points,const char *txt,size_t len,i_img_dim cords[6], int utf8) { int inst; i_clear_error(); - mm_log((1,"i_tt_box(handle 0x%X,points %f,txt '%.*s', len %d, utf8 %d)\n",handle,points,len,txt,len, utf8)); + mm_log((1,"i_tt_box(handle %p,points %f,txt '%.*s', len %ld, utf8 %d)\n", + handle, points, (int)len, txt, (long)len, utf8)); if ( (inst=i_tt_get_instance(handle,points,-1)) < 0) { i_push_errorf(0, "i_tt_get_instance(%g)", points); @@ -1749,7 +1200,7 @@ This is complicated by the need to handle encodings and so on. =cut */ -int +size_t i_tt_face_name(TT_Fonthandle *handle, char *name_buf, size_t name_buf_size) { TT_Face_Properties props; int name_count; @@ -1839,9 +1290,10 @@ void i_tt_dump_names(TT_Fonthandle *handle) { printf("'%s'\n", name); } } + fflush(stdout); } -int +size_t i_tt_glyph_name(TT_Fonthandle *handle, unsigned long ch, char *name_buf, size_t name_buf_size) { #ifdef FTXPOST @@ -1859,7 +1311,8 @@ i_tt_glyph_name(TT_Fonthandle *handle, unsigned long ch, char *name_buf, } if (handle->load_cond) { - i_push_errorf(rc, "error loading names (%d)", handle->load_cond); + i_push_errorf(handle->load_cond, "error loading names (%#x)", + (unsigned)handle->load_cond); return 0; } @@ -1889,6 +1342,24 @@ i_tt_glyph_name(TT_Fonthandle *handle, unsigned long ch, char *name_buf, #endif } +/* +=item i_tt_push_error(code) + +Push an error message and code onto the Imager error stack. + +=cut +*/ +static void +i_tt_push_error(TT_Error rc) { +#ifdef FTXERR18 + TT_String const *msg = TT_ErrToString18(rc); + + i_push_error(rc, msg); +#else + i_push_errorf(rc, "Error code 0x%04x", (unsigned)rc); +#endif +} + #endif /* HAVE_LIBTT */