]> git.imager.perl.org - imager.git/commitdiff
has_chars() support for freetype 1.x
authorTony Cook <tony@develop=help.com>
Sun, 5 May 2002 03:33:00 +0000 (03:33 +0000)
committerTony Cook <tony@develop=help.com>
Sun, 5 May 2002 03:33:00 +0000 (03:33 +0000)
minor bug fixes

Changes
Imager.xs
TODO
font.c
freetyp2.c
image.h
lib/Imager/Font/Truetype.pm
t/t36oofont.t

diff --git a/Changes b/Changes
index 1cde5c9819c439bee16138b325a05f50b221bee5..35635f807e213324001c271d8db75a26cd422739 100644 (file)
--- 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
         - 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
           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
 
 =================================================================
 
 
 =================================================================
 
index c7f9dfb8a8eb0cabbe2986ef4a746ff1ea05c606..341820efcaaf805f158e417f8f368bb5380abea3 100644 (file)
--- 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])));
                }
 
                  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 
 
 
 #endif 
 
@@ -3975,8 +4005,9 @@ ft2_transform_box(font, x0, x1, x2, x3)
           PUSHs(sv_2mortal(newSViv(box[3])));
 
 void
           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
         Imager::Font::FT2 handle
+        SV  *text_sv
         int utf8
       PREINIT:
         char *text;
         int utf8
       PREINIT:
         char *text;
@@ -3986,10 +4017,10 @@ i_ft2_has_chars(handle, text, utf8)
         int i;
       PPCODE:
 #ifdef SvUTF8
         int i;
       PPCODE:
 #ifdef SvUTF8
-        if (SvUTF8(ST(7)))
+        if (SvUTF8(text_sv))
           utf8 = 1;
 #endif
           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) {
         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 a53f0816f6076ef2873496e4e6e8ddda63df7c5f..1ab7a51a7acabb0ea5d161f91059068876c459dd 100644 (file)
--- 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)
 
 - 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
 
 Format specific issues:
 - provide patches for libgif and libungif that fix their bugs
diff --git a/font.c b/font.c
index 410752661ae60eea83ddb54f45f0c6fade760a2d..3fb111ffb126a20b990f68f55fd5c956a32ffef5 100644 (file)
--- 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);
 
   #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
   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 ));
   
   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)) ) {
     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;
     /* 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;
   }
 
     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;
     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;
 }
 
     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)
 
 /* 
 =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
 
 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;
   
   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);
   
   /* 
      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 */
   }
   
   /* 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];
   
   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_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; */
   
 
   /*  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;
   
   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];
   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;
   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;
   
   
   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;
 
       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;
 
       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;
 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) {
   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;
   }
     mm_log((1,"i_tt_text: get instance failed\n"));
     return 0;
   }
index b24c83be3ab48d4029125a3e39e4b0f3d07e26ce..0b23791034d4f5ab70ae9e37d8099b782779c458 100644 (file)
@@ -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;
 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) {
          handle, text, len, utf8));
 
   while (len) {
diff --git a/image.h b/image.h
index f18996b9986e6ebbe869a8ada76aad5a2dc25a25..d2ff41a6629c1e9807bf9a54be5989b84a707d98 100644 (file)
--- 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);
 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 */
 
 
 #endif  /* End of freetype headers */
 
index 2bf14b815c7cb8226d93514d238b104d87650cd2..3b98504236c7e337dbd90ba854dd751f964638fd 100644 (file)
@@ -68,6 +68,17 @@ sub _bounding_box {
 
 sub utf8 { 1 }
 
 
 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__
 1;
 
 __END__
index 2fe5b69ac059d1575a9eed082567b1ef6f9b1b8b..2b4c5c84c0bc27f1193093faa990f1256860c32b 100644 (file)
@@ -12,7 +12,7 @@ use strict;
 # (It may become useful if the test is moved to ./t subdirectory.)
 
 my $loaded;
 # (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";
 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");
 
 
   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 {
 } else {
-  skipx(7, "FT1.x missing or disabled");
+  skipx(10, "FT1.x missing or disabled");
 }
 
 okx(1, "end");
 }
 
 okx(1, "end");