From eeaa33fd90756291645114587135233d147749f2 Mon Sep 17 00:00:00 2001 From: Tony Cook Date: Sun, 5 May 2002 03:33:00 +0000 Subject: [PATCH] has_chars() support for freetype 1.x minor bug fixes --- Changes | 7 +++- Imager.xs | 37 ++++++++++++++-- TODO | 5 ++- font.c | 84 +++++++++++++++++++++++++++++++++---- freetyp2.c | 2 +- image.h | 1 + lib/Imager/Font/Truetype.pm | 11 +++++ t/t36oofont.t | 9 +++- 8 files changed, 137 insertions(+), 19 deletions(-) diff --git a/Changes b/Changes index 1cde5c98..35635f80 100644 --- a/Changes +++ b/Changes @@ -656,11 +656,14 @@ Revision history for Perl extension Imager. - some char * vs unsigned char * casts missing on OSF1 v4.0 - some enums had , on the last item in datatypes.h, which OSF1 didn't like - - Compaq C 6.4 (OSF1) claims to be C99 but doesn't provide + - Compaq C 6.4 (OSF1) claims to be C99 but doesn't provide stdint.h, don't try to use it under OSF - fix missing initialization in tags.c - Change i_draw to i_line and have it use Bresenham's line - drawing algorithm. + drawing algorithm. + - support has_chars() method for Freetype 1.x + - fixed log message for i_ft2_has_chars() + - fixed some broken checking for UTF8 in FT2 code ================================================================= diff --git a/Imager.xs b/Imager.xs index c7f9dfb8..341820ef 100644 --- a/Imager.xs +++ b/Imager.xs @@ -1825,6 +1825,36 @@ i_tt_bbox(handle,point,str_sv,len_ignored, utf8) PUSHs(sv_2mortal(newSViv(cords[5]))); } +void +i_tt_has_chars(handle, text_sv, utf8) + Imager::Font::TT handle + SV *text_sv + int utf8 + PREINIT: + char const *text; + STRLEN len; + char *work; + int count; + int i; + PPCODE: +#ifdef SvUTF8 + if (SvUTF8(text_sv)) + utf8 = 1; +#endif + text = SvPV(text_sv, len); + work = mymalloc(len); + count = i_tt_has_chars(handle, text, len, utf8, work); + if (GIMME_V == G_ARRAY) { + EXTEND(SP, count); + for (i = 0; i < count; ++i) { + PUSHs(sv_2mortal(newSViv(work[i]))); + } + } + else { + EXTEND(SP, 1); + PUSHs(sv_2mortal(newSVpv(work, count))); + } + myfree(work); #endif @@ -3975,8 +4005,9 @@ ft2_transform_box(font, x0, x1, x2, x3) PUSHs(sv_2mortal(newSViv(box[3]))); void -i_ft2_has_chars(handle, text, utf8) +i_ft2_has_chars(handle, text_sv, utf8) Imager::Font::FT2 handle + SV *text_sv int utf8 PREINIT: char *text; @@ -3986,10 +4017,10 @@ i_ft2_has_chars(handle, text, utf8) int i; PPCODE: #ifdef SvUTF8 - if (SvUTF8(ST(7))) + if (SvUTF8(text_sv)) utf8 = 1; #endif - text = SvPV(ST(1), len); + text = SvPV(text_sv, len); work = mymalloc(len); count = i_ft2_has_chars(handle, text, len, utf8, work); if (GIMME_V == G_ARRAY) { diff --git a/TODO b/TODO index a53f0816..1ab7a51a 100644 --- a/TODO +++ b/TODO @@ -137,8 +137,9 @@ Clean up: - try to clean up the inconsistencies between font types: - utf8 (even if we just treat characters over 0xFF as missing for T1) - - transformations - - has_char() method + (done for FT2, FT1) + - transformations (done for FT2) + - has_char() method (done for FT2, FT1) Format specific issues: - provide patches for libgif and libungif that fix their bugs diff --git a/font.c b/font.c index 41075266..3fb111ff 100644 --- a/font.c +++ b/font.c @@ -29,7 +29,7 @@ font.c - implements font handling functions for t1 and truetype fonts #ifdef HAVE_LIBTT handle = i_tt_new(path_to_ttf); - rc = i_tt_bbox(handle, points, "foo", 3, int cords[6]); + rc = i_tt_bbox(handle, points, "foo", 3, int cords[6], utf8); i_tt_destroy(handle); // and much more @@ -837,6 +837,7 @@ i_tt_get_glyph( TT_Fonthandle *handle, int inst, unsigned long 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 )); + 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)) ) { @@ -844,6 +845,7 @@ i_tt_get_glyph( TT_Fonthandle *handle, int inst, unsigned long j) { /* Don't leak */ TT_Done_Glyph( handle->instanceh[inst].glyphs[TT_HASH(j)].glyph ); USTRCT( handle->instanceh[inst].glyphs[TT_HASH(j)].glyph ) = NULL; + i_push_error(error, "TT_Load_Glyph()"); return 0; } @@ -858,12 +860,62 @@ i_tt_get_glyph( TT_Fonthandle *handle, int inst, unsigned long j) { 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; + i_push_error(error, "TT_Get_Glyph_Metrics()"); return 0; } return 1; } +/* +=item i_tt_has_chars(handle, 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). + +Returns the number of characters that were checked. + +=cut +*/ + +int +i_tt_has_chars(TT_Fonthandle *handle, char const *text, int len, int utf8, + char *out) { + int count = 0; + int inst; + mm_log((1, "i_ft2_has_chars(handle %p, text %p, len %d, utf8 %d)\n", + handle, text, len, utf8)); + + 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 (TT_VALID(handle->char_map)) { + index = TT_Char_Index(handle->char_map, c); + } + else { + index = (c - ' ' + 1) < 0 ? 0 : (c - ' ' + 1); + if (index >= handle->properties.num_Glyphs) + index = 0; + } + *out++ = index != 0; + ++count; + } + + return count; +} /* =item i_tt_destroy(handle) @@ -961,13 +1013,15 @@ 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 ) { +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 ) { 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)\n", - handle, inst, bit, small_bit, len, txt, len, smooth)); + 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)); /* y=-( handle->properties.horizontal->Descender * handle->instanceh[inst].imetrics.y_ppem )/(handle->properties.header->Units_Per_EM); @@ -1125,7 +1179,9 @@ i_tt_rasterize( TT_Fonthandle *handle, TT_Raster_Map *bit, int cords[6], float p } /* calculate bounding box */ - i_tt_bbox_inst( handle, inst, txt, len, cords, 0 ); + if (!i_tt_bbox_inst( handle, inst, txt, len, cords, utf8 )) + return 0; + width = cords[2]-cords[0]; height = cords[5]-cords[4]; @@ -1136,8 +1192,12 @@ i_tt_rasterize( TT_Fonthandle *handle, TT_Raster_Map *bit, int cords[6], float p i_tt_clear_raster_map( bit ); if ( smooth ) i_tt_init_raster_map( &small_bit, handle->instanceh[inst].imetrics.x_ppem + 32, height, smooth ); - i_tt_render_all_glyphs( handle, inst, bit, &small_bit, cords, txt, len, - smooth, utf8 ); + if (!i_tt_render_all_glyphs( handle, inst, bit, &small_bit, cords, txt, len, + smooth, utf8 )) { + if ( smooth ) + i_tt_done_raster_map( &small_bit ); + return 0; + } /* ascent = ( handle->properties.horizontal->Ascender * handle->instanceh[inst].imetrics.y_ppem ) / handle->properties.header->Units_Per_EM; */ @@ -1176,6 +1236,7 @@ i_tt_cp( TT_Fonthandle *handle, i_img *im, int xb, int yb, int channel, float po int ascent, st_offset; TT_Raster_Map bit; + i_clear_error(); if (! i_tt_rasterize( handle, &bit, cords, points, txt, len, smooth, utf8 ) ) return 0; ascent=cords[5]; @@ -1210,6 +1271,8 @@ i_tt_text( TT_Fonthandle *handle, i_img *im, int xb, int yb, i_color *cl, float int cords[6]; int ascent, st_offset; TT_Raster_Map bit; + + i_clear_error(); if (! i_tt_rasterize( handle, &bit, cords, points, txt, len, smooth, utf8 ) ) return 0; @@ -1275,7 +1338,8 @@ i_tt_bbox_inst( TT_Fonthandle *handle, int inst ,const char *txt, int len, int c casc = (gm->bbox.yMax+63) / 64; cdesc = (gm->bbox.yMin-63) / 64; - mm_log((1, "i_tt_box_inst: glyph='%c' casc=%d cdesc=%d\n", j, casc, cdesc)); + mm_log((1, "i_tt_box_inst: glyph='%c' casc=%d cdesc=%d\n", + ((j >= ' ' && j <= '~') ? j : '.'), casc, cdesc)); if (first) { start = gm->bbox.xMin / 64; @@ -1328,10 +1392,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) { 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)); if ( (inst=i_tt_get_instance(handle,points,-1)) < 0) { + i_push_errorf(0, "i_tt_get_instance(%g)", points); mm_log((1,"i_tt_text: get instance failed\n")); return 0; } diff --git a/freetyp2.c b/freetyp2.c index b24c83be..0b237910 100644 --- a/freetyp2.c +++ b/freetyp2.c @@ -787,7 +787,7 @@ Returns the number of characters that were checked. int i_ft2_has_chars(FT2_Fonthandle *handle, char const *text, int len, int utf8, char *out) { int count = 0; - mm_log((1, "i_ft2_check_chars(handle %p, text %p, len %d, utf8 %d)\n", + mm_log((1, "i_ft2_has_chars(handle %p, text %p, len %d, utf8 %d)\n", handle, text, len, utf8)); while (len) { diff --git a/image.h b/image.h index f18996b9..d2ff41a6 100644 --- a/image.h +++ b/image.h @@ -268,6 +268,7 @@ void i_tt_destroy( TT_Fonthandle *handle ); 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); 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); undef_int i_tt_bbox( TT_Fonthandle *handle, float points,char *txt,int len,int cords[6], int utf8); +int i_tt_has_chars(TT_Fonthandle *handle, char const *text, int len, int utf8, char *out); #endif /* End of freetype headers */ diff --git a/lib/Imager/Font/Truetype.pm b/lib/Imager/Font/Truetype.pm index 2bf14b81..3b985042 100644 --- a/lib/Imager/Font/Truetype.pm +++ b/lib/Imager/Font/Truetype.pm @@ -68,6 +68,17 @@ sub _bounding_box { sub utf8 { 1 } +# check if the font has the characters in the given string +sub has_chars { + my ($self, %hsh) = @_; + + unless (defined $hsh{string} && length $hsh{string}) { + $Imager::ERRSTR = "No string supplied to \$font->has_chars()"; + return; + } + return Imager::i_tt_has_chars($self->{id}, $hsh{string}, $hsh{'utf8'} || 0); +} + 1; __END__ diff --git a/t/t36oofont.t b/t/t36oofont.t index 2fe5b69a..2b4c5c84 100644 --- a/t/t36oofont.t +++ b/t/t36oofont.t @@ -12,7 +12,7 @@ use strict; # (It may become useful if the test is moved to ./t subdirectory.) my $loaded; -BEGIN { $| = 1; print "1..13\n"; } +BEGIN { $| = 1; print "1..16\n"; } END {print "not ok 1\n" unless $loaded;} use Imager; require "t/testtools.pl"; @@ -98,8 +98,13 @@ if (i_has_format("tt") and -f $fontname_tt) { okx($font->utf8, "make sure utf8 method returns true"); + my $has_chars = $font->has_chars(string=>"\x01A"); + okx($has_chars eq "\x00\x01", "has_chars scalar"); + my @has_chars = $font->has_chars(string=>"\x01A"); + okx(!$has_chars[0], "has_chars list 0"); + okx($has_chars[1], "has_chars list 1"); } else { - skipx(7, "FT1.x missing or disabled"); + skipx(10, "FT1.x missing or disabled"); } okx(1, "end"); -- 2.39.5