fix for rt 62855
authorTony Cook <tony@develop=help.com>
Thu, 11 Nov 2010 11:07:48 +0000 (11:07 +0000)
committerTony Cook <tony@develop=help.com>
Thu, 11 Nov 2010 11:07:48 +0000 (11:07 +0000)
Changes
MANIFEST
lib/Imager/Font.pm
t/GoodTestFont.pm [new file with mode: 0644]
t/t31font.t [new file with mode: 0644]

diff --git a/Changes b/Changes
index f077dcf96c1f54936ce34337baef9891eb3f8fca..b155d02d08e8a55ce59291b4490f7fcaf936c3ad 100644 (file)
--- a/Changes
+++ b/Changes
@@ -21,6 +21,10 @@ Bug fixes:
 
  - treat the co-efficients for convert() as doubles instead of floats.
 
+ - If a higher (earlier) priority font failed to load, that would
+   crash preventing loading of later fonts.
+   https://rt.cpan.org/Ticket/Display.html?id=62855
+
 Imager 0.78 - 4 Oct 2010
 ===========
 
index 08f408a04d12362a407f3a18d8c1648841cd067b..4d63fa73f8d84aa701a674b176feb5da5a469207 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -317,6 +317,7 @@ scale.im    Newer scaling code
 spot.perl      For making an ordered dither matrix from a spot function
 stackmach.c
 stackmach.h
+t/GoodTestFont.pm      A dummy (hardly implemented) font driver.
 t/Pod/Coverage/Imager.pm
 t/t00basic.t
 t/t01introvert.t
@@ -341,6 +342,7 @@ t/t20fill.t             Tests fills
 t/t21draw.t             Basic drawing tests
 t/t22flood.t           Flood fill tests
 t/t30t1font.t
+t/t31font.t            General font interface tests
 t/t35ttfont.t
 t/t36oofont.t
 t/t40scale.t
index 92c121b91e794ee432203012d18d109f7e1e5a80..1dedbaacd06171a430b36006a4e888713b4b521e 100644 (file)
@@ -18,12 +18,14 @@ my %drivers =
         module=>'Imager/Font/Truetype.pm',
         files=>'.*\.ttf$',
        description => 'FreeType 1.x',
+       checktype => 1,
        },
    t1=>{
         class=>'Imager::Font::Type1',
         module=>'Imager/Font/Type1.pm',
         files=>'.*\.pfb$',
        description => 'T1Lib',
+       checktype => 1,
        },
    ft2=>{
          class=>'Imager::Font::FT2',
@@ -76,8 +78,10 @@ sub new {
         undef $type;
         my $re = $drivers{$drv}{files} or next;
         if ($file =~ /$re/i) {
-          $type = $drv;
-          last;
+         if (eval { require $drivers{$drv}{module}; 1 }) {
+           $type = $drv;
+           last;
+         }
         }
       }
     }
@@ -106,7 +110,7 @@ sub new {
     return;
   }
 
-  if (!$Imager::formats{$type}) {
+  if ($drivers{$type}{checktype} && !$Imager::formats{$type}) {
     $Imager::ERRSTR = "`$type' not enabled";
     return;
   }
@@ -312,11 +316,50 @@ sub priorities {
   my @old = @priority;
 
   if (@_) {
-    @priority = grep Imager::i_has_format($_), @_;
+    @priority = @_;
   }
   return @old;
 }
 
+sub register {
+  my ($self, %opts) = @_;
+
+  my $type = delete $opts{type};
+  my $class = delete $opts{class};
+  my $files = delete $opts{files};
+  my $description = delete $opts{description} || $class;
+
+  defined $type
+    or return Imager->_set_error("No type parameter supplied to Imager::Font->regster");
+
+  defined $class
+    or return Imager->_set_error("No class parameter supplied to Imager::Font->register");
+
+  if ($files) {
+    eval { qr/$files/ }
+      or return Imager->_set_error("files isn't a valid regexp");
+  }
+
+  if ($drivers{$type} && $drivers{$type}{class} ne $class) {
+    Imager->_set_error("Font type $type already registered as $drivers{$type}{class}");
+    return;
+  }
+
+  (my $module = $class . ".pm") =~ s(::)(/)g;
+
+  my $driver =
+    {
+     class => $class,
+     module => $module,
+     description => $description,
+    };
+  $files and $driver->{files} = $files;
+
+  $drivers{$type} = $driver;
+
+  1;
+}
+
 1;
 
 __END__
@@ -952,8 +995,6 @@ You can set new priorities and save the old priorities with:
 
   @old = Imager::Font->priorities(@drivers);
 
-=back
-
 If you supply driver names that are not currently supported, they will
 be ignored.
 
@@ -964,6 +1005,39 @@ do font transformations, you may want to give that a higher priority:
 
   my @old = Imager::Font->priorities(qw(tt ft2 t1));
 
+=item register
+
+Registers an extra font driver.  Accepts the following parameters:
+
+=over
+
+=item *
+
+type - a brief identifier for the font driver.  You can supply this
+value to C<< Imager::Font->new() >> to create fonts of this type.
+Required.
+
+=item *
+
+class - the font class name.  Imager will attempted to load this
+module by name.  Required.
+
+=item *
+
+files - a regular expression to match against file names.  If supplied
+this must be a valid perl regular expression.  If not supplied you can
+only create fonts of this type by supplying the C<type> parameter to
+C<< Imager::Font->new() >>
+
+=item *
+
+description - a brief description of the font driver.  Defaults to the
+value supplied in C<class>.
+
+=back
+
+=back
+
 =head1 AUTHOR
 
 Arnar M. Hrafnkelsson, addi@umich.edu
@@ -972,8 +1046,6 @@ list.
 
 =head1 BUGS
 
-You need to modify this class to add new font types.
-
 The $pos_width member returned by the bounding_box() method has
 historically returned different values from different drivers.  The
 FreeType 1.x and 2.x, and the Win32 drivers return the max of the
diff --git a/t/GoodTestFont.pm b/t/GoodTestFont.pm
new file mode 100644 (file)
index 0000000..ad75804
--- /dev/null
@@ -0,0 +1,13 @@
+package GoodTestFont;
+use strict;
+use vars '@ISA';
+
+# this doesn't do enough to be a font
+
+sub new {
+  my ($class, %opts) = @_;
+
+  return bless \%opts, $class; # as long as it's true
+}
+
+1;
diff --git a/t/t31font.t b/t/t31font.t
new file mode 100644 (file)
index 0000000..b266485
--- /dev/null
@@ -0,0 +1,42 @@
+#!perl -w
+use strict;
+use Imager;
+use Test::More tests => 10;
+
+unshift @INC, "t";
+
+ok(Imager::Font->register(type => "test",
+                         class=>"GoodTestFont",
+                         files => "\\.ppm\$"),
+   "register a test font");
+
+ok(Imager::Font->register(type => "bad",
+                         class => "BadTestFont",
+                         files => "\\.ppm\$"),
+   "register a bad test font");
+
+ok(!Imager::Font->register(), "no register parameters");
+like(Imager->errstr, qr/No type parameter/, "check message");
+
+ok(!Imager::Font->register(type => "bad1"), "no class parameter");
+like(Imager->errstr, qr/No class parameter/, "check message");
+
+ok(!Imager::Font->register(type => "bad2", class => "BadFont", files => "**"),
+   "bad files parameter");
+is(Imager->errstr, "files isn't a valid regexp", "check message");
+
+Imager::Font->priorities("bad", "test");
+
+# RT #62855
+# previously we'd select the first file matched font driver, even if
+# it wasn't available, then crash loading it.
+
+SKIP:
+{
+  my $good;
+  ok(eval {
+    $good = Imager::Font->new(file => "testimg/penguin-base.ppm");
+  }, "load good font avoiding RT 62855")
+    or skip("Failed to load", 1);
+  ok($good->isa("GoodTestFont"), "and it's the right type");
+}