thread-safe T1lib interface
authorTony Cook <tony@develop-help.com>
Sun, 9 Sep 2012 01:43:11 +0000 (11:43 +1000)
committerTony Cook <tony@develop-help.com>
Sun, 9 Sep 2012 01:43:11 +0000 (11:43 +1000)
T1lib itself doesn't provide a thread-safe API, so we control access
to it via a mutex.

T1/T1.pm
T1/T1.xs
T1/imt1.c
T1/imt1.h
T1/t/t10type1.t
T1/typemap [new file with mode: 0644]

index 374fb5a..188fa0d 100644 (file)
--- a/T1/T1.pm
+++ b/T1/T1.pm
@@ -5,7 +5,7 @@ use vars qw(@ISA $VERSION);
 @ISA = qw(Imager::Font);
 
 BEGIN {
-  $VERSION = "1.017";
+  $VERSION = "1.018";
 
   require XSLoader;
   XSLoader::load('Imager::Font::T1', $VERSION);
@@ -19,13 +19,6 @@ my $t1aa;
 # $T1AA is in there because for some reason (probably cache related) antialiasing
 # is a system wide setting in t1 lib.
 
-sub t1_set_aa_level {
-  if (!defined $t1aa or $_[0] != $t1aa) {
-    i_t1_set_aa($_[0]);
-    $t1aa=$_[0];
-  }
-}
-
 sub new {
   my $class = shift;
   my %hsh=(color=>Imager::Color->new(255,0,0,255),
@@ -65,13 +58,13 @@ sub new {
          $hsh{afm} = 0;
   }
 
-  my $id = i_t1_new($hsh{file},$hsh{afm});
-  unless ($id >= 0) { # the low-level code may miss some error handling
+  my $font = Imager::Font::T1xs->new($hsh{file},$hsh{afm});
+  unless ($font) { # the low-level code may miss some error handling
     Imager->_set_error(Imager->_error_as_msg);
     return;
   }
   return bless {
-               id    => $id,
+               t1font    => $font,
                aa    => $hsh{aa} || 0,
                file  => $hsh{file},
                type  => 't1',
@@ -83,21 +76,20 @@ sub new {
 sub _draw {
   my $self = shift;
   my %input = @_;
-  t1_set_aa_level($input{aa});
   my $flags = '';
   $flags .= 'u' if $input{underline};
   $flags .= 's' if $input{strikethrough};
   $flags .= 'o' if $input{overline};
   if (exists $input{channel}) {
-    i_t1_cp($input{image}{IMG}, $input{'x'}, $input{'y'},
-                   $input{channel}, $self->{id}, $input{size},
+    $self->{t1font}->cp($input{image}{IMG}, $input{'x'}, $input{'y'},
+                   $input{channel}, $input{size},
                    $input{string}, length($input{string}), $input{align},
-                    $input{utf8}, $flags);
+                    $input{utf8}, $flags, $input{aa});
   } else {
-    i_t1_text($input{image}{IMG}, $input{'x'}, $input{'y'}, 
-                     $input{color}, $self->{id}, $input{size}, 
+    $self->{t1font}->text($input{image}{IMG}, $input{'x'}, $input{'y'}, 
+                     $input{color}, $input{size}, 
                      $input{string}, length($input{string}), 
-                     $input{align}, $input{utf8}, $flags);
+                     $input{align}, $input{utf8}, $flags, $input{aa});
   }
 
   return $self;
@@ -110,7 +102,7 @@ sub _bounding_box {
   $flags .= 'u' if $input{underline};
   $flags .= 's' if $input{strikethrough};
   $flags .= 'o' if $input{overline};
-  return i_t1_bbox($self->{id}, $input{size}, $input{string},
+  return $self->{t1font}->bbox($input{size}, $input{string},
                           length($input{string}), $input{utf8}, $flags);
 }
 
@@ -122,8 +114,8 @@ sub has_chars {
     $Imager::ERRSTR = "No string supplied to \$font->has_chars()";
     return;
   }
-  return i_t1_has_chars($self->{id}, $hsh{string}, 
-                               _first($hsh{'utf8'}, $self->{utf8}, 0));
+  return $self->{t1font}->has_chars($hsh{string}, 
+                                   _first($hsh{'utf8'}, $self->{utf8}, 0));
 }
 
 sub utf8 {
@@ -133,7 +125,7 @@ sub utf8 {
 sub face_name {
   my ($self) = @_;
 
-  i_t1_face_name($self->{id});
+  return $self->{t1font}->face_name();
 }
 
 sub glyph_names {
@@ -144,7 +136,7 @@ sub glyph_names {
     or return Imager->_set_error("no string parameter passed to glyph_names");
   my $utf8 = _first($input{utf8} || 0);
 
-  i_t1_glyph_name($self->{id}, $string, $utf8);
+  return $self->{t1font}->glyph_name($string, $utf8);
 }
 
 
index f587fb0..6330733 100644 (file)
--- a/T1/T1.xs
+++ b/T1/T1.xs
@@ -11,38 +11,43 @@ extern "C" {
 
 DEFINE_IMAGER_CALLBACKS;
 
+typedef i_t1_font_t Imager__Font__T1xs;
+
+#define i_t1_DESTROY(font) i_t1_destroy(font)
+
 MODULE = Imager::Font::T1  PACKAGE = Imager::Font::T1
 
 undef_int
 i_init_t1(t1log)
        int t1log
 
-void
-i_t1_set_aa(st)
-              int     st
+MODULE = Imager::Font::T1  PACKAGE = Imager::Font::T1xs PREFIX = i_t1_
 
-int
-i_t1_new(pfb,afm)
+Imager::Font::T1xs
+i_t1_new(class,pfb,afm)
                      char*    pfb
                      char*    afm
+  C_ARGS:
+    pfb, afm
 
-int
-i_t1_destroy(font_id)
-                      int     font_id
+void
+i_t1_DESTROY(font)
+ Imager::Font::T1xs font       
 
 
 undef_int
-i_t1_cp(im,xb,yb,channel,fontnum,points,str_sv,len_ignored,align,utf8=0,flags="")
+i_t1_cp(font,im,xb,yb,channel,points,str_sv, length(str),align,utf8=0,flags="",aa=1)
+ Imager::Font::T1xs     font
     Imager::ImgRaw     im
         i_img_dim     xb
         i_img_dim     yb
               int     channel
-              int     fontnum
             double     points
                SV*    str_sv
               int     align
                int     utf8
               char*    flags
+              int     aa
              PREINIT:
                char *str;
                STRLEN len;
@@ -52,15 +57,15 @@ i_t1_cp(im,xb,yb,channel,fontnum,points,str_sv,len_ignored,align,utf8=0,flags=""
                  utf8 = 1;
 #endif
                str = SvPV(str_sv, len);
-               RETVAL = i_t1_cp(im, xb,yb,channel,fontnum,points,str,len,align,
-                                  utf8,flags);
+               RETVAL = i_t1_cp(font, im, xb,yb,channel,points,str,len,align,
+                                  utf8,flags,aa);
            OUTPUT:
              RETVAL
 
 
 void
 i_t1_bbox(fontnum,point,str_sv,len_ignored,utf8=0,flags="")
              int     fontnum
Imager::Font::T1xs     fontnum
            double     point
                SV*    str_sv
                int     utf8
@@ -87,17 +92,18 @@ i_t1_bbox(fontnum,point,str_sv,len_ignored,utf8=0,flags="")
 
 
 undef_int
-i_t1_text(im,xb,yb,cl,fontnum,points,str_sv,len_ignored,align,utf8=0,flags="")
+i_t1_text(font,im,xb,yb,cl,points,str_sv,length(str),align,utf8=0,flags="",aa=1)
+ Imager::Font::T1xs font
     Imager::ImgRaw     im
         i_img_dim     xb
         i_img_dim     yb
      Imager::Color    cl
-              int     fontnum
             double     points
                SV*    str_sv
               int     align
                int     utf8
-              char*    flags
+        const char*    flags
+              int     aa
              PREINIT:
                char *str;
                STRLEN len;
@@ -107,14 +113,14 @@ i_t1_text(im,xb,yb,cl,fontnum,points,str_sv,len_ignored,align,utf8=0,flags="")
                  utf8 = 1;
 #endif
                str = SvPV(str_sv, len);
-               RETVAL = i_t1_text(im, xb,yb,cl,fontnum,points,str,len,align,
-                                  utf8,flags);
+               RETVAL = i_t1_text(font,im, xb,yb,cl,points,str,len,align,
+                                  utf8,flags,aa);
            OUTPUT:
              RETVAL
 
 void
-i_t1_has_chars(handle, text_sv, utf8 = 0)
-        int handle
+i_t1_has_chars(font, text_sv, utf8 = 0)
+ Imager::Font::T1xs font
         SV  *text_sv
         int utf8
       PREINIT:
@@ -130,9 +136,10 @@ i_t1_has_chars(handle, text_sv, utf8 = 0)
 #endif
         text = SvPV(text_sv, len);
         work = mymalloc(len);
-        count = i_t1_has_chars(handle, text, len, utf8, work);
+        count = i_t1_has_chars(font, text, len, utf8, work);
         if (GIMME_V == G_ARRAY) {
           EXTEND(SP, count);
+
           for (i = 0; i < count; ++i) {
             PUSHs(boolSV(work[i]));
           }
@@ -144,21 +151,21 @@ i_t1_has_chars(handle, text_sv, utf8 = 0)
         myfree(work);
 
 void
-i_t1_face_name(handle)
-        int handle
+i_t1_face_name(font)
+ Imager::Font::T1xs font
       PREINIT:
         char name[255];
         int len;
       PPCODE:
-        len = i_t1_face_name(handle, name, sizeof(name));
+        len = i_t1_face_name(font, name, sizeof(name));
         if (len) {
           EXTEND(SP, 1);
           PUSHs(sv_2mortal(newSVpv(name, strlen(name))));
         }
 
 void
-i_t1_glyph_name(handle, text_sv, utf8 = 0)
-        int handle
+i_t1_glyph_name(font, text_sv, utf8 = 0)
+ Imager::Font::T1xs font
         SV *text_sv
         int utf8
       PREINIT:
@@ -187,7 +194,7 @@ i_t1_glyph_name(handle, text_sv, utf8 = 0)
             --len;
           }
           EXTEND(SP, 1);
-          if (i_t1_glyph_name(handle, ch, name, sizeof(name))) {
+          if (i_t1_glyph_name(font, ch, name, sizeof(name))) {
             PUSHs(sv_2mortal(newSVpv(name, 0)));
           }
           else {
@@ -197,3 +204,4 @@ i_t1_glyph_name(handle, text_sv, utf8 = 0)
 
 BOOT:
        PERL_INITIALIZE_IMAGER_CALLBACKS;
+       i_t1_start();
\ No newline at end of file
index 3027e42..41f1255 100644 (file)
--- a/T1/imt1.c
+++ b/T1/imt1.c
@@ -5,11 +5,33 @@
 
 static int t1_get_flags(char const *flags);
 static char *t1_from_utf8(char const *in, size_t len, int *outlen);
-
+static undef_int i_init_t1_low(int t1log);
 static void t1_push_error(void);
+static void i_t1_set_aa(int st);
 
 static int t1_active_fonts = 0;
 static int t1_initialized = 0;
+static int t1_aa = 0;
+
+struct i_t1_font_tag {
+  int font_id;
+};
+
+static i_mutex_t mutex;
+
+/*
+=item i_t1_start()
+
+Initialize the font driver.  This does not actually initialize T1Lib,
+it just allocates the mutex we use to gate access to it.
+
+=cut
+*/
+
+void
+i_t1_start(void) {
+  mutex = i_mutex_new();
+}
 
 /* 
 =item i_init_t1(t1log)
@@ -21,6 +43,18 @@ Initializes the t1lib font rendering engine.
 
 undef_int
 i_init_t1(int t1log) {
+  undef_int result;
+  i_mutex_lock(mutex);
+
+  result = i_init_t1_low(t1log);
+
+  i_mutex_unlock(mutex);
+
+  return result;
+}
+
+static undef_int
+i_init_t1_low(int t1log) {
   int init_flags = IGNORE_CONFIGFILE|IGNORE_FONTDATABASE;
   mm_log((1,"init_t1()\n"));
 
@@ -64,8 +98,10 @@ Shuts the t1lib font rendering engine down.
 
 void
 i_close_t1(void) {
+  i_mutex_lock(mutex);
   T1_CloseLib();
   t1_initialized = 0;
+  i_mutex_unlock(mutex);
 }
 
 
@@ -80,21 +116,27 @@ Loads the fonts with the given filenames, returns its font id
 =cut
 */
 
-int
+i_t1_font_t
 i_t1_new(char *pfb,char *afm) {
   int font_id;
+  i_t1_font_t font;
+
+  i_mutex_lock(mutex);
 
   i_clear_error();
 
-  if (!t1_initialized && i_init_t1(0))
-    return -1;
+  if (!t1_initialized && i_init_t1_low(0)) {
+    i_mutex_unlock(mutex);
+    return NULL;
+  }
 
   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));
     t1_push_error();
-    return font_id;
+    i_mutex_unlock(mutex);
+    return NULL;
   }
   
   if (afm != NULL) {
@@ -107,33 +149,48 @@ i_t1_new(char *pfb,char *afm) {
     t1_push_error();
     i_push_error(0, "loading font");
     T1_DeleteFont(font_id);
-    return -1;
+    i_mutex_unlock(mutex);
+    return NULL;
   }
 
   ++t1_active_fonts;
 
   mm_log((1, "i_t1_new() -> %d\n", font_id));
 
-  return font_id;
+  i_mutex_unlock(mutex);
+
+  font = mymalloc(sizeof(*font));
+  font->font_id = font_id;
+
+  return font;
 }
 
 /*
-=item i_t1_destroy(font_id)
+=item i_t1_destroy(font)
 
 Frees resources for a t1 font with given font id.
 
-   font_id - number of the font to free
+   font - font to free
 
 =cut
 */
 
 int
-i_t1_destroy(int font_id) {
-  mm_log((1,"i_t1_destroy(font_id %d)\n",font_id));
+i_t1_destroy(i_t1_font_t font) {
+  int result;
+
+  i_mutex_lock(mutex);
+
+  mm_log((1,"i_t1_destroy(font_id %d)\n",font->font_id));
 
   --t1_active_fonts;
 
-  return T1_DeleteFont(font_id);
+  result = T1_DeleteFont(font->font_id);
+  myfree(font);
+
+  i_mutex_unlock(mutex);
+
+  return result;
 }
 
 
@@ -144,13 +201,19 @@ Sets the antialiasing level of the t1 library.
 
    st - 0 =  NONE, 1 = LOW, 2 =  HIGH.
 
+Must be called with the mutex locked.
+
 =cut
 */
 
-void
+static void
 i_t1_set_aa(int st) {
   int i;
   unsigned long cst[17];
+
+  if (t1_aa == st)
+    return;
+
   switch(st) {
   case 0:
     T1_AASetBitsPerPixel( 8 );
@@ -171,11 +234,13 @@ i_t1_set_aa(int st) {
     T1_AAHSetGrayValues( cst );
     mm_log((1,"setting T1 antialias to high\n"));
   }
+  
+  t1_aa = st;
 }
 
 
 /* 
-=item i_t1_cp(im, xb, yb, channel, fontnum, points, str, len, align)
+=item i_t1_cp(im, xb, yb, channel, fontnum, points, str, len, align,aa)
 
 Interface to text rendering into a single channel in an image
 
@@ -188,21 +253,27 @@ Interface to text rendering into a single channel in an image
    str     - string to render
    len     - string length
    align   - (0 - top of font glyph | 1 - baseline )
+   aa      - anti-aliasing
 
 =cut
 */
 
 undef_int
-i_t1_cp(i_img *im,i_img_dim xb,i_img_dim yb,int channel,int fontnum,double points,char* str,size_t len,int align, int utf8, char const *flags) {
+i_t1_cp(i_t1_font_t font, i_img *im,i_img_dim xb,i_img_dim yb,int channel,double points,char* str,size_t len,int align, int utf8, char const *flags, int aa) {
   GLYPH *glyph;
   int xsize,ysize,x,y;
   i_color val;
   int mod_flags = t1_get_flags(flags);
+  int fontnum = font->font_id;
 
   unsigned int ch_mask_store;
   
   if (im == NULL) { mm_log((1,"i_t1_cp: Null image in input\n")); return(0); }
 
+  i_mutex_lock(mutex);
+
+  i_t1_set_aa(aa);
+
   if (utf8) {
     int worklen;
     char *work = t1_from_utf8(str, len, &worklen);
@@ -212,8 +283,10 @@ i_t1_cp(i_img *im,i_img_dim xb,i_img_dim yb,int channel,int fontnum,double point
   else {
     glyph=T1_AASetString( fontnum, str, len, 0, mod_flags, points, NULL);
   }
-  if (glyph == NULL)
+  if (glyph == NULL) {
+    i_mutex_unlock(mutex);
     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));
@@ -236,6 +309,9 @@ i_t1_cp(i_img *im,i_img_dim xb,i_img_dim yb,int channel,int fontnum,double point
   }
   
   im->ch_mask=ch_mask_store;
+
+  i_mutex_unlock(mutex);
+
   return 1;
 }
 
@@ -267,12 +343,17 @@ function to get a strings bounding box given the font id and sizes
 */
 
 int
-i_t1_bbox(int fontnum, double points,const char *str,size_t len, i_img_dim cords[6], int utf8,char const *flags) {
+i_t1_bbox(i_t1_font_t font, double points,const char *str,size_t len, i_img_dim cords[6], int utf8,char const *flags) {
   BBox bbox;
   BBox gbbox;
   int mod_flags = t1_get_flags(flags);
   i_img_dim advance;
-  int space_position = T1_GetEncodingIndex(fontnum, "space");
+  int fontnum = font->font_id;
+  int space_position;
+
+  i_mutex_lock(mutex);
+
+  space_position = T1_GetEncodingIndex(fontnum, "space");
   
   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 */ 
@@ -322,12 +403,14 @@ i_t1_bbox(int fontnum, double points,const char *str,size_t len, i_img_dim cords
   cords[BBOX_RIGHT_BEARING] = 
     cords[BBOX_ADVANCE_WIDTH] - cords[BBOX_POS_WIDTH];
 
+  i_mutex_unlock(mutex);
+
   return BBOX_RIGHT_BEARING+1;
 }
 
 
 /*
-=item i_t1_text(im, xb, yb, cl, fontnum, points, str, len, align)
+=item i_t1_text(im, xb, yb, cl, fontnum, points, str, len, align, aa)
 
 Interface to text rendering in a single color onto an image
 
@@ -340,19 +423,25 @@ Interface to text rendering in a single color onto an image
    str     - char pointer to string to render
    len     - string length
    align   - (0 - top of font glyph | 1 - baseline )
+   aa      - anti-aliasing level
 
 =cut
 */
 
 undef_int
-i_t1_text(i_img *im, i_img_dim xb, i_img_dim yb,const i_color *cl,int fontnum, double points,const char* str,size_t len,int align, int utf8, char const *flags) {
+i_t1_text(i_t1_font_t font, i_img *im, i_img_dim xb, i_img_dim yb,const i_color *cl, double points,const char* str,size_t len,int align, int utf8, char const *flags, int aa) {
   GLYPH *glyph;
   int xsize,ysize,y;
   int mod_flags = t1_get_flags(flags);
   i_render *r;
+  int fontnum = font->font_id;
 
   if (im == NULL) { mm_log((1,"i_t1_cp: Null image in input\n")); return(0); }
 
+  i_mutex_lock(mutex);
+
+  i_t1_set_aa(aa);
+
   if (utf8) {
     int worklen;
     char *work = t1_from_utf8(str, len, &worklen);
@@ -363,8 +452,10 @@ i_t1_text(i_img *im, i_img_dim xb, i_img_dim yb,const i_color *cl,int fontnum, d
     /* T1_AASetString() accepts a char * not a const char */
     glyph=T1_AASetString( fontnum, (char *)str, len, 0, mod_flags, points, NULL);
   }
-  if (glyph == NULL)
+  if (glyph == NULL) {
+    i_mutex_unlock(mutex);
     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));
@@ -383,6 +474,8 @@ i_t1_text(i_img *im, i_img_dim xb, i_img_dim yb,const i_color *cl,int fontnum, d
     i_render_color(r, xb, yb+y, xsize, (unsigned char *)glyph->bits+y*xsize, cl);
   }
   i_render_delete(r);
+
+  i_mutex_unlock(mutex);
     
   return 1;
 }
@@ -467,16 +560,20 @@ Returns the number of characters that were checked.
 */
 
 int
-i_t1_has_chars(int font_num, const char *text, size_t len, int utf8,
+i_t1_has_chars(i_t1_font_t font, const char *text, size_t len, int utf8,
                char *out) {
   int count = 0;
+  int font_num = font->font_id;
   
+  i_mutex_lock(mutex);
+
   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();
+    i_mutex_unlock(mutex);
     return 0;
   }
 
@@ -486,6 +583,7 @@ i_t1_has_chars(int font_num, const char *text, size_t len, int utf8,
       c = i_utf8_advance(&text, &len);
       if (c == ~0UL) {
         i_push_error(0, "invalid UTF8 character");
+       i_mutex_unlock(mutex);
         return 0;
       }
     }
@@ -512,11 +610,13 @@ i_t1_has_chars(int font_num, const char *text, size_t len, int utf8,
     ++count;
   }
 
+  i_mutex_unlock(mutex);
+
   return count;
 }
 
 /*
-=item i_t1_face_name(font_num, name_buf, name_buf_size)
+=item i_t1_face_name(font, name_buf, name_buf_size)
 
 Copies the face name of the given C<font_num> to C<name_buf>.  Returns
 the number of characters required to store the name (which can be
@@ -530,53 +630,68 @@ will be truncated.  name_buf will always be NUL termintaed.
 */
 
 int
-i_t1_face_name(int font_num, char *name_buf, size_t name_buf_size) {
+i_t1_face_name(i_t1_font_t font, char *name_buf, size_t name_buf_size) {
   char *name;
+  int font_num = font->font_id;
+
+  i_mutex_lock(mutex);
 
   T1_errno = 0;
   if (T1_LoadFont(font_num)) {
     t1_push_error();
+    i_mutex_unlock(mutex);
     return 0;
   }
   name = T1_GetFontName(font_num);
 
   if (name) {
+    size_t len = strlen(name);
     strncpy(name_buf, name, name_buf_size);
     name_buf[name_buf_size-1] = '\0';
-    return strlen(name) + 1;
+    i_mutex_unlock(mutex);
+    return len + 1;
   }
   else {
     t1_push_error();
+    i_mutex_unlock(mutex);
     return 0;
   }
 }
 
 int
-i_t1_glyph_name(int font_num, unsigned long ch, char *name_buf, 
+i_t1_glyph_name(i_t1_font_t font, unsigned long ch, char *name_buf, 
                  size_t name_buf_size) {
   char *name;
+  int font_num = font->font_id;
 
+  i_mutex_lock(mutex);
   i_clear_error();
   if (ch > 0xFF) {
+    i_mutex_unlock(mutex);
     return 0;
   }
   if (T1_LoadFont(font_num)) {
     t1_push_error();
+    i_mutex_unlock(mutex);
     return 0;
   }
   name = T1_GetCharName(font_num, (unsigned char)ch);
   if (name) {
     if (strcmp(name, ".notdef")) {
+      size_t len = strlen(name);
       strncpy(name_buf, name, name_buf_size);
       name_buf[name_buf_size-1] = '\0';
-      return strlen(name) + 1;
+      i_mutex_unlock(mutex);
+      return len + 1;
     }
     else {
+      i_mutex_unlock(mutex);
       return 0;
     }
   }
   else {
     t1_push_error();
+    i_mutex_unlock(mutex);
     return 0;
   }
 }
index 489bcef..5783e05 100644 (file)
--- a/T1/imt1.h
+++ b/T1/imt1.h
@@ -3,38 +3,40 @@
 
 #include "imdatatypes.h"
 
+typedef struct i_t1_font_tag *i_t1_font_t;
+
+extern void
+i_t1_start(void);
+
 extern undef_int
 i_init_t1(int t1log);
 
 extern void
 i_close_t1(void);
 
-extern int
+extern i_t1_font_t
 i_t1_new(char *pfb,char *afm);
 
 extern int
-i_t1_destroy(int font_id);
-
-extern void
-i_t1_set_aa(int st);
+i_t1_destroy(i_t1_font_t font);
 
 extern undef_int
-i_t1_cp(i_img *im,i_img_dim xb,i_img_dim yb,int channel,int fontnum,double points,char* str,size_t len,int align, int utf8, char const *flags);
+i_t1_cp(i_t1_font_t font, i_img *im,i_img_dim xb,i_img_dim yb,int channel,double points,char* str,size_t len,int align, int utf8, char const *flags, int aa);
 
 extern int
-i_t1_bbox(int fontnum,double points,const char *str,size_t len,i_img_dim *cords, int utf8,char const *flags);
+i_t1_bbox(i_t1_font_t font,double points,const char *str,size_t len,i_img_dim *cords, int utf8,char const *flags);
 
 extern undef_int
-i_t1_text(i_img *im,i_img_dim xb,i_img_dim yb,const i_color *cl,int fontnum,double points,const char* str,size_t len,int align, int utf8, char const *flags);
+i_t1_text(i_t1_font_t font, i_img *im,i_img_dim xb,i_img_dim yb,const i_color *cl,double points,const char* str,size_t len,int align, int utf8, char const *flags, int aa);
 
 extern int
-i_t1_has_chars(int font_num, const char *text, size_t len, int utf8,
+i_t1_has_chars(i_t1_font_t font, const char *text, size_t len, int utf8,
                char *out);
 
 extern int
-i_t1_face_name(int font_num, char *name_buf, size_t name_buf_size);
+i_t1_face_name(i_t1_font_t font, char *name_buf, size_t name_buf_size);
 
 extern int
-i_t1_glyph_name(int font_num, unsigned long ch, char *name_buf, 
+i_t1_glyph_name(i_t1_font_t font, unsigned long ch, char *name_buf, 
                size_t name_buf_size);
 #endif
index 8e23561..ec36749 100644 (file)
@@ -8,7 +8,7 @@ use Cwd qw(getcwd abs_path);
 
 #$Imager::DEBUG=1;
 
-plan tests => 97;
+plan tests => 96;
 
 ok($Imager::formats{t1}, "must have t1");
 
@@ -40,7 +40,7 @@ SKIP:
   init(t1log=>0);
   unlink "t1lib.log";
 
-  my $fnum=Imager::Font::T1::i_t1_new($fontname_pfb,$fontname_afm); # this will load the pfb font
+  my $fnum=Imager::Font::T1xs->new($fontname_pfb,$fontname_afm); # this will load the pfb font
   unless (ok($fnum >= 0, "load font $fontname_pfb")) {
     skip("without the font I can't do a thing", 90);
   }
@@ -48,11 +48,11 @@ SKIP:
   my $bgcolor=Imager::Color->new(255,0,0,0);
   my $overlay=Imager::ImgRaw::new(200,70,3);
   
-  ok(Imager::Font::T1::i_t1_cp($overlay,5,50,1,$fnum,50.0,'XMCLH',5,1), "i_t1_cp");
+  ok($fnum->cp($overlay,5,50,1,50.0,'XMCLH',5,1), "i_t1_cp");
 
   i_line($overlay,0,50,100,50,$bgcolor,1);
 
-  my @bbox=Imager::Font::T1::i_t1_bbox(0,50.0,'XMCLH',5);
+  my @bbox=$fnum->bbox(50.0,'XMCLH',5);
   is(@bbox, 8, "i_t1_bbox");
   print "# bbox: ($bbox[0], $bbox[1]) - ($bbox[2], $bbox[3])\n";
 
@@ -65,8 +65,7 @@ SKIP:
   $bgcolor=Imager::Color::set($bgcolor,200,200,200,0);
   my $backgr=Imager::ImgRaw::new(280,300,3);
 
-  Imager::Font::T1::i_t1_set_aa(2);
-  ok(Imager::Font::T1::i_t1_text($backgr,10,100,$bgcolor,$fnum,150.0,'test',4,1), "i_t1_text");
+  ok($fnum->text($backgr,10,100,$bgcolor,150.0,'test',4,1,2), "i_t1_text");
 
   # "UTF8" tests
   # for perl < 5.6 we can hand-encode text
@@ -77,9 +76,9 @@ SKIP:
   my $text = pack("C*", 0x41, 0xC2, 0xA1, 0xE2, 0x80, 0x90, 0x41);
   my $alttext = "A\xA1A";
   
-  my @utf8box = Imager::Font::T1::i_t1_bbox($fnum, 50.0, $text, length($text), 1);
+  my @utf8box = $fnum->bbox(50.0, $text, length($text), 1);
   is(@utf8box, 8, "utf8 bbox element count");
-  my @base = Imager::Font::T1::i_t1_bbox($fnum, 50.0, $alttext, length($alttext), 0);
+  my @base = $fnum->bbox(50.0, $alttext, length($alttext), 0);
   is(@base, 8, "alt bbox element count");
   my $maxdiff = $fontname_pfb eq $deffont ? 0 : $base[2] / 3;
   print "# (@utf8box vs @base)\n";
@@ -87,9 +86,9 @@ SKIP:
       "compare box sizes $utf8box[2] vs $base[2] (maxerror $maxdiff)");
 
   # hand-encoded UTF8 drawing
-  ok(Imager::Font::T1::i_t1_text($backgr, 10, 140, $bgcolor, $fnum, 32, $text, length($text), 1,1), "draw hand-encoded UTF8");
+  ok($fnum->text($backgr, 10, 140, $bgcolor, 32, $text, length($text), 1,1), "draw hand-encoded UTF8");
 
-  ok(Imager::Font::T1::i_t1_cp($backgr, 80, 140, 1, $fnum, 32, $text, length($text), 1, 1), 
+  ok($fnum->cp($backgr, 80, 140, 1, 32, $text, length($text), 1, 1), 
       "cp hand-encoded UTF8");
 
   # ok, try native perl UTF8 if available
@@ -101,16 +100,16 @@ SKIP:
     # versions
     eval q{$text = "A\xA1\x{2010}A"}; # A, a with ogonek, HYPHEN, A in our test font
     #$text = "A".chr(0xA1).chr(0x2010)."A"; # this one works too
-    ok(Imager::Font::T1::i_t1_text($backgr, 10, 180, $bgcolor, $fnum, 32, $text, length($text), 1),
+    ok($fnum->text($backgr, 10, 180, $bgcolor, 32, $text, length($text), 1),
         "draw UTF8");
-    ok(Imager::Font::T1::i_t1_cp($backgr, 80, 180, 1, $fnum, 32, $text, length($text), 1),
+    ok($fnum->cp($backgr, 80, 180, 1, 32, $text, length($text), 1),
         "cp UTF8");
-    @utf8box = Imager::Font::T1::i_t1_bbox($fnum, 50.0, $text, length($text), 0);
+    @utf8box = $fnum->bbox(50.0, $text, length($text), 0);
     is(@utf8box, 8, "native utf8 bbox element count");
     ok(abs($utf8box[2] - $base[2]) <= $maxdiff, 
       "compare box sizes native $utf8box[2] vs $base[2] (maxerror $maxdiff)");
     eval q{$text = "A\xA1\xA2\x01\x1F\x{0100}A"};
-    ok(Imager::Font::T1::i_t1_text($backgr, 10, 220, $bgcolor, $fnum, 32, $text, 0, 1, 0, "uso"),
+    ok($fnum->text($backgr, 10, 220, $bgcolor, 32, $text, 0, 1, 0, "uso"),
        "more complex output");
   }
 
@@ -120,13 +119,7 @@ SKIP:
   i_writeppm_wiol($backgr, $IO);
   close(FH);
 
-  my $rc=Imager::Font::T1::i_t1_destroy($fnum);
-  unless (ok($rc >= 0, "i_t1_destroy")) {
-    print "# i_t1_destroy failed: rc=$rc\n";
-  }
-
-  print "# debug: ",join(" x ",Imager::Font::T1::i_t1_bbox(0,50,"eses",4) ),"\n";
-  print "# debug: ",join(" x ",Imager::Font::T1::i_t1_bbox(0,50,"llll",4) ),"\n";
+  undef $fnum;
 
   # character existance tests - uses the special ExistenceTest font
   my $exists_font = 'fontfiles/ExistenceTest.pfb';
@@ -134,22 +127,22 @@ SKIP:
   
   -e $exists_font or die "$exists_font not found";
     
-  my $font_num = Imager::Font::T1::i_t1_new($exists_font, $exists_afm);
+  my $font_num = Imager::Font::T1xs->new($exists_font, $exists_afm);
   SKIP: {
     ok($font_num >= 0, 'loading test font')
       or skip('Could not load test font', 6);
     # first the list interface
-    my @exists = Imager::Font::T1::i_t1_has_chars($font_num, "!A");
+    my @exists = $font_num->has_chars("!A");
     is(@exists, 2, "return count from has_chars");
     ok($exists[0], "we have an exclamation mark");
     ok(!$exists[1], "we have no uppercase A");
 
     # then the scalar interface
-    my $exists = Imager::Font::T1::i_t1_has_chars($font_num, "!A");
+    my $exists = $font_num->has_chars("!A");
     is(length($exists), 2, "return scalar length");
     ok(ord(substr($exists, 0, 1)), "we have an exclamation mark");
     ok(!ord(substr($exists, 1, 1)), "we have no upper-case A");
-    Imager::Font::T1::i_t1_destroy($font_num);
+    undef $font_num;
   }
   
   my $font = Imager::Font->new(file=>$exists_font, type=>'t1');
@@ -174,7 +167,7 @@ SKIP:
     isnt($bbox[2], $bbox[5], "different advance to pos_width");
 
     # names
-    my $face_name = Imager::Font::T1::i_t1_face_name($font->{id});
+    my $face_name = $font->{t1font}->face_name();
     print "# face $face_name\n";
     is($face_name, 'ExistenceTest', "face name");
     $face_name = $font->face_name;
diff --git a/T1/typemap b/T1/typemap
new file mode 100644 (file)
index 0000000..95e197e
--- /dev/null
@@ -0,0 +1 @@
+Imager::Font::T1xs     T_PTROBJ