Move freetype 2 support into its own module
authorTony Cook <tony@develop=help.com>
Sat, 25 Sep 2010 05:06:23 +0000 (05:06 +0000)
committerTony Cook <tony@develop=help.com>
Sat, 25 Sep 2010 05:06:23 +0000 (05:06 +0000)
lots of other changes in support of that

46 files changed:
FT2/FT2.pm [new file with mode: 0644]
FT2/FT2.xs [new file with mode: 0644]
FT2/Makefile.PL [new file with mode: 0644]
FT2/fontfiles/ExistenceTest.afm [new file with mode: 0644]
FT2/fontfiles/ExistenceTest.pfb [new file with mode: 0644]
FT2/fontfiles/ExistenceTest.ttf [new file with mode: 0644]
FT2/fontfiles/ImUgly.ttf [new file with mode: 0644]
FT2/fontfiles/MMOne.pfb [new file with mode: 0644]
FT2/fontfiles/NameTest.ttf [new file with mode: 0644]
FT2/fontfiles/dodge.ttf [new file with mode: 0644]
FT2/freetyp2.c [new file with mode: 0644]
FT2/imft2.h [new file with mode: 0644]
FT2/t/t10ft2.t [new file with mode: 0644]
FT2/typemap [new file with mode: 0644]
Imager.pm
Imager.xs
MANIFEST
Makefile.PL
apidocs.perl
fills.c
filters.im
fontfiles/MMOne.pfb [deleted file]
freetyp2.c [deleted file]
imager.h
imageri.h
imdatatypes.h
imext.c
imext.h
imexttypes.h
imio.h
imperl.h
imrender.h
io.c
iolayer.c
lib/Imager/APIRef.pod
lib/Imager/Font.pm
lib/Imager/Font/FreeType2.pm
paste.im
polygon.c
quant.c
regmach.c
render.im
rendert.h
t/t38ft2font.t [deleted file]
t/x20spell.t
typemap

diff --git a/FT2/FT2.pm b/FT2/FT2.pm
new file mode 100644 (file)
index 0000000..118522a
--- /dev/null
@@ -0,0 +1,227 @@
+package Imager::Font::FT2;
+use strict;
+use Imager;
+use vars qw($VERSION @ISA);
+@ISA = qw(Imager::Font);
+
+BEGIN {
+  $VERSION = "0.77";
+
+  eval {
+    require XSLoader;
+    XSLoader::load('Imager::Font::FT2', $VERSION);
+    1;
+  } or do {
+    require DynaLoader;
+    push @ISA, 'DynaLoader';
+    bootstrap Imager::Font::FT2 $VERSION;
+  };
+}
+
+*_first = \&Imager::Font::_first;
+
+sub new {
+  my $class = shift;
+  my %hsh=(color=>Imager::Color->new(255,0,0,0),
+          size=>15,
+          @_);
+
+  unless ($hsh{file}) {
+    $Imager::ERRSTR = "No font file specified";
+    return;
+  }
+  unless (-e $hsh{file}) {
+    $Imager::ERRSTR = "Font file $hsh{file} not found";
+    return;
+  }
+  unless ($Imager::formats{ft2}) {
+    $Imager::ERRSTR = "Freetype2 not supported in this build";
+    return;
+  }
+  my $id = i_ft2_new($hsh{file}, $hsh{'index'} || 0);
+  unless ($id) { # the low-level code may miss some error handling
+    $Imager::ERRSTR = Imager::_error_as_msg();
+    return;
+  }
+  return bless {
+               id       => $id,
+               aa       => $hsh{aa} || 0,
+               file     => $hsh{file},
+               type     => 't1',
+               size     => $hsh{size},
+               color    => $hsh{color},
+                utf8     => $hsh{utf8},
+                vlayout  => $hsh{vlayout},
+              }, $class;
+}
+
+sub _draw {
+  my $self = shift;
+  my %input = @_;
+  if (exists $input{channel}) {
+    i_ft2_cp($self->{id}, $input{image}{IMG}, $input{'x'}, $input{'y'},
+             $input{channel}, $input{size}, $input{sizew} || 0,
+             $input{string}, , $input{align}, $input{aa}, $input{vlayout},
+             $input{utf8});
+  } else {
+    i_ft2_text($self->{id}, $input{image}{IMG},
+               $input{'x'}, $input{'y'},
+               $input{color}, $input{size}, $input{sizew} || 0,
+               $input{string}, $input{align}, $input{aa}, $input{vlayout},
+               $input{utf8});
+  }
+}
+
+sub _bounding_box {
+  my $self = shift;
+  my %input = @_;
+
+  return i_ft2_bbox($self->{id}, $input{size}, $input{sizew}, $input{string}, 
+                   $input{utf8});
+}
+
+sub dpi {
+  my $self = shift;
+  my @old = i_ft2_getdpi($self->{id});
+  if (@_) {
+    my %hsh = @_;
+    my $result;
+    unless ($hsh{xdpi} && $hsh{ydpi}) {
+      if ($hsh{dpi}) {
+        $hsh{xdpi} = $hsh{ydpi} = $hsh{dpi};
+      }
+      else {
+        $Imager::ERRSTR = "dpi method requires xdpi and ydpi or just dpi";
+        return;
+      }
+      i_ft2_setdpi($self->{id}, $hsh{xdpi}, $hsh{ydpi}) or return;
+    }
+  }
+  
+  return @old;
+}
+
+sub hinting {
+  my ($self, %opts) = @_;
+
+  i_ft2_sethinting($self->{id}, $opts{hinting} || 0);
+}
+
+sub _transform {
+  my $self = shift;
+
+  my %hsh = @_;
+  my $matrix = $hsh{matrix} or return undef;
+
+  return i_ft2_settransform($self->{id}, $matrix)
+}
+
+sub utf8 {
+  return 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 i_ft2_has_chars($self->{id}, $hsh{string}, 
+                        _first($hsh{'utf8'}, $self->{utf8}, 0));
+}
+
+sub face_name {
+  my ($self) = @_;
+
+  i_ft2_face_name($self->{id});
+}
+
+sub can_glyph_names {
+  i_ft2_can_do_glyph_names();
+}
+
+sub glyph_names {
+  my ($self, %input) = @_;
+
+  my $string = $input{string};
+  defined $string
+    or return Imager->_set_error("no string parameter passed to glyph_names");
+  my $utf8 = _first($input{utf8}, 0);
+  my $reliable_only = _first($input{reliable_only}, 1);
+
+  my @names = i_ft2_glyph_name($self->{id}, $string, $utf8, $reliable_only);
+  @names or return Imager->_set_error(Imager->_error_as_msg);
+
+  return @names if wantarray;
+  return pop @names;
+}
+
+sub is_mm {
+  my ($self) = @_;
+
+  i_ft2_is_multiple_master($self->{id});
+}
+
+sub mm_axes {
+  my ($self) = @_;
+
+  my ($num_axis, $num_design, @axes) =
+    i_ft2_get_multiple_masters($self->{id})
+      or return Imager->_set_error(Imager->_error_as_msg);
+
+  return @axes;
+}
+
+sub set_mm_coords {
+  my ($self, %opts) = @_;
+
+  $opts{coords}
+    or return Imager->_set_error("Missing coords parameter");
+  ref($opts{coords}) && $opts{coords} =~ /ARRAY\(0x[\da-f]+\)$/
+    or return Imager->_set_error("coords parameter must be an ARRAY ref");
+
+  i_ft2_set_mm_coords($self->{id}, @{$opts{coords}})
+    or return Imager->_set_error(Imager->_error_as_msg);
+
+  return 1;
+}
+1;
+
+__END__
+
+=head1 NAME
+
+Imager::Font::FT2 - font support using FreeType 2
+
+=head1 SYNOPSIS
+
+  use Imager;
+
+  my $img = Imager->new;
+  my $font = Imager::Font->new(file => "foo.ttf", type => "ft2");
+
+  $img->string(... font => $font);
+
+=head1 DESCRIPTION
+
+This provides font support on FreeType 2.
+
+=head1 CAVEATS
+
+Unfortunately, older versions of Imager would install
+C<Imager::Font::FreeType2> even if FreeType 2 wasn't available, and if
+no font was created would succeed in loading the module.  This means
+that an existing C<FreeType2.pm> could cause a probe success for
+supported font files, so I've renamed it.
+
+=head1 AUTHOR
+
+Tony Cook <tony@imager.perl.org>
+
+=head1 SEE ALSO
+
+Imager, Imager::Font.
+
+=cut
diff --git a/FT2/FT2.xs b/FT2/FT2.xs
new file mode 100644 (file)
index 0000000..4bd1801
--- /dev/null
@@ -0,0 +1,357 @@
+#define PERL_NO_GET_CONTEXT
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include "EXTERN.h"
+#include "perl.h"
+#include "XSUB.h"
+#include "imext.h"
+#include "imperl.h"
+#include "imft2.h"
+
+DEFINE_IMAGER_CALLBACKS;
+
+MODULE = Imager::Font::FT2  PACKAGE = Imager::Font::FT2x     PREFIX=FT2_
+
+#define FT2_DESTROY(font) i_ft2_destroy(font)
+
+void
+FT2_DESTROY(font)
+        Imager::Font::FT2x font
+
+int
+FT2_CLONE_SKIP(...)
+    CODE:
+        RETVAL = 1;
+    OUTPUT:
+        RETVAL
+
+MODULE = Imager::Font::FT2  PACKAGE = Imager::Font::FT2
+
+Imager::Font::FT2x
+i_ft2_new(name, index)
+        char *name
+        int index
+
+undef_int
+i_ft2_setdpi(font, xdpi, ydpi)
+        Imager::Font::FT2x font
+        int xdpi
+        int ydpi
+
+void
+i_ft2_getdpi(font)
+        Imager::Font::FT2x font
+      PREINIT:
+        int xdpi, ydpi;
+      CODE:
+        if (i_ft2_getdpi(font, &xdpi, &ydpi)) {
+          EXTEND(SP, 2);
+          PUSHs(sv_2mortal(newSViv(xdpi)));
+          PUSHs(sv_2mortal(newSViv(ydpi)));
+        }
+
+undef_int
+i_ft2_sethinting(font, hinting)
+        Imager::Font::FT2x font
+        int hinting
+
+undef_int
+i_ft2_settransform(font, matrix)
+        Imager::Font::FT2x font
+      PREINIT:
+        double matrix[6];
+        int len;
+        AV *av;
+        SV *sv1;
+        int i;
+      CODE:
+        if (!SvROK(ST(1)) || SvTYPE(SvRV(ST(1))) != SVt_PVAV)
+          croak("i_ft2_settransform: parameter 2 must be an array ref\n");
+       av=(AV*)SvRV(ST(1));
+       len=av_len(av)+1;
+        if (len > 6)
+          len = 6;
+        for (i = 0; i < len; ++i) {
+         sv1=(*(av_fetch(av,i,0)));
+         matrix[i] = SvNV(sv1);
+        }
+        for (; i < 6; ++i)
+          matrix[i] = 0;
+        RETVAL = i_ft2_settransform(font, matrix);
+      OUTPUT:
+        RETVAL
+
+void
+i_ft2_bbox(font, cheight, cwidth, text_sv, utf8)
+        Imager::Font::FT2x font
+        double cheight
+        double cwidth
+        SV *text_sv
+       int utf8
+      PREINIT:
+        int bbox[BOUNDING_BOX_COUNT];
+        int i;
+        char *text;
+        STRLEN text_len;
+        int rc;
+      PPCODE:
+        text = SvPV(text_sv, text_len);
+#ifdef SvUTF8
+        if (SvUTF8(text_sv))
+          utf8 = 1;
+#endif
+        rc = i_ft2_bbox(font, cheight, cwidth, text, text_len, bbox, utf8);
+        if (rc) {
+          EXTEND(SP, rc);
+          for (i = 0; i < rc; ++i)
+            PUSHs(sv_2mortal(newSViv(bbox[i])));
+        }
+
+void
+i_ft2_bbox_r(font, cheight, cwidth, text, vlayout, utf8)
+        Imager::Font::FT2x font
+        double cheight
+        double cwidth
+        char *text
+        int vlayout
+        int utf8
+      PREINIT:
+        int bbox[8];
+        int i;
+      PPCODE:
+#ifdef SvUTF8
+        if (SvUTF8(ST(3)))
+          utf8 = 1;
+#endif
+        if (i_ft2_bbox_r(font, cheight, cwidth, text, strlen(text), vlayout,
+                         utf8, bbox)) {
+          EXTEND(SP, 8);
+          for (i = 0; i < 8; ++i)
+            PUSHs(sv_2mortal(newSViv(bbox[i])));
+        }
+
+undef_int
+i_ft2_text(font, im, tx, ty, cl, cheight, cwidth, text, align, aa, vlayout, utf8)
+        Imager::Font::FT2x font
+        Imager::ImgRaw im
+        int tx
+        int ty
+        Imager::Color cl
+        double cheight
+        double cwidth
+        int align
+        int aa
+        int vlayout
+        int utf8
+      PREINIT:
+        char *text;
+        STRLEN len;
+      CODE:
+#ifdef SvUTF8
+        if (SvUTF8(ST(7))) {
+          utf8 = 1;
+        }
+#endif
+        text = SvPV(ST(7), len);
+        RETVAL = i_ft2_text(font, im, tx, ty, cl, cheight, cwidth, text,
+                            len, align, aa, vlayout, utf8);
+      OUTPUT:
+        RETVAL
+
+undef_int
+i_ft2_cp(font, im, tx, ty, channel, cheight, cwidth, text_sv, align, aa, vlayout, utf8)
+        Imager::Font::FT2x font
+        Imager::ImgRaw im
+        int tx
+        int ty
+        int channel
+        double cheight
+        double cwidth
+        SV *text_sv
+        int align
+        int aa
+        int vlayout
+        int utf8
+      PREINIT:
+       char const *text;
+       STRLEN len;
+      CODE:
+#ifdef SvUTF8
+        if (SvUTF8(ST(7)))
+          utf8 = 1;
+#endif
+       text = SvPV(text_sv, len);
+        RETVAL = i_ft2_cp(font, im, tx, ty, channel, cheight, cwidth, text,
+                          len, align, aa, vlayout, 1);
+      OUTPUT:
+        RETVAL
+
+void
+ft2_transform_box(font, x0, x1, x2, x3)
+        Imager::Font::FT2x font
+        int x0
+        int x1
+        int x2
+        int x3
+      PREINIT:
+        int box[4];
+      PPCODE:
+        box[0] = x0; box[1] = x1; box[2] = x2; box[3] = x3;
+        ft2_transform_box(font, box);
+          EXTEND(SP, 4);
+          PUSHs(sv_2mortal(newSViv(box[0])));
+          PUSHs(sv_2mortal(newSViv(box[1])));
+          PUSHs(sv_2mortal(newSViv(box[2])));
+          PUSHs(sv_2mortal(newSViv(box[3])));
+
+void
+i_ft2_has_chars(handle, text_sv, utf8)
+        Imager::Font::FT2x handle
+        SV  *text_sv
+        int utf8
+      PREINIT:
+        char *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_ft2_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);
+
+void
+i_ft2_face_name(handle)
+        Imager::Font::FT2x handle
+      PREINIT:
+        char name[255];
+        int len;
+      PPCODE:
+        len = i_ft2_face_name(handle, name, sizeof(name));
+        if (len) {
+          EXTEND(SP, 1);
+          PUSHs(sv_2mortal(newSVpv(name, 0)));
+        }
+
+undef_int
+i_ft2_can_face_name()
+
+void
+i_ft2_glyph_name(handle, text_sv, utf8 = 0, reliable_only = 1)
+        Imager::Font::FT2x handle
+        SV *text_sv
+        int utf8
+        int reliable_only
+      PREINIT:
+        char const *text;
+        STRLEN work_len;
+        size_t len;
+        char name[255];
+      PPCODE:
+#ifdef SvUTF8
+        if (SvUTF8(text_sv))
+          utf8 = 1;
+#endif
+        text = SvPV(text_sv, work_len);
+        len = work_len;
+        while (len) {
+          unsigned long ch;
+          if (utf8) {
+            ch = i_utf8_advance(&text, &len);
+            if (ch == ~0UL) {
+              i_push_error(0, "invalid UTF8 character");
+              break;
+            }
+          }
+          else {
+            ch = *text++;
+            --len;
+          }
+          EXTEND(SP, 1);
+          if (i_ft2_glyph_name(handle, ch, name, sizeof(name), 
+                                         reliable_only)) {
+            PUSHs(sv_2mortal(newSVpv(name, 0)));
+          }
+          else {
+            PUSHs(&PL_sv_undef);
+          } 
+        }
+
+int
+i_ft2_can_do_glyph_names()
+
+int
+i_ft2_face_has_glyph_names(handle)
+        Imager::Font::FT2x handle
+
+int
+i_ft2_is_multiple_master(handle)
+        Imager::Font::FT2x handle
+
+void
+i_ft2_get_multiple_masters(handle)
+        Imager::Font::FT2x handle
+      PREINIT:
+        i_font_mm mm;
+        int i;
+      PPCODE:
+        if (i_ft2_get_multiple_masters(handle, &mm)) {
+          EXTEND(SP, 2+mm.num_axis);
+          PUSHs(sv_2mortal(newSViv(mm.num_axis)));
+          PUSHs(sv_2mortal(newSViv(mm.num_designs)));
+          for (i = 0; i < mm.num_axis; ++i) {
+            AV *av = newAV();
+            SV *sv;
+            av_extend(av, 3);
+            sv = newSVpv(mm.axis[i].name, strlen(mm.axis[i].name));
+            SvREFCNT_inc(sv);
+            av_store(av, 0, sv);
+            sv = newSViv(mm.axis[i].minimum);
+            SvREFCNT_inc(sv);
+            av_store(av, 1, sv);
+            sv = newSViv(mm.axis[i].maximum);
+            SvREFCNT_inc(sv);
+            av_store(av, 2, sv);
+            PUSHs(newRV_noinc((SV *)av));
+          }
+        }
+
+undef_int
+i_ft2_set_mm_coords(handle, ...)
+        Imager::Font::FT2x handle
+      PROTOTYPE: DISABLE
+      PREINIT:
+        long *coords;
+        int ix_coords, i;
+      CODE:
+        /* T_ARRAY handling by xsubpp seems to be busted in 5.6.1, so
+           transfer the array manually */
+        ix_coords = items-1;
+        coords = mymalloc(sizeof(long) * ix_coords);
+       for (i = 0; i < ix_coords; ++i) {
+          coords[i] = (long)SvIV(ST(1+i));
+        }
+        RETVAL = i_ft2_set_mm_coords(handle, ix_coords, coords);
+        myfree(coords);
+      OUTPUT:
+        RETVAL
+
+
+BOOT:
+       PERL_INITIALIZE_IMAGER_CALLBACKS;
diff --git a/FT2/Makefile.PL b/FT2/Makefile.PL
new file mode 100644 (file)
index 0000000..fc19136
--- /dev/null
@@ -0,0 +1,185 @@
+#!perl -w
+use strict;
+use ExtUtils::MakeMaker qw(WriteMakefile WriteEmptyMakefile);
+use Getopt::Long;
+use Config;
+
+my $verbose = $ENV{IM_VERBOSE};
+my @libpaths;
+my @incpaths;
+
+GetOptions("incpath=s", \@incpaths,
+           "libpath=s" => \@libpaths,
+           "verbose|v" => \$verbose);
+
+our $BUILDING_IMAGER;
+
+$DB::single = 1;
+
+my $MM_ver = eval $ExtUtils::MakeMaker::VERSION;
+
+my %opts = 
+  (
+   NAME => 'Imager::Font::FT2',
+   VERSION_FROM => 'FT2.pm',
+   OBJECT => 'FT2.o freetyp2.o',
+   clean => { FILES => 'testout' },
+  );
+
+my @inc;
+if ($BUILDING_IMAGER) {
+  push @inc, "-I..";
+  unshift @INC, "../lib";
+}
+else {
+  unshift @INC, "inc";
+  print "FreeType 2: building independently\n";
+  require Imager::ExtUtils;
+  push @inc, Imager::ExtUtils->includes;
+  $opts{TYPEMAPS} = [ Imager::ExtUtils->typemap ];
+
+  # Imager required configure through use
+  my @Imager_req = ( Imager => "0.77" );
+  if ($MM_ver >= 6.46) {
+    $opts{META_MERGE} =
+      {
+       configure_requires => 
+       {
+       @Imager_req,
+       },
+       build_requires => 
+       {
+       @Imager_req,
+       "Test::More" => "0.47",
+       },
+       resources =>
+       {
+       homepage => "http://imager.perl.org/",
+       repository =>
+       {
+        url => "http://imager.perl.org/svn/trunk/Imager-Font-FT2",
+        web => "http://imager.perl.org/svnweb/public/browse/trunk/Imager-Font-FT2",
+        type => "svn",
+       },
+       },
+      };
+    $opts{PREREQ_PM} =
+      {
+       @Imager_req,
+      };
+  }
+}
+
+require Imager::Probe;
+
+my %probe =
+  (
+   name => "FreeType 2",
+   code => \&freetype2_probe_ftconfig,
+   inccheck =>
+   sub { -e File::Spec->catfile($_[0], "freetype/ftbitmap.h") },
+   libbase => "freetype",
+   testcode => _ft2_test_code(),
+   testcodeheaders => [ "stdio.h", "string.h", "ft2build.h" ],
+   incpath => join($Config{path_sep}, @incpaths),
+   libpath => join($Config{path_sep}, @libpaths),
+   alternatives =>
+   [
+    {
+     incsuffix => "freetype2",
+    },
+    {
+     incsuffix => "freetype",
+    },
+   ],
+  );
+
+my $probe_res = Imager::Probe->probe(\%probe);
+if ($probe_res) {
+  push @inc, $probe_res->{INC};
+  $opts{LIBS} = $probe_res->{LIBS};
+
+  $opts{INC} = "@inc";
+
+  if ($MM_ver > 6.06) {
+    $opts{AUTHOR} = 'Tony Cook <tony@imager.perl.org>';
+    $opts{ABSTRACT} = 'FreeType 2 font driver for Imager';
+  }
+  
+  WriteMakefile(%opts);
+}
+else {
+  if ($BUILDING_IMAGER) {
+    WriteEmptyMakefile(%opts);
+  }
+  else {
+    # fail in good way
+    die "OS unsupported: FreeType 2 headers/libraries not found\n";
+  }
+}
+
+sub _ft2_test_code {
+  return <<'CODE';
+return 0;
+CODE
+}
+
+sub is_exe {
+  my ($name) = @_;
+
+  my @exe_suffix = $Config{_exe};
+  if ($^O eq 'MSWin32') {
+    push @exe_suffix, qw/.bat .cmd/;
+  }
+
+  for my $dir (File::Spec->path) {
+    for my $suffix (@exe_suffix) {
+      -x catfile($dir, "$name$suffix")
+       and return 1;
+    }
+  }
+
+  return;
+}
+
+# probes for freetype2 by trying to run freetype-config
+sub freetype2_probe_ftconfig {
+  my ($req) = @_;
+
+  is_exe('freetype-config') or return;
+
+  my $cflags = `freetype-config --cflags`
+    and !$? or return;
+  chomp $cflags;
+
+  my $lflags = `freetype-config --libs`
+    and !$? or return;
+  chomp $lflags;
+
+  # before 2.1.5 freetype-config --cflags could output
+  # the -I options in the wrong order, causing a conflict with
+  # freetype1.x installed with the same --prefix
+  #
+  # can happen iff:
+  #  - both -Iprefix/include and -Iprefix/include/freetype2 are in cflags
+  #    in that order
+  #  - freetype 1.x headers are in prefix/include/freetype
+  my @incdirs = map substr($_, 2), grep /^-I/, split ' ', $cflags;
+  if (@incdirs == 2 
+      && $incdirs[1] eq "$incdirs[0]/freetype2"
+      && -e "$incdirs[0]/freetype/freetype.h"
+      && -e "$incdirs[0]/freetype/fterrid.h") {
+    print "** freetype-config provided -I options out of order, correcting\n"
+      if $verbose;
+    $cflags = join(' ', grep(!/-I/, split ' ', $cflags),
+                  map "-I$_", reverse @incdirs);
+  }
+
+  print "$req->{name}: configured via freetype-config\n";
+
+  return
+    {
+     INC => $cflags,
+     LIBS => $lflags,
+    };
+}
diff --git a/FT2/fontfiles/ExistenceTest.afm b/FT2/fontfiles/ExistenceTest.afm
new file mode 100644 (file)
index 0000000..5200705
--- /dev/null
@@ -0,0 +1,21 @@
+StartFontMetrics 2.0
+Comment Generated by pfaedit
+Comment Creation Date: Thu Jul 20 21:57:23 2006
+FontName ExistenceTest
+FullName ExistenceTest
+FamilyName ExistenceTest
+Weight Medium
+Notice (Created by Tony Cook,,, with PfaEdit 1.0 (http://pfaedit.sf.net))
+ItalicAngle 0
+IsFixedPitch false
+UnderlinePosition -100
+UnderlineThickness 50
+Version 001.000
+EncodingScheme AdobeStandardEncoding
+FontBBox -60 -55 819 775
+StartCharMetrics 3
+C 0 ; WX 487 ; N uniFFFD ; B 72 87 414 396 ;
+C 33 ; WX 310 ; N exclam ; B 51 0 207 738 ;
+C 47 ; WX 761 ; N slash ; B -60 -55 819 775 ;
+EndCharMetrics
+EndFontMetrics
diff --git a/FT2/fontfiles/ExistenceTest.pfb b/FT2/fontfiles/ExistenceTest.pfb
new file mode 100644 (file)
index 0000000..88863ad
Binary files /dev/null and b/FT2/fontfiles/ExistenceTest.pfb differ
diff --git a/FT2/fontfiles/ExistenceTest.ttf b/FT2/fontfiles/ExistenceTest.ttf
new file mode 100644 (file)
index 0000000..a4a7e56
Binary files /dev/null and b/FT2/fontfiles/ExistenceTest.ttf differ
diff --git a/FT2/fontfiles/ImUgly.ttf b/FT2/fontfiles/ImUgly.ttf
new file mode 100644 (file)
index 0000000..eb07393
Binary files /dev/null and b/FT2/fontfiles/ImUgly.ttf differ
diff --git a/FT2/fontfiles/MMOne.pfb b/FT2/fontfiles/MMOne.pfb
new file mode 100644 (file)
index 0000000..7f83901
Binary files /dev/null and b/FT2/fontfiles/MMOne.pfb differ
diff --git a/FT2/fontfiles/NameTest.ttf b/FT2/fontfiles/NameTest.ttf
new file mode 100644 (file)
index 0000000..a28723a
Binary files /dev/null and b/FT2/fontfiles/NameTest.ttf differ
diff --git a/FT2/fontfiles/dodge.ttf b/FT2/fontfiles/dodge.ttf
new file mode 100644 (file)
index 0000000..132b95b
Binary files /dev/null and b/FT2/fontfiles/dodge.ttf differ
diff --git a/FT2/freetyp2.c b/FT2/freetyp2.c
new file mode 100644 (file)
index 0000000..8d034f9
--- /dev/null
@@ -0,0 +1,1163 @@
+/*
+=head1 NAME
+
+freetyp2.c - font support via the FreeType library version 2.
+
+=head1 SYNOPSIS
+
+  if (!i_ft2_init()) { error }
+  FT2_Fonthandle *font;
+  font = i_ft2_new(name, index);
+  if (!i_ft2_setdpi(font, xdpi, ydpi)) { error }
+  if (!i_ft2_getdpi(font, &xdpi, &ydpi)) { error }
+  double matrix[6];
+  if (!i_ft2_settransform(font, matrix)) { error }
+  int bbox[BOUNDING_BOX_COUNT];
+  if (!i_ft2_bbox(font, cheight, cwidth, text, length, bbox, utf8)) { error }
+  i_img *im = ...;
+  i_color cl;
+  if (!i_ft2_text(font, im, tx, ty, cl, cheight, cwidth, text, length, align,
+                  aa)) { error }
+  if (!i_ft2_cp(font, im, tx, ty, channel, cheight, cwidth, text, length,
+                align, aa)) { error }
+  i_ft2_destroy(font);
+
+=head1 DESCRIPTION
+
+Implements Imager font support using the FreeType2 library.
+
+The FreeType2 library understands several font file types, including
+Truetype, Type1 and Windows FNT.
+
+=over 
+
+=cut
+*/
+
+#include "imext.h"
+#include "imft2.h"
+#include <stdio.h>
+#include <math.h>
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#ifdef FT_MULTIPLE_MASTERS_H
+#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
+#define IM_FT2_MM
+#include FT_MULTIPLE_MASTERS_H
+#endif
+#endif
+
+static void ft2_push_message(int code);
+
+static int ft2_initialized = 0;
+static FT_Library library;
+
+static int i_min(int a, int b);
+static int i_max(int a, int b);
+
+/*
+=item i_ft2_init(void)
+
+Initializes the Freetype 2 library.
+
+Returns true on success, false on failure.
+
+=cut
+*/
+int
+i_ft2_init(void) {
+  FT_Error error;
+
+  i_clear_error();
+  error = FT_Init_FreeType(&library);
+  if (error) {
+    ft2_push_message(error);
+    i_push_error(0, "Initializing Freetype2");
+    return 0;
+  }
+
+  ft2_initialized = 1;
+
+  return 1;
+}
+
+struct FT2_Fonthandle {
+  FT_Face face;
+  int xdpi, ydpi;
+  int hint;
+  FT_Encoding encoding;
+
+  /* used to adjust so we can align the draw point to the top-left */
+  double matrix[6];
+
+#ifdef IM_FT2_MM
+  /* Multiple master data if any */
+  int has_mm;
+  FT_Multi_Master mm;
+#endif
+};
+
+/* the following is used to select a "best" encoding */
+static struct enc_score {
+  FT_Encoding encoding;
+  int score;
+} enc_scores[] =
+{
+  /* the selections here are fairly arbitrary
+     ideally we need to give the user a list of encodings available
+     and a mechanism to choose one */
+  { ft_encoding_unicode,        10 },
+  { ft_encoding_sjis,            8 },
+  { ft_encoding_gb2312,          8 },
+  { ft_encoding_big5,            8 },
+  { ft_encoding_wansung,         8 },
+  { ft_encoding_johab,           8 },  
+  { ft_encoding_latin_2,         6 },
+  { ft_encoding_apple_roman,     6 },
+  { ft_encoding_adobe_standard,  6 },
+  { ft_encoding_adobe_expert,    6 },
+};
+
+/*
+=item i_ft2_new(char *name, int index)
+
+Creates a new font object, from the file given by I<name>.  I<index>
+is the index of the font in a file with multiple fonts, where 0 is the
+first font.
+
+Return NULL on failure.
+
+=cut
+*/
+
+FT2_Fonthandle *
+i_ft2_new(const char *name, int index) {
+  FT_Error error;
+  FT2_Fonthandle *result;
+  FT_Face face;
+  int i, j;
+  FT_Encoding encoding;
+  int score;
+
+  mm_log((1, "i_ft2_new(name %p, index %d)\n", name, index));
+
+  if (!ft2_initialized && !i_ft2_init())
+    return NULL;
+
+  i_clear_error();
+  error = FT_New_Face(library, name, index, &face);
+  if (error) {
+    ft2_push_message(error);
+    i_push_error(error, "Opening face");
+    mm_log((2, "error opening face '%s': %d\n", name, error));
+    return NULL;
+  }
+
+  encoding = face->num_charmaps ? face->charmaps[0]->encoding : ft_encoding_unicode;
+  score = 0;
+  for (i = 0; i < face->num_charmaps; ++i) {
+    FT_Encoding enc_entry = face->charmaps[i]->encoding;
+    mm_log((2, "i_ft2_new, encoding %lX platform %u encoding %u\n",
+            enc_entry, face->charmaps[i]->platform_id,
+            face->charmaps[i]->encoding_id));
+    for (j = 0; j < sizeof(enc_scores) / sizeof(*enc_scores); ++j) {
+      if (enc_scores[j].encoding == enc_entry && enc_scores[j].score > score) {
+        encoding = enc_entry;
+        score = enc_scores[j].score;
+        break;
+      }
+    }
+  }
+  FT_Select_Charmap(face, encoding);
+  mm_log((2, "i_ft2_new, selected encoding %lX\n", encoding));
+
+  result = mymalloc(sizeof(FT2_Fonthandle));
+  result->face = face;
+  result->xdpi = result->ydpi = 72;
+  result->encoding = encoding;
+
+  /* by default we disable hinting on a call to i_ft2_settransform()
+     if we don't do this, then the hinting can the untransformed text
+     to be a different size to the transformed text.
+     Obviously we have it initially enabled.
+  */
+  result->hint = 1; 
+
+  /* I originally forgot this:   :/ */
+  /*i_ft2_settransform(result, matrix); */
+  result->matrix[0] = 1; result->matrix[1] = 0; result->matrix[2] = 0;
+  result->matrix[3] = 0; result->matrix[4] = 1; result->matrix[5] = 0;
+
+#ifdef IM_FT2_MM
+ {
+   FT_Multi_Master *mm = &result->mm;
+   int i;
+
+   if ((face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS) != 0 
+       && (error = FT_Get_Multi_Master(face, mm)) == 0) {
+     mm_log((2, "MM Font, %d axes, %d designs\n", mm->num_axis, mm->num_designs));
+     for (i = 0; i < mm->num_axis; ++i) {
+       mm_log((2, "  axis %d name %s range %ld - %ld\n", i, mm->axis[i].name,
+               (long)(mm->axis[i].minimum), (long)(mm->axis[i].maximum)));
+     }
+     result->has_mm = 1;
+   }
+   else {
+     mm_log((2, "No multiple masters\n"));
+     result->has_mm = 0;
+   }
+ }
+#endif
+
+  return result;
+}
+
+/*
+=item i_ft2_destroy(FT2_Fonthandle *handle)
+
+Destroys a font object, which must have been the return value of
+i_ft2_new().
+
+=cut
+*/
+void
+i_ft2_destroy(FT2_Fonthandle *handle) {
+  FT_Done_Face(handle->face);
+  myfree(handle);
+}
+
+/*
+=item i_ft2_setdpi(FT2_Fonthandle *handle, int xdpi, int ydpi)
+
+Sets the resolution in dots per inch at which point sizes scaled, by
+default xdpi and ydpi are 72, so that 1 point maps to 1 pixel.
+
+Both xdpi and ydpi should be positive.
+
+Return true on success.
+
+=cut
+*/
+int
+i_ft2_setdpi(FT2_Fonthandle *handle, int xdpi, int ydpi) {
+  i_clear_error();
+  if (xdpi > 0 && ydpi > 0) {
+    handle->xdpi = xdpi;
+    handle->ydpi = ydpi;
+    return 0;
+  }
+  else {
+    i_push_error(0, "resolutions must be positive");
+    return 0;
+  }
+}
+
+/*
+=item i_ft2_getdpi(FT2_Fonthandle *handle, int *xdpi, int *ydpi)
+
+Retrieves the current horizontal and vertical resolutions at which
+point sizes are scaled.
+
+=cut
+*/
+int
+i_ft2_getdpi(FT2_Fonthandle *handle, int *xdpi, int *ydpi) {
+  *xdpi = handle->xdpi;
+  *ydpi = handle->ydpi;
+
+  return 1;
+}
+
+/*
+=item i_ft2_settransform(FT2_FontHandle *handle, double *matrix)
+
+Sets a transormation matrix for output.
+
+This should be a 2 x 3 matrix like:
+
+ matrix[0]   matrix[1]   matrix[2]
+ matrix[3]   matrix[4]   matrix[5]
+
+=cut
+*/
+int
+i_ft2_settransform(FT2_Fonthandle *handle, const double *matrix) {
+  FT_Matrix m;
+  FT_Vector v;
+  int i;
+
+  m.xx = matrix[0] * 65536;
+  m.xy = matrix[1] * 65536;
+  v.x  = matrix[2]; /* this could be pels of 26.6 fixed - not sure */
+  m.yx = matrix[3] * 65536;
+  m.yy = matrix[4] * 65536;
+  v.y  = matrix[5]; /* see just above */
+
+  FT_Set_Transform(handle->face, &m, &v);
+
+  for (i = 0; i < 6; ++i)
+    handle->matrix[i] = matrix[i];
+  handle->hint = 0;
+
+  return 1;
+}
+
+/*
+=item i_ft2_sethinting(FT2_Fonthandle *handle, int hinting)
+
+If hinting is non-zero then glyph hinting is enabled, otherwise disabled.
+
+i_ft2_settransform() disables hinting to prevent distortions in
+gradual text transformations.
+
+=cut
+*/
+int i_ft2_sethinting(FT2_Fonthandle *handle, int hinting) {
+  handle->hint = hinting;
+  return 1;
+}
+
+/*
+=item i_ft2_bbox(FT2_Fonthandle *handle, double cheight, double cwidth, char *text, size_t len, int *bbox)
+
+Retrieves bounding box information for the font at the given 
+character width and height.  This ignores the transformation matrix.
+
+Returns non-zero on success.
+
+=cut
+*/
+int
+i_ft2_bbox(FT2_Fonthandle *handle, double cheight, double cwidth, 
+           char const *text, size_t len, int *bbox, int utf8) {
+  FT_Error error;
+  int width;
+  int index;
+  int first;
+  int ascent = 0, descent = 0;
+  int glyph_ascent, glyph_descent;
+  FT_Glyph_Metrics *gm;
+  int start = 0;
+  int loadFlags = FT_LOAD_DEFAULT;
+  int rightb = 0;
+
+  mm_log((1, "i_ft2_bbox(handle %p, cheight %f, cwidth %f, text %p, len %d, bbox %p)\n",
+         handle, cheight, cwidth, text, len, bbox));
+
+  error = FT_Set_Char_Size(handle->face, cwidth*64, cheight*64, 
+                           handle->xdpi, handle->ydpi);
+  if (error) {
+    ft2_push_message(error);
+    i_push_error(0, "setting size");
+  }
+
+  if (!handle->hint)
+    loadFlags |= FT_LOAD_NO_HINTING;
+
+  first = 1;
+  width = 0;
+  while (len) {
+    unsigned long c;
+    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;
+    }
+
+    index = FT_Get_Char_Index(handle->face, c);
+    error = FT_Load_Glyph(handle->face, index, loadFlags);
+    if (error) {
+      ft2_push_message(error);
+      i_push_errorf(0, "loading glyph for character \\x%02x (glyph 0x%04X)", 
+                    c, index);
+      return 0;
+    }
+    gm = &handle->face->glyph->metrics;
+    glyph_ascent = gm->horiBearingY / 64;
+    glyph_descent = glyph_ascent - gm->height/64;
+    if (first) {
+      start = gm->horiBearingX / 64;
+      /* handles -ve values properly */
+      ascent = glyph_ascent;
+      descent = glyph_descent;
+      first = 0;
+    }
+
+    if (glyph_ascent > ascent)
+      ascent = glyph_ascent;
+    if (glyph_descent < descent)
+      descent = glyph_descent;
+
+    width += gm->horiAdvance / 64;
+
+    if (len == 0) {
+      /* last character 
+       handle the case where the right the of the character overlaps the 
+       right*/
+      rightb = (gm->horiAdvance - gm->horiBearingX - gm->width)/64;
+      /*if (rightb > 0)
+        rightb = 0;*/
+    }
+  }
+
+  bbox[BBOX_NEG_WIDTH] = start;
+  bbox[BBOX_GLOBAL_DESCENT] = handle->face->size->metrics.descender / 64;
+  bbox[BBOX_POS_WIDTH] = width;
+  if (rightb < 0)
+    bbox[BBOX_POS_WIDTH] -= rightb;
+  bbox[BBOX_GLOBAL_ASCENT] = handle->face->size->metrics.ascender / 64;
+  bbox[BBOX_DESCENT] = descent;
+  bbox[BBOX_ASCENT] = ascent;
+  bbox[BBOX_ADVANCE_WIDTH] = width;
+  bbox[BBOX_RIGHT_BEARING] = rightb;
+  mm_log((1, " bbox=> negw=%d glob_desc=%d pos_wid=%d glob_asc=%d desc=%d asc=%d adv_width=%d rightb=%d\n", bbox[0], bbox[1], bbox[2], bbox[3], bbox[4], bbox[5], bbox[6], bbox[7]));
+
+  return BBOX_RIGHT_BEARING + 1;
+}
+
+/*
+=item transform_box(FT2_FontHandle *handle, int bbox[4])
+
+bbox contains coorinates of a the top-left and bottom-right of a bounding 
+box relative to a point.
+
+This is then transformed and the values in bbox[4] are the top-left
+and bottom-right of the new bounding box.
+
+This is meant to provide the bounding box of a transformed character
+box.  The problem is that if the character was round and is rotated,
+the real bounding box isn't going to be much different from the
+original, but this function will return a _bigger_ bounding box.  I
+suppose I could work my way through the glyph outline, but that's
+too much hard work.
+
+=cut
+*/
+void ft2_transform_box(FT2_Fonthandle *handle, int bbox[4]) {
+  double work[8];
+  double *matrix = handle->matrix;
+  
+  work[0] = matrix[0] * bbox[0] + matrix[1] * bbox[1];
+  work[1] = matrix[3] * bbox[0] + matrix[4] * bbox[1];
+  work[2] = matrix[0] * bbox[2] + matrix[1] * bbox[1];
+  work[3] = matrix[3] * bbox[2] + matrix[4] * bbox[1];
+  work[4] = matrix[0] * bbox[0] + matrix[1] * bbox[3];
+  work[5] = matrix[3] * bbox[0] + matrix[4] * bbox[3];
+  work[6] = matrix[0] * bbox[2] + matrix[1] * bbox[3];
+  work[7] = matrix[3] * bbox[2] + matrix[4] * bbox[3];
+
+  bbox[0] = floor(i_min(i_min(work[0], work[2]),i_min(work[4], work[6])));
+  bbox[1] = floor(i_min(i_min(work[1], work[3]),i_min(work[5], work[7])));
+  bbox[2] = ceil(i_max(i_max(work[0], work[2]),i_max(work[4], work[6])));
+  bbox[3] = ceil(i_max(i_max(work[1], work[3]),i_max(work[5], work[7])));
+}
+
+/*
+=item expand_bounds(int bbox[4], int bbox2[4]) 
+
+Treating bbox[] and bbox2[] as 2 bounding boxes, produces a new
+bounding box in bbox[] that encloses both.
+
+=cut
+*/
+static void expand_bounds(int bbox[4], int bbox2[4]) {
+  bbox[0] = i_min(bbox[0], bbox2[0]);
+  bbox[1] = i_min(bbox[1], bbox2[1]);
+  bbox[2] = i_max(bbox[2], bbox2[2]);
+  bbox[3] = i_max(bbox[3], bbox2[3]);
+}
+
+/*
+=item i_ft2_bbox_r(FT2_Fonthandle *handle, double cheight, double cwidth, char *text, size_t len, int vlayout, int utf8, int *bbox)
+
+Retrieves bounding box information for the font at the given 
+character width and height.
+
+This version finds the rectangular bounding box of the glyphs, with
+the text as transformed by the transformation matrix.  As with
+i_ft2_bbox (bbox[0], bbox[1]) will the the offset from the start of
+the topline to the top-left of the bounding box.  Unlike i_ft2_bbox()
+this could be near the bottom left corner of the box.
+
+(bbox[4], bbox[5]) is the offset to the start of the baseline.
+(bbox[6], bbox[7]) is the offset from the start of the baseline to the
+end of the baseline.
+
+Returns non-zero on success.
+
+=cut
+*/
+int
+i_ft2_bbox_r(FT2_Fonthandle *handle, double cheight, double cwidth, 
+           char const *text, size_t len, int vlayout, int utf8, int *bbox) {
+  FT_Error error;
+  int width;
+  int index;
+  int first;
+  int ascent = 0, descent = 0;
+  int glyph_ascent, glyph_descent;
+  FT_Glyph_Metrics *gm;
+  int work[4];
+  int bounds[4];
+  double x = 0, y = 0;
+  int i;
+  FT_GlyphSlot slot;
+  int loadFlags = FT_LOAD_DEFAULT;
+
+  if (vlayout)
+    loadFlags |= FT_LOAD_VERTICAL_LAYOUT;
+  if (!handle->hint)
+    loadFlags |= FT_LOAD_NO_HINTING;
+
+  error = FT_Set_Char_Size(handle->face, cwidth*64, cheight*64, 
+                           handle->xdpi, handle->ydpi);
+  if (error) {
+    ft2_push_message(error);
+    i_push_error(0, "setting size");
+  }
+
+  first = 1;
+  width = 0;
+  while (len) {
+    unsigned long c;
+    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;
+    }
+
+    index = FT_Get_Char_Index(handle->face, c);
+    error = FT_Load_Glyph(handle->face, index, loadFlags);
+    if (error) {
+      ft2_push_message(error);
+      i_push_errorf(0, "loading glyph for character \\x%02x (glyph 0x%04X)", 
+                    c, index);
+      return 0;
+    }
+    slot = handle->face->glyph; 
+    gm = &slot->metrics;
+
+    /* these probably don't mean much for vertical layouts */
+    glyph_ascent = gm->horiBearingY / 64;
+    glyph_descent = glyph_ascent - gm->height/64;
+    if (vlayout) {
+      work[0] = gm->vertBearingX;
+      work[1] = gm->vertBearingY;
+    }
+    else {
+      work[0] = gm->horiBearingX;
+      work[1] = gm->horiBearingY;
+    }
+    work[2] = gm->width  + work[0];
+    work[3] = work[1] - gm->height;
+    if (first) {
+      bbox[4] = work[0] * handle->matrix[0] + work[1] * handle->matrix[1] + handle->matrix[2];
+      bbox[5] = work[0] * handle->matrix[3] + work[1] * handle->matrix[4] + handle->matrix[5];
+      bbox[4] = bbox[4] < 0 ? -(-bbox[4] + 32)/64 : (bbox[4] + 32) / 64;
+      bbox[5] /= 64;
+    }
+    ft2_transform_box(handle, work);
+    for (i = 0; i < 4; ++i)
+      work[i] /= 64;
+    work[0] += x;
+    work[1] += y;
+    work[2] += x;
+    work[3] += y;
+    if (first) {
+      for (i = 0; i < 4; ++i)
+        bounds[i] = work[i];
+      ascent = glyph_ascent;
+      descent = glyph_descent;
+      first = 0;
+    }
+    else {
+      expand_bounds(bounds, work);
+    }
+    x += slot->advance.x / 64;
+    y += slot->advance.y / 64;
+
+    if (glyph_ascent > ascent)
+      ascent = glyph_ascent;
+    if (glyph_descent > descent)
+      descent = glyph_descent;
+
+    if (len == 0) {
+      /* last character 
+       handle the case where the right the of the character overlaps the 
+       right*/
+      /*int rightb = gm->horiAdvance - gm->horiBearingX - gm->width;
+      if (rightb < 0)
+      width -= rightb / 64;*/
+    }
+  }
+
+  /* at this point bounds contains the bounds relative to the CP,
+     and x, y hold the final position relative to the CP */
+  /*bounds[0] -= x;
+  bounds[1] -= y;
+  bounds[2] -= x;
+  bounds[3] -= y;*/
+
+  bbox[0] = bounds[0];
+  bbox[1] = -bounds[3];
+  bbox[2] = bounds[2];
+  bbox[3] = -bounds[1];
+  bbox[6] = x;
+  bbox[7] = -y;
+
+  return 1;
+}
+
+static int
+make_bmp_map(FT_Bitmap *bitmap, unsigned char *map);
+
+/*
+=item i_ft2_text(FT2_Fonthandle *handle, i_img *im, int tx, int ty, i_color *cl, double cheight, double cwidth, char *text, size_t len, int align, int aa)
+
+Renders I<text> to (I<tx>, I<ty>) in I<im> using color I<cl> at the given 
+I<cheight> and I<cwidth>.
+
+If align is 0, then the text is rendered with the top-left of the
+first character at (I<tx>, I<ty>).  If align is non-zero then the text
+is rendered with (I<tx>, I<ty>) aligned with the base-line of the
+characters.
+
+If aa is non-zero then the text is anti-aliased.
+
+Returns non-zero on success.
+
+=cut
+*/
+int
+i_ft2_text(FT2_Fonthandle *handle, i_img *im, int tx, int ty, const i_color *cl,
+           double cheight, double cwidth, char const *text, size_t len,
+          int align, int aa, int vlayout, int utf8) {
+  FT_Error error;
+  int index;
+  FT_Glyph_Metrics *gm;
+  int bbox[BOUNDING_BOX_COUNT];
+  FT_GlyphSlot slot;
+  int x, y;
+  unsigned char *bmp;
+  unsigned char map[256];
+  char last_mode = ft_pixel_mode_none; 
+  int last_grays = -1;
+  int loadFlags = FT_LOAD_DEFAULT;
+  i_render *render;
+
+  mm_log((1, "i_ft2_text(handle %p, im %p, tx %d, ty %d, cl %p, cheight %f, cwidth %f, text %p, len %d, align %d, aa %d)\n",
+         handle, im, tx, ty, cl, cheight, cwidth, text, align, aa));
+
+  if (vlayout) {
+    if (!FT_HAS_VERTICAL(handle->face)) {
+      i_push_error(0, "face has no vertical metrics");
+      return 0;
+    }
+    loadFlags |= FT_LOAD_VERTICAL_LAYOUT;
+  }
+  if (!handle->hint)
+    loadFlags |= FT_LOAD_NO_HINTING;
+
+  /* set the base-line based on the string ascent */
+  if (!i_ft2_bbox(handle, cheight, cwidth, text, len, bbox, utf8))
+    return 0;
+
+  if (aa)
+    render = i_render_new(im, bbox[BBOX_POS_WIDTH] - bbox[BBOX_NEG_WIDTH]);
+
+  if (!align) {
+    /* this may need adjustment */
+    tx -= bbox[0] * handle->matrix[0] + bbox[5] * handle->matrix[1] + handle->matrix[2];
+    ty += bbox[0] * handle->matrix[3] + bbox[5] * handle->matrix[4] + handle->matrix[5];
+  }
+  while (len) {
+    unsigned long c;
+    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;
+    }
+    
+    index = FT_Get_Char_Index(handle->face, c);
+    error = FT_Load_Glyph(handle->face, index, loadFlags);
+    if (error) {
+      ft2_push_message(error);
+      i_push_errorf(0, "loading glyph for character \\x%02x (glyph 0x%04X)", 
+                    c, index);
+      if (aa)
+        i_render_delete(render);
+      return 0;
+    }
+    slot = handle->face->glyph;
+    gm = &slot->metrics;
+
+    if (gm->width) {
+      error = FT_Render_Glyph(slot, aa ? ft_render_mode_normal : ft_render_mode_mono);
+      if (error) {
+       ft2_push_message(error);
+       i_push_errorf(0, "rendering glyph 0x%04X (character \\x%02X)");
+      if (aa)
+        i_render_delete(render);
+       return 0;
+      }
+      if (slot->bitmap.pixel_mode == ft_pixel_mode_mono) {
+       bmp = slot->bitmap.buffer;
+       for (y = 0; y < slot->bitmap.rows; ++y) {
+         int pos = 0;
+         int bit = 0x80;
+         for (x = 0; x < slot->bitmap.width; ++x) {
+           if (bmp[pos] & bit)
+             i_ppix(im, tx+x+slot->bitmap_left, ty+y-slot->bitmap_top, cl);
+           
+           bit >>= 1;
+           if (bit == 0) {
+             bit = 0x80;
+             ++pos;
+           }
+         }
+         bmp += slot->bitmap.pitch;
+       }
+      }
+      else {
+       /* grey scale or something we can treat as greyscale */
+       /* we create a map to convert from the bitmap values to 0-255 */
+       if (last_mode != slot->bitmap.pixel_mode 
+           || last_grays != slot->bitmap.num_grays) {
+         if (!make_bmp_map(&slot->bitmap, map))
+           return 0;
+         last_mode = slot->bitmap.pixel_mode;
+         last_grays = slot->bitmap.num_grays;
+       }
+
+       bmp = slot->bitmap.buffer;
+       for (y = 0; y < slot->bitmap.rows; ++y) {
+          if (last_mode == ft_pixel_mode_grays &&
+              last_grays != 255) {
+            for (x = 0; x < slot->bitmap.width; ++x) 
+              bmp[x] = map[bmp[x]];
+          }
+          i_render_color(render, tx + slot->bitmap_left, ty-slot->bitmap_top+y,
+                         slot->bitmap.width, bmp, cl);
+         bmp += slot->bitmap.pitch;
+       }
+      }
+    }
+
+    tx += slot->advance.x / 64;
+    ty -= slot->advance.y / 64;
+  }
+
+  if (aa)
+    i_render_delete(render);
+
+  return 1;
+}
+
+/*
+=item i_ft2_cp(FT2_Fonthandle *handle, i_img *im, int tx, int ty, int channel, double cheight, double cwidth, char *text, size_t len, int align, int aa)
+
+Renders I<text> to (I<tx>, I<ty>) in I<im> to I<channel> at the given 
+I<cheight> and I<cwidth>.
+
+If align is 0, then the text is rendered with the top-left of the
+first character at (I<tx>, I<ty>).  If align is non-zero then the text
+is rendered with (I<tx>, I<ty>) aligned with the base-line of the
+characters.
+
+If aa is non-zero then the text is anti-aliased.
+
+Returns non-zero on success.
+
+=cut
+*/
+
+int
+i_ft2_cp(FT2_Fonthandle *handle, i_img *im, int tx, int ty, int channel,
+         double cheight, double cwidth, char const *text, size_t len, int align,
+         int aa, int vlayout, int utf8) {
+  int bbox[8];
+  i_img *work;
+  i_color cl, cl2;
+  int x, y;
+
+  mm_log((1, "i_ft2_cp(handle %p, im %p, tx %d, ty %d, channel %d, cheight %f, cwidth %f, text %p, len %d, ...)\n", 
+         handle, im, tx, ty, channel, cheight, cwidth, text, len));
+
+  if (vlayout && !FT_HAS_VERTICAL(handle->face)) {
+    i_push_error(0, "face has no vertical metrics");
+    return 0;
+  }
+
+  if (!i_ft2_bbox_r(handle, cheight, cwidth, text, len, vlayout, utf8, bbox))
+    return 0;
+
+  work = i_img_8_new(bbox[2]-bbox[0]+1, bbox[3]-bbox[1]+1, 1);
+  cl.channel[0] = 255;
+  if (!i_ft2_text(handle, work, -bbox[0], -bbox[1], &cl, cheight, cwidth, 
+                  text, len, 1, aa, vlayout, utf8))
+    return 0;
+
+  if (!align) {
+    tx -= bbox[4];
+    ty += bbox[5];
+  }
+  
+  /* render to the specified channel */
+  /* this will be sped up ... */
+  for (y = 0; y < work->ysize; ++y) {
+    for (x = 0; x < work->xsize; ++x) {
+      i_gpix(work, x, y, &cl);
+      i_gpix(im, tx + x + bbox[0], ty + y + bbox[1], &cl2);
+      cl2.channel[channel] = cl.channel[0];
+      i_ppix(im, tx + x + bbox[0], ty + y + bbox[1], &cl2);
+    }
+  }
+  i_img_destroy(work);
+  return 1;
+}
+
+/*
+=item i_ft2_has_chars(handle, char *text, size_t len, int utf8, char *out)
+
+Check if the given characters are defined by the font.
+
+Returns the number of characters that were checked.
+
+=cut
+*/
+int i_ft2_has_chars(FT2_Fonthandle *handle, char const *text, size_t len, 
+                    int utf8, char *out) {
+  int count = 0;
+  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;
+    }
+    
+    index = FT_Get_Char_Index(handle->face, c);
+    *out++ = index != 0;
+    ++count;
+  }
+
+  return count;
+}
+
+/* uses a method described in fterrors.h to build an error translation
+   function
+*/
+#undef __FTERRORS_H__
+#define FT_ERRORDEF(e, v, s) case v: i_push_error(code, s); return;
+#define FT_ERROR_START_LIST 
+#define FT_ERROR_END_LIST 
+
+/*
+=back
+
+=head2 Internal Functions
+
+These functions are used in the implementation of freetyp2.c and should not
+(usually cannot) be called from outside it.
+
+=over
+
+=item ft2_push_message(int code)
+
+Pushes an error message corresponding to code onto the error stack.
+
+=cut
+*/
+static void ft2_push_message(int code) {
+  char unknown[40];
+
+  switch (code) {
+#include FT_ERRORS_H
+  }
+
+  sprintf(unknown, "Unknown Freetype2 error code 0x%04X\n", code);
+  i_push_error(code, unknown);
+}
+
+/*
+=item make_bmp_map(FT_Bitmap *bitmap, unsigned char *map)
+
+Creates a map to convert grey levels from the glyphs bitmap into
+values scaled 0..255.
+
+=cut
+*/
+static int
+make_bmp_map(FT_Bitmap *bitmap, unsigned char *map) {
+  int scale;
+  int i;
+
+  switch (bitmap->pixel_mode) {
+  case ft_pixel_mode_grays:
+    scale = bitmap->num_grays;
+    break;
+    
+  default:
+    i_push_errorf(0, "I can't handle pixel mode %d", bitmap->pixel_mode);
+    return 0;
+  }
+
+  /* build the table */
+  for (i = 0; i < scale; ++i)
+    map[i] = i * 255 / (bitmap->num_grays - 1);
+
+  return 1;
+}
+
+/* FREETYPE_PATCH was introduced in 2.0.6, we don't want a false 
+   positive on 2.0.0 to 2.0.4, so we accept a false negative in 2.0.5 */
+#ifndef FREETYPE_PATCH
+#define FREETYPE_PATCH 4
+#endif
+
+/* FT_Get_Postscript_Name() was introduced in FT2.0.5 */
+#define IM_HAS_FACE_NAME (FREETYPE_MINOR > 0 || FREETYPE_PATCH >= 5)
+/* #define IM_HAS_FACE_NAME 0 */ 
+
+/*
+=item i_ft2_face_name(handle, name_buf, name_buf_size)
+
+Fills the given buffer with the Postscript Face name of the font,
+if there is one.
+
+=cut
+*/
+
+int
+i_ft2_face_name(FT2_Fonthandle *handle, char *name_buf, size_t name_buf_size) {
+#if IM_HAS_FACE_NAME
+  char const *name = FT_Get_Postscript_Name(handle->face);
+
+  i_clear_error();
+
+  if (name) {
+    strncpy(name_buf, name, name_buf_size);
+    name_buf[name_buf_size-1] = '\0';
+
+    return strlen(name) + 1;
+  }
+  else {
+    i_push_error(0, "no face name available");
+    *name_buf = '\0';
+
+    return 0;
+  }
+#else
+  i_clear_error();
+  i_push_error(0, "Freetype 2.0.6 or later required");
+  *name_buf = '\0';
+
+  return 0;
+#endif
+}
+
+int
+i_ft2_can_face_name(void) {
+  return IM_HAS_FACE_NAME;
+}
+
+/* FT_Has_PS_Glyph_Names() was introduced in FT2.1.1 */
+/* well, I assume FREETYPE_MAJOR is 2, since we're here */
+#if FREETYPE_MINOR < 1 || (FREETYPE_MINOR == 1 && FREETYPE_PATCH < 1)
+#define FT_Has_PS_Glyph_Names(face) (FT_HAS_GLYPH_NAMES(face))
+#endif
+
+int
+i_ft2_glyph_name(FT2_Fonthandle *handle, unsigned long ch, char *name_buf, 
+                 size_t name_buf_size, int reliable_only) {
+#ifdef FT_CONFIG_OPTION_NO_GLYPH_NAMES
+  i_clear_error();
+  *name_buf = '\0';
+  i_push_error(0, "FT2 configured without glyph name support");
+
+  return 0;
+#else
+  FT_UInt index;
+
+  i_clear_error();
+
+  if (!FT_HAS_GLYPH_NAMES(handle->face)) {
+    i_push_error(0, "no glyph names in font");
+    *name_buf = '\0';
+    return 0;
+  }
+  if (reliable_only && !FT_Has_PS_Glyph_Names(handle->face)) {
+    i_push_error(0, "no reliable glyph names in font - set reliable_only to 0 to try anyway");
+    *name_buf = '\0';
+    return 0;
+  }
+
+  index = FT_Get_Char_Index(handle->face, ch);
+  
+  if (index) {
+    FT_Error error = FT_Get_Glyph_Name(handle->face, index, name_buf, 
+                                       name_buf_size);
+    if (error) {
+      ft2_push_message(error);
+      *name_buf = '\0';
+      return 0;
+    }
+    if (*name_buf) {
+      return strlen(name_buf) + 1;
+    }
+    else {
+      return 0;
+    }
+  }
+  else {
+    i_push_error(0, "no glyph for that character");
+    *name_buf = 0;
+    return 0;
+  }
+#endif
+}
+
+int
+i_ft2_can_do_glyph_names(void) {
+#ifdef FT_CONFIG_OPTION_NO_GLYPH_NAMES
+  return 0;
+#else
+  return 1;
+#endif
+}
+
+int 
+i_ft2_face_has_glyph_names(FT2_Fonthandle *handle) {
+#ifdef FT_CONFIG_OPTION_NO_GLYPH_NAMES
+  return 0;
+#else
+  return FT_Has_PS_Glyph_Names(handle->face);
+#endif
+}
+
+int
+i_ft2_is_multiple_master(FT2_Fonthandle *handle) {
+  i_clear_error();
+#ifdef IM_FT2_MM
+  return handle->has_mm;
+#else
+  return 0;
+#endif
+}
+
+int
+i_ft2_get_multiple_masters(FT2_Fonthandle *handle, i_font_mm *mm) {
+#ifdef IM_FT2_MM
+  int i;
+  FT_Multi_Master *mms = &handle->mm;
+
+  i_clear_error();
+  if (!handle->has_mm) {
+    i_push_error(0, "Font has no multiple masters");
+    return 0;
+  }
+  mm->num_axis = mms->num_axis;
+  mm->num_designs = mms->num_designs;
+  for (i = 0; i < mms->num_axis; ++i) {
+    mm->axis[i].name = mms->axis[i].name;
+    mm->axis[i].minimum = mms->axis[i].minimum;
+    mm->axis[i].maximum = mms->axis[i].maximum;
+  }
+
+  return 1;
+#else
+  i_clear_error();
+  i_push_error(0, "Multiple master functions unavailable");
+  return 0;
+#endif
+}
+
+int
+i_ft2_set_mm_coords(FT2_Fonthandle *handle, int coord_count, const long *coords) {
+#ifdef IM_FT2_MM
+  int i;
+  FT_Long ftcoords[T1_MAX_MM_AXIS];
+  FT_Error error;
+
+  i_clear_error();
+  if (!handle->has_mm) {
+    i_push_error(0, "Font has no multiple masters");
+    return 0;
+  }
+  if (coord_count != handle->mm.num_axis) {
+    i_push_error(0, "Number of MM coords doesn't match MM axis count");
+    return 0;
+  }
+  for (i = 0; i < coord_count; ++i)
+    ftcoords[i] = coords[i];
+
+  error = FT_Set_MM_Design_Coordinates(handle->face, coord_count, ftcoords);
+  if (error) {
+    ft2_push_message(error);
+    return 0;
+  }
+  
+  return 1;
+#else 
+  i_clear_error();
+  i_push_error(0, "Multiple master functions unavailable");
+
+  return 0;
+#endif
+}
+
+static int
+i_min(int a, int b) {
+  return a < b ? a : b;
+}
+
+static int
+i_max(int a, int b) {
+  return a > b ? a : b;
+}
+
+/*
+=back
+
+=head1 AUTHOR
+
+Tony Cook <tony@develop-help.com>, with a fair amount of help from
+reading the code in font.c.
+
+=head1 SEE ALSO
+
+font.c, Imager::Font(3), Imager(3)
+
+http://www.freetype.org/
+
+=cut
+*/
+
diff --git a/FT2/imft2.h b/FT2/imft2.h
new file mode 100644 (file)
index 0000000..b283c62
--- /dev/null
@@ -0,0 +1,47 @@
+#ifndef IMAGER_FT2_H
+#define IMAGER_FT2_H
+
+#include "imdatatypes.h"
+
+typedef struct FT2_Fonthandle FT2_Fonthandle;
+
+typedef FT2_Fonthandle* Imager__Font__FT2x;
+
+extern int i_ft2_init(void);
+extern FT2_Fonthandle * i_ft2_new(const char *name, int index);
+extern void i_ft2_destroy(FT2_Fonthandle *handle);
+extern int i_ft2_setdpi(FT2_Fonthandle *handle, int xdpi, int ydpi);
+extern int i_ft2_getdpi(FT2_Fonthandle *handle, int *xdpi, int *ydpi);
+extern int i_ft2_settransform(FT2_Fonthandle *handle, const double *matrix);
+extern int i_ft2_sethinting(FT2_Fonthandle *handle, int hinting);
+extern int i_ft2_bbox(FT2_Fonthandle *handle, double cheight, double cwidth, 
+                      char const *text, size_t len, int *bbox, int utf8);
+extern int i_ft2_bbox_r(FT2_Fonthandle *handle, double cheight, double cwidth, 
+                     char const *text, size_t len, int vlayout, int utf8, int *bbox);
+extern int i_ft2_text(FT2_Fonthandle *handle, i_img *im, int tx, int ty, 
+                      const i_color *cl, double cheight, double cwidth, 
+                      char const *text, size_t len, int align, int aa, 
+                      int vlayout, int utf8);
+extern int i_ft2_cp(FT2_Fonthandle *handle, i_img *im, int tx, int ty, 
+                    int channel, double cheight, double cwidth, 
+                    char const *text, size_t len, int align, int aa, 
+                   int vlayout, int utf8);
+extern int i_ft2_has_chars(FT2_Fonthandle *handle, char const *text, size_t len,
+                           int utf8, char *work);
+extern int i_ft2_face_name(FT2_Fonthandle *handle, char *name_buf, 
+                           size_t name_buf_size);
+extern int i_ft2_can_face_name(void);
+extern int i_ft2_glyph_name(FT2_Fonthandle *handle, unsigned long ch, 
+                            char *name_buf, size_t name_buf_size,
+                            int reliable_only);
+extern int i_ft2_can_do_glyph_names(void);
+extern int i_ft2_face_has_glyph_names(FT2_Fonthandle *handle);
+
+extern int i_ft2_get_multiple_masters(FT2_Fonthandle *handle,
+                                      i_font_mm *mm);
+extern int
+i_ft2_is_multiple_master(FT2_Fonthandle *handle);
+extern int
+i_ft2_set_mm_coords(FT2_Fonthandle *handle, int coord_count, const long *coords);
+#endif
+
diff --git a/FT2/t/t10ft2.t b/FT2/t/t10ft2.t
new file mode 100644 (file)
index 0000000..e8546eb
--- /dev/null
@@ -0,0 +1,586 @@
+#!perl -w
+use strict;
+use Test::More tests => 189;
+use Cwd qw(getcwd abs_path);
+
+use Imager qw(:all);
+
+use Imager::Test qw(diff_text_with_nul is_color3);
+
+-d "testout" or mkdir "testout";
+
+init_log("testout/t38ft2font.log",2);
+
+my $deffont = "fontfiles/dodge.ttf";
+
+my @base_color = (64, 255, 64);
+
+SKIP:
+{
+  ok($Imager::formats{ft2}, "ft2 should be in %formats");
+
+  my $fontname=$ENV{'TTFONTTEST'} || $deffont;
+
+  -f $fontname or skip("cannot find fontfile $fontname", 188);
+
+
+  my $bgcolor=i_color_new(255,0,0,0);
+  my $overlay=Imager::ImgRaw::new(200,70,3);
+  
+  my $ttraw=Imager::Font::FT2::i_ft2_new($fontname, 0);
+  
+  $ttraw or print Imager::_error_as_msg(),"\n";
+  ok($ttraw, "loaded raw font");
+
+  my @bbox=Imager::Font::FT2::i_ft2_bbox($ttraw, 50.0, 0, 'XMCLH', 0);
+  print "#bbox @bbox\n";
+  
+  is(@bbox, 8, "i_ft2_bbox() returns 8 values");
+
+  ok(Imager::Font::FT2::i_ft2_cp($ttraw,$overlay,5,50,1,50.0,50, 'XMCLH',1,1, 0, 0), "drawn to channel");
+  i_line($overlay,0,50,100,50,$bgcolor,1);
+
+  open(FH,">testout/t38ft2font.ppm") || die "cannot open testout/t38ft2font.ppm\n";
+  binmode(FH);
+  my $IO = Imager::io_new_fd(fileno(FH));
+  ok(i_writeppm_wiol($overlay, $IO), "saved image");
+  close(FH);
+
+  $bgcolor=i_color_set($bgcolor,200,200,200,0);
+  my $backgr=Imager::ImgRaw::new(500,300,3);
+  
+  #     i_tt_set_aa(2);
+  ok(Imager::Font::FT2::i_ft2_text($ttraw,$backgr,100,150,NC(255, 64, 64),200.0,50, 'MAW',1,1,0, 0), "drew MAW");
+  Imager::Font::FT2::i_ft2_settransform($ttraw, [0.9659, 0.2588, 0, -0.2588, 0.9659, 0 ]);
+  ok(Imager::Font::FT2::i_ft2_text($ttraw,$backgr,100,150,NC(0, 128, 0),200.0,50, 'MAW',0,1, 0, 0), "drew rotated MAW");
+  i_line($backgr, 0,150, 499, 150, NC(0, 0, 255),1);
+
+  open(FH,">testout/t38ft2font2.ppm") || die "cannot open testout/t38ft2font.ppm\n";
+  binmode(FH);
+  $IO = Imager::io_new_fd(fileno(FH));
+  ok(i_writeppm_wiol($backgr,$IO), "saved second image");
+  close(FH);
+
+  my $oof = Imager::Font->new(file=>$fontname, type=>'ft2', 'index'=>0);
+
+  ok($oof, "loaded OO font");
+
+  my $im = Imager->new(xsize=>400, ysize=>250);
+  
+  ok($im->string(font=>$oof,
+                 text=>"Via OO",
+                 'x'=>20,
+                 'y'=>20,
+                 size=>60,
+                 color=>NC(255, 128, 255),
+                 aa => 1,
+                 align=>0), "drawn through OO interface");
+  ok($oof->transform(matrix=>[1, 0.1, 0, 0, 1, 0]),
+     "set matrix via OO interface");
+  ok($im->string(font=>$oof,
+                 text=>"Shear",
+                 'x'=>20,
+                 'y'=>40,
+                 size=>60,
+                 sizew=>50,
+                 channel=>1,
+                 aa=>1,
+                 align=>1), "drawn transformed through OO");
+  use Imager::Matrix2d ':handy';
+  ok($oof->transform(matrix=>m2d_rotate(degrees=>-30)),
+     "set transform from m2d module");
+  ok($im->string(font=>$oof,
+                 text=>"SPIN",
+                 'x'=>20,
+                 'y'=>50,
+                 size=>50,
+                 sizew=>40,
+                 color=>NC(255,255,0),
+                 aa => 1,
+                 align=>0, vlayout=>0), "drawn first rotated");
+
+  ok($im->string(font=>$oof,
+                 text=>"SPIN",
+                 'x'=>20,
+                 'y'=>50,
+                 size=>50,
+                 sizew=>40,
+            channel=>2,
+                 aa => 1,
+                 align=>0, vlayout=>0), "drawn second rotated");
+  
+  $oof->transform(matrix=>m2d_identity());
+  $oof->hinting(hinting=>1);
+
+  # UTF8 testing
+  # the test font (dodge.ttf) only supports one character above 0xFF that
+  # I can see, 0x2010 HYPHEN (which renders the same as 0x002D HYPHEN MINUS)
+  # an attempt at utf8 support
+  # first attempt to use native perl UTF8
+ SKIP:
+  {
+    skip("no native UTF8 support in this version of perl", 1) 
+      unless $] >= 5.006;
+    my $text;
+    # we need to do this in eval to prevent compile time errors in older
+    # versions
+    eval q{$text = "A\x{2010}A"}; # A, HYPHEN, A in our test font
+    #$text = "A".chr(0x2010)."A"; # this one works too
+    unless (ok($im->string(font=>$oof,
+                           text=>$text,
+                           'x'=>20,
+                           'y'=>200,
+                           size=>50,
+                           color=>NC(0,255,0),
+                           aa=>1), "drawn UTF natively")) {
+      print "# ",$im->errstr,"\n";
+    }
+  }
+
+  # an attempt using emulation of UTF8
+  my $text = pack("C*", 0x41, 0xE2, 0x80, 0x90, 0x41);
+  #my $text = "A\xE2\x80\x90\x41\x{2010}";
+  #substr($text, -1, 0) = '';
+  unless (ok($im->string(font=>$oof,
+                         text=>$text,
+                         'x'=>20,
+                         'y'=>230,
+                         size=>50,
+                         color=>NC(255,128,0),
+                         aa=>1, 
+                         utf8=>1), "drawn UTF emulated")) {
+    print "# ",$im->errstr,"\n";
+  }
+
+  # just a bit of fun
+  # well it was - it demostrates what happens when you combine
+  # transformations and font hinting
+  for my $steps (0..39) {
+    $oof->transform(matrix=>m2d_rotate(degrees=>-$steps+5));
+    # demonstrates why we disable hinting on a doing a transform
+    # if the following line is enabled then the 0 degrees output sticks 
+    # out a bit
+    # $oof->hinting(hinting=>1);
+    $im->string(font=>$oof,
+                text=>"SPIN",
+                'x'=>160,
+                'y'=>70,
+                size=>65,
+                color=>NC(255, $steps * 5, 200-$steps * 5),
+                aa => 1,
+                align=>0, );
+  }
+
+  $im->write(file=>'testout/t38_oo.ppm')
+    or print "# could not save OO output: ",$im->errstr,"\n";
+  
+  my (@got) = $oof->has_chars(string=>"\x01H");
+  ok(@got == 2, "has_chars returned 2 items");
+  ok(!$got[0], "have no chr(1)");
+  ok($got[1], "have 'H'");
+  is($oof->has_chars(string=>"H\x01"), "\x01\x00",
+     "scalar has_chars()");
+
+  print "# OO bounding boxes\n";
+  @bbox = $oof->bounding_box(string=>"hello", size=>30);
+  my $bbox = $oof->bounding_box(string=>"hello", size=>30);
+
+  is(@bbox, 8, "list bbox returned 8 items");
+  ok($bbox->isa('Imager::Font::BBox'), "scalar bbox returned right class");
+  ok($bbox->start_offset == $bbox[0], "start_offset");
+  ok($bbox->end_offset == $bbox[2], "end_offset");
+  ok($bbox->global_ascent == $bbox[3], "global_ascent");
+  ok($bbox->global_descent == $bbox[1], "global_descent");
+  ok($bbox->ascent == $bbox[5], "ascent");
+  ok($bbox->descent == $bbox[4], "descent");
+  ok($bbox->advance_width == $bbox[6], "advance_width");
+
+  print "# aligned text output\n";
+  my $alimg = Imager->new(xsize=>300, ysize=>300);
+  $alimg->box(color=>'40FF40', filled=>1);
+
+  $oof->transform(matrix=>m2d_identity());
+  $oof->hinting(hinting=>1);
+  
+  align_test('left', 'top', 10, 10, $oof, $alimg);
+  align_test('start', 'top', 10, 40, $oof, $alimg);
+  align_test('center', 'top', 150, 70, $oof, $alimg);
+  align_test('end', 'top', 290, 100, $oof, $alimg);
+  align_test('right', 'top', 290, 130, $oof, $alimg);
+
+  align_test('center', 'top', 150, 160, $oof, $alimg);
+  align_test('center', 'center', 150, 190, $oof, $alimg);
+  align_test('center', 'bottom', 150, 220, $oof, $alimg);
+  align_test('center', 'baseline', 150, 250, $oof, $alimg);
+  
+  ok($alimg->write(file=>'testout/t38aligned.ppm'), 
+     "saving aligned output image");
+  
+  my $exfont = Imager::Font->new(file=>'fontfiles/ExistenceTest.ttf',
+                                 type=>'ft2');
+  SKIP:
+  {
+    ok($exfont, "loaded existence font")
+      or diag(Imager->errstr);
+    $exfont
+      or skip("couldn't load test font", 11);
+
+    # the test font is known to have a shorter advance width for that char
+    my @bbox = $exfont->bounding_box(string=>"/", size=>100);
+    is(@bbox, 8, "should be 8 entries");
+    isnt($bbox[6], $bbox[2], "different advance width");
+    my $bbox = $exfont->bounding_box(string=>"/", size=>100);
+    ok($bbox->pos_width != $bbox->advance_width, "OO check");
+
+    cmp_ok($bbox->right_bearing, '<', 0, "check right bearing");
+
+    cmp_ok($bbox->display_width, '>', $bbox->advance_width,
+           "check display width (roughly)");
+
+    # check with a char that fits inside the box
+    $bbox = $exfont->bounding_box(string=>"!", size=>100);
+    print "# pos width ", $bbox->pos_width, "\n";
+    is($bbox->pos_width, $bbox->advance_width, 
+       "check backwards compatibility");
+    cmp_ok($bbox->left_bearing, '>', 0, "left bearing positive");
+    cmp_ok($bbox->right_bearing, '>', 0, "right bearing positive");
+    cmp_ok($bbox->display_width, '<', $bbox->advance_width,
+           "display smaller than advance");
+
+    # name tests
+    # make sure the number of tests on each branch match
+    if (Imager::Font::FT2::i_ft2_can_face_name()) {
+      my $facename = Imager::Font::FT2::i_ft2_face_name($exfont->{id});
+      print "# face name '$facename'\n";
+      is($facename, 'ExistenceTest', "test face name");
+      $facename = $exfont->face_name;
+      is($facename, 'ExistenceTest', "test face name OO");
+    }
+    else {
+      # make sure we get the error we expect
+      my $facename = Imager::Font::FT2::i_ft2_face_name($exfont->{id});
+      my ($msg) = Imager::_error_as_msg();
+      ok(!defined($facename), "test face name not supported");
+      print "# $msg\n";
+      ok(scalar($msg =~ /or later required/), "test face name not supported");
+    }
+  }
+
+  SKIP:
+  {
+    Imager::Font::FT2->can_glyph_names
+        or skip("FT2 compiled without glyph names support", 9);
+        
+    # FT2 considers POST tables in TTF fonts unreliable, so use
+    # a type 1 font, see below for TTF test 
+    my $exfont = Imager::Font->new(file=>'fontfiles/ExistenceTest.pfb',
+                               type=>'ft2');
+  SKIP:
+    {
+      ok($exfont, "load Type 1 via FT2")
+        or skip("couldn't load type 1 with FT2", 8);
+      my @glyph_names = 
+        Imager::Font::FT2::i_ft2_glyph_name($exfont->{id}, "!J/");
+      #use Data::Dumper;
+      #print Dumper \@glyph_names;
+      is($glyph_names[0], 'exclam', "check exclam name");
+      ok(!defined($glyph_names[1]), "check for no J name");
+      is($glyph_names[2], 'slash', "check slash name");
+
+      # oo interfaces
+      @glyph_names = $exfont->glyph_names(string=>"!J/");
+      is($glyph_names[0], 'exclam', "check exclam name OO");
+      ok(!defined($glyph_names[1]), "check for no J name OO");
+      is($glyph_names[2], 'slash', "check slash name OO");
+
+      # make sure a missing string parameter is handled correctly
+      eval {
+        $exfont->glyph_names();
+      };
+      is($@, "", "correct error handling");
+      cmp_ok(Imager->errstr, '=~', qr/no string parameter/, "error message");
+    }
+  
+    # freetype 2 considers truetype glyph name tables unreliable
+    # due to some specific fonts, supplying reliable_only=>0 bypasses
+    # that check and lets us get the glyph names even for truetype fonts
+    # so we can test this stuff <sigh>
+    # we can't use ExistenceTest.ttf since that's generated with 
+    # AppleStandardEncoding since the same .sfd needs to generate
+    # a .pfb file, NameTest.ttf uses a Unicode encoding
+    
+    # we were using an unsigned char to store a unicode character
+    # https://rt.cpan.org/Ticket/Display.html?id=7949
+    $exfont = Imager::Font->new(file=>'fontfiles/NameTest.ttf',
+                                type=>'ft2');
+  SKIP:
+    {
+      ok($exfont, "load TTF via FT2")
+        or skip("could not load TTF with FT2", 1);
+      my $text = pack("C*", 0xE2, 0x80, 0x90); # "\x{2010}" as utf-8
+      my @names = $exfont->glyph_names(string=>$text,
+                                       utf8=>1, reliable_only=>0);
+      is($names[0], "hyphentwo", "check utf8 glyph name");
+    }
+  }
+
+  # check that error codes are translated correctly
+  my $errfont = Imager::Font->new(file=>"t/t10ft2.t", type=>"ft2");
+  is($errfont, undef, "new font vs non font");
+  cmp_ok(Imager->errstr, '=~', qr/unknown file format/, "check error message");
+
+  # Multiple Master tests
+  # we check a non-MM font errors correctly
+  print "# check that the methods act correctly for a non-MM font\n";
+  ok(!$exfont->is_mm, "exfont not MM");
+  ok((() = $exfont->mm_axes) == 0, "exfont has no MM axes");
+  cmp_ok(Imager->errstr, '=~', qr/no multiple masters/, 
+         "and returns correct error when we ask");
+  ok(!$exfont->set_mm_coords(coords=>[0, 0]), "fail setting axis on exfont");
+  cmp_ok(Imager->errstr, '=~', qr/no multiple masters/, 
+         "and returns correct error when we ask");
+
+  # try a MM font now - test font only has A defined
+  print "# Try a multiple master font\n";
+  my $mmfont = Imager::Font->new(file=>"fontfiles/MMOne.pfb", type=>"ft2", 
+                                 color=>"white", aa=>1, size=>60);
+  ok($mmfont, "loaded MM font");
+  ok($mmfont->is_mm, "font is multiple master");
+  my @axes = $mmfont->mm_axes;
+  is(@axes, 2, "check we got both axes");
+  is($axes[0][0], "Weight", "name of first axis");
+  is($axes[0][1],  50, "min for first axis");
+  is($axes[0][2], 999, "max for first axis");
+  is($axes[1][0], "Slant", "name of second axis");
+  is($axes[1][1],   0, "min for second axis");
+  is($axes[1][2], 999, "max for second axis");
+  my $mmim = Imager->new(xsize=>200, ysize=>200);
+  $mmim->string(font=>$mmfont, x=>0, 'y'=>50, text=>"A");
+  ok($mmfont->set_mm_coords(coords=>[ 700, 0 ]), "set to bold, unsloped");
+  $mmim->string(font=>$mmfont, x=>0, 'y'=>100, text=>"A", color=>'blue');
+  my @weights = qw(50 260 525 760 999);
+  my @slants = qw(0 333 666 999);
+  for my $windex (0 .. $#weights) {
+    my $weight = $weights[$windex];
+    for my $sindex (0 .. $#slants) {
+      my $slant = $slants[$sindex];
+      $mmfont->set_mm_coords(coords=>[ $weight, $slant ]);
+      $mmim->string(font=>$mmfont, x=>30+32*$windex, 'y'=>50+45*$sindex,
+                    text=>"A");
+    }
+  }
+
+  ok($mmim->write(file=>"testout/t38mm.ppm"), "save MM output");
+
+ SKIP:
+  { print "# alignment tests\n";
+    my $font = Imager::Font->new(file=>'fontfiles/ImUgly.ttf', type=>'ft2');
+    ok($font, "loaded deffont OO")
+      or skip("could not load font:".Imager->errstr, 4);
+    my $im = Imager->new(xsize=>140, ysize=>150);
+    my %common = 
+      (
+       font=>$font, 
+       size=>40, 
+       aa=>1,
+      );
+    $im->line(x1=>0, y1=>40, x2=>139, y2=>40, color=>'blue');
+    $im->line(x1=>0, y1=>90, x2=>139, y2=>90, color=>'blue');
+    $im->line(x1=>0, y1=>110, x2=>139, y2=>110, color=>'blue');
+    for my $args ([ x=>5,   text=>"A", color=>"white" ],
+                  [ x=>40,  text=>"y", color=>"white" ],
+                  [ x=>75,  text=>"A", channel=>1 ],
+                  [ x=>110, text=>"y", channel=>1 ]) {
+      ok($im->string(%common, @$args, 'y'=>40), "A no alignment");
+      ok($im->string(%common, @$args, 'y'=>90, align=>1), "A align=1");
+      ok($im->string(%common, @$args, 'y'=>110, align=>0), "A align=0");
+    }
+    ok($im->write(file=>'testout/t38align.ppm'), "save align image");
+  }
+
+
+  { # outputting a space in non-AA could either crash 
+    # or fail (ft 2.2+)
+    my $font = Imager::Font->new(file=>'fontfiles/ImUgly.ttf', type=>'ft2');
+    my $im = Imager->new(xsize => 100, ysize => 100);
+    ok($im->string(x => 10, y => 10, string => "test space", aa => 0,
+                  color => '#FFF', size => 8, font => $font),
+       "draw space non-antialiased (color)");
+    ok($im->string(x => 10, y => 50, string => "test space", aa => 0,
+                  channel => 0, size => 8, font => $font),
+       "draw space non-antialiased (channel)");
+  }
+
+  { # cannot output "0"
+    # https://rt.cpan.org/Ticket/Display.html?id=21770
+    my $font = Imager::Font->new(file=>'fontfiles/ImUgly.ttf', type=>'ft2');
+    ok($font, "loaded imugly");
+    my $imbase = Imager->new(xsize => 100, ysize => 100);
+    my $im = $imbase->copy;
+    ok($im->string(x => 10, y => 50, string => "0", aa => 0,
+                  color => '#FFF', size => 20, font => $font),
+       "draw '0'");
+    ok(Imager::i_img_diff($im->{IMG}, $imbase->{IMG}),
+       "make sure we actually drew it");
+    $im = $imbase->copy;
+    ok($im->string(x => 10, y => 50, string => 0.0, aa => 0,
+                  color => '#FFF', size => 20, font => $font),
+       "draw 0.0");
+    ok(Imager::i_img_diff($im->{IMG}, $imbase->{IMG}),
+       "make sure we actually drew it");
+  }
+  { # string output cut off at NUL ('\0')
+    # https://rt.cpan.org/Ticket/Display.html?id=21770 cont'd
+    my $font = Imager::Font->new(file=>'fontfiles/ImUgly.ttf', type=>'ft2');
+    ok($font, "loaded imugly");
+
+    diff_text_with_nul("a\\0b vs a", "a\0b", "a", 
+                      font => $font, color => '#FFFFFF');
+    diff_text_with_nul("a\\0b vs a", "a\0b", "a", 
+                      font => $font, channel => 1);
+
+    # UTF8 encoded \x{2010}
+    my $dash = pack("C*", 0xE2, 0x80, 0x90);
+    diff_text_with_nul("utf8 dash\0dash vs dash", "$dash\0$dash", $dash,
+                      font => $font, color => '#FFFFFF', utf8 => 1);
+    diff_text_with_nul("utf8 dash\0dash vs dash", "$dash\0$dash", $dash,
+                      font => $font, channel => 1, utf8 => 1);
+  }
+
+  { # RT 11972
+    # when rendering to a transparent image the coverage should be
+    # expressed in terms of the alpha channel rather than the color
+    my $font = Imager::Font->new(file=>'fontfiles/ImUgly.ttf', type=>'ft2');
+    my $im = Imager->new(xsize => 40, ysize => 20, channels => 4);
+    ok($im->string(string => "AB", size => 20, aa => 1, color => '#F00',
+                  x => 0, y => 15, font => $font),
+       "draw to transparent image");
+    my $im_noalpha = $im->convert(preset => 'noalpha');
+    my $im_pal = $im->to_paletted(make_colors => 'mediancut');
+    my @colors = $im_pal->getcolors;
+    is(@colors, 2, "should be only 2 colors");
+    @colors = sort { ($a->rgba)[0] <=> ($b->rgba)[0] } @colors;
+    is_color3($colors[0], 0, 0, 0, "check we got black");
+    is_color3($colors[1], 255, 0, 0, "and red");
+  }
+
+  { # RT 27546
+    my $im = Imager->new(xsize => 100, ysize => 100, channels => 4);
+    $im->box(filled => 1, color => '#ff0000FF');
+    my $font = Imager::Font->new(file=>'fontfiles/ImUgly.ttf', type=>'ft2');
+    ok($im->string(x => 0, 'y' => 40, text => 'test', 
+                  size => 11, sizew => 11, font => $font, aa => 1),
+       'draw on translucent image')
+  }
+
+  { # RT 60199
+    # not ft2 specific, but Imager
+    my $im = Imager->new(xsize => 100, ysize => 100);
+    my $font = Imager::Font->new(file=>'fontfiles/ImUgly.ttf', type=>'ft2');
+    my $imcopy = $im->copy;
+    ok($im, "make test image");
+    ok($font, "make test font");
+    ok($im->align_string(valign => "center", halign => "center",
+                        x => 50, y => 50, string => "0", color => "#FFF",
+                        font => $font),
+       "draw 0 aligned");
+    ok(Imager::i_img_diff($im->{IMG}, $imcopy->{IMG}),
+       "make sure we drew the '0'");
+  }
+
+ SKIP:
+  { # RT 60509
+    # checks that a c:foo or c:\foo path is handled correctly on win32
+    my $type = "ft2";
+    $^O eq "MSWin32" || $^O eq "cygwin"
+      or skip("only for win32", 2);
+    my $dir = getcwd
+      or skip("Cannot get cwd", 2);
+    if ($^O eq "cygwin") {
+      $dir = Cygwin::posix_to_win_path($dir);
+    }
+    my $abs_path = abs_path($deffont);
+    my $font = Imager::Font->new(file => $abs_path, type => $type);
+    ok($font, "found font by absolute path")
+      or print "# path $abs_path\n";
+    undef $font;
+
+    $^O eq "cygwin"
+      and skip("cygwin doesn't support drive relative DOSsish paths", 1);
+    my ($drive) = $dir =~ /^([a-z]:)/i
+      or skip("cwd has no drive letter", 2);
+    my $drive_path = $drive . $deffont;
+    $font = Imager::Font->new(file => $drive_path, type => $type);
+    ok($font, "found font by drive relative path")
+      or print "# path $drive_path\n";
+  }
+
+}
+
+sub align_test {
+  my ($h, $v, $x, $y, $f, $img) = @_;
+
+  my @pos = $f->align(halign=>$h, valign=>$v, 'x'=>$x, 'y'=>$y,
+                      image=>$img, size=>15, color=>'FFFFFF',
+                      string=>"x$h ${v}y", channel=>1, aa=>1);
+  @pos = $img->align_string(halign=>$h, valign=>$v, 'x'=>$x, 'y'=>$y,
+                      font=>$f, size=>15, color=>'FF99FF',
+                      string=>"x$h ${v}y", aa=>1);
+  if (ok(@pos == 4, "$h $v aligned output")) {
+    # checking corners
+    my $cx = int(($pos[0] + $pos[2]) / 2);
+    my $cy = int(($pos[1] + $pos[3]) / 2);
+    
+    print "# @pos cx $cx cy $cy\n";
+    okmatchcolor($img, $cx, $pos[1]-1, @base_color, "outer top edge");
+    okmatchcolor($img, $cx, $pos[3], @base_color, "outer bottom edge");
+    okmatchcolor($img, $pos[0]-1, $cy, @base_color, "outer left edge");
+    okmatchcolor($img, $pos[2], $cy, @base_color, "outer right edge");
+    
+    okmismatchcolor($img, $cx, $pos[1], @base_color, "inner top edge");
+    okmismatchcolor($img, $cx, $pos[3]-1, @base_color, "inner bottom edge");
+    okmismatchcolor($img, $pos[0], $cy, @base_color, "inner left edge");
+#    okmismatchcolor($img, $pos[2]-1, $cy, @base_color, "inner right edge");
+# XXX: This gets triggered by a freetype2 bug I think 
+#    $ rpm -qa | grep freetype
+#    freetype-2.1.3-6
+#
+# (addi: 4/1/2004).
+
+    cross($img, $x, $y, 'FF0000');
+    cross($img, $cx, $pos[1]-1, '0000FF');
+    cross($img, $cx, $pos[3], '0000FF');
+    cross($img, $pos[0]-1, $cy, '0000FF');
+    cross($img, $pos[2], $cy, '0000FF');
+  }
+  else {
+    SKIP: { skip("couldn't draw text", 7) };
+  }
+}
+
+sub okmatchcolor {
+  my ($img, $x, $y, $r, $g, $b, $about) = @_;
+
+  my $c = $img->getpixel('x'=>$x, 'y'=>$y);
+  my ($fr, $fg, $fb) = $c->rgba;
+  ok($fr == $r && $fg == $g && $fb == $b,
+      "want ($r,$g,$b) found ($fr,$fg,$fb)\@($x,$y) $about");
+}
+
+sub okmismatchcolor {
+  my ($img, $x, $y, $r, $g, $b, $about) = @_;
+
+  my $c = $img->getpixel('x'=>$x, 'y'=>$y);
+  my ($fr, $fg, $fb) = $c->rgba;
+  ok($fr != $r || $fg != $g || $fb != $b,
+      "don't want ($r,$g,$b) found ($fr,$fg,$fb)\@($x,$y) $about");
+}
+
+sub cross {
+  my ($img, $x, $y, $color) = @_;
+
+  $img->setpixel('x'=>[$x, $x, $x, $x, $x, $x-2, $x-1, $x+1, $x+2], 
+                 'y'=>[$y-2, $y-1, $y, $y+1, $y+2, $y, $y, $y, $y], 
+                 color => $color);
+  
+}
diff --git a/FT2/typemap b/FT2/typemap
new file mode 100644 (file)
index 0000000..385fb65
--- /dev/null
@@ -0,0 +1 @@
+Imager::Font::FT2x       T_PTROBJ
index 7349469..c6bd71a 100644 (file)
--- a/Imager.pm
+++ b/Imager.pm
@@ -1,7 +1,7 @@
 package Imager;
 
 use strict;
-use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS %formats $DEBUG %filters %DSOs $ERRSTR $fontstate %OPCODES $I2P $FORMATGUESS $warn_obsolete);
+use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS %formats $DEBUG %filters %DSOs $ERRSTR %OPCODES $I2P $FORMATGUESS $warn_obsolete);
 use IO::File;
 
 use Imager::Color;
@@ -175,18 +175,14 @@ my %format_classes =
    tiff => "Imager::File::TIFF",
    jpeg => "Imager::File::JPEG",
    w32 => "Imager::Font::W32",
+   ft2 => "Imager::Font::FT2",
   );
 
 tie %formats, "Imager::FORMATS", \%formats_low, \%format_classes;
 
 BEGIN {
-  Imager::Font::__init();
   for(i_list_formats()) { $formats_low{$_}++; }
 
-  if (!$formats_low{'t1'} and !$formats_low{'tt'} 
-      && !$formats_low{'ft2'} && !$formats_low{'w32'}) {
-    $fontstate='no font support';
-  }
   %OPCODES=(Add=>[0],Sub=>[1],Mult=>[2],Div=>[3],Parm=>[4],'sin'=>[5],'cos'=>[6],'x'=>[4,0],'y'=>[4,1]);
 
   $DEBUG=0;
@@ -3907,8 +3903,6 @@ sub _check {
 sub FETCH {
   my ($self, $key) = @_;
 
-  $DB::single = 1;
-
   exists $self->[IX_FORMATS]{$key} and return $self->[IX_FORMATS]{$key};
 
   $self->[IX_CLASSES]{$key} or return undef;
index 734a307..970d7df 100644 (file)
--- a/Imager.xs
+++ b/Imager.xs
@@ -3809,350 +3809,6 @@ i_tags_count(im)
         RETVAL
 
 
-#ifdef HAVE_FT2
-
-MODULE = Imager         PACKAGE = Imager::Font::FT2     PREFIX=FT2_
-
-#define FT2_DESTROY(font) i_ft2_destroy(font)
-
-void
-FT2_DESTROY(font)
-        Imager::Font::FT2 font
-
-int
-FT2_CLONE_SKIP(...)
-    CODE:
-        RETVAL = 1;
-    OUTPUT:
-        RETVAL
-
-MODULE = Imager         PACKAGE = Imager::Font::FreeType2 
-
-Imager::Font::FT2
-i_ft2_new(name, index)
-        char *name
-        int index
-
-undef_int
-i_ft2_setdpi(font, xdpi, ydpi)
-        Imager::Font::FT2 font
-        int xdpi
-        int ydpi
-
-void
-i_ft2_getdpi(font)
-        Imager::Font::FT2 font
-      PREINIT:
-        int xdpi, ydpi;
-      CODE:
-        if (i_ft2_getdpi(font, &xdpi, &ydpi)) {
-          EXTEND(SP, 2);
-          PUSHs(sv_2mortal(newSViv(xdpi)));
-          PUSHs(sv_2mortal(newSViv(ydpi)));
-        }
-
-undef_int
-i_ft2_sethinting(font, hinting)
-        Imager::Font::FT2 font
-        int hinting
-
-undef_int
-i_ft2_settransform(font, matrix)
-        Imager::Font::FT2 font
-      PREINIT:
-        double matrix[6];
-        int len;
-        AV *av;
-        SV *sv1;
-        int i;
-      CODE:
-        if (!SvROK(ST(1)) || SvTYPE(SvRV(ST(1))) != SVt_PVAV)
-          croak("i_ft2_settransform: parameter 2 must be an array ref\n");
-       av=(AV*)SvRV(ST(1));
-       len=av_len(av)+1;
-        if (len > 6)
-          len = 6;
-        for (i = 0; i < len; ++i) {
-         sv1=(*(av_fetch(av,i,0)));
-         matrix[i] = SvNV(sv1);
-        }
-        for (; i < 6; ++i)
-          matrix[i] = 0;
-        RETVAL = i_ft2_settransform(font, matrix);
-      OUTPUT:
-        RETVAL
-
-void
-i_ft2_bbox(font, cheight, cwidth, text_sv, utf8)
-        Imager::Font::FT2 font
-        double cheight
-        double cwidth
-        SV *text_sv
-       int utf8
-      PREINIT:
-        int bbox[BOUNDING_BOX_COUNT];
-        int i;
-        char *text;
-        STRLEN text_len;
-        int rc;
-      PPCODE:
-        text = SvPV(text_sv, text_len);
-#ifdef SvUTF8
-        if (SvUTF8(text_sv))
-          utf8 = 1;
-#endif
-        rc = i_ft2_bbox(font, cheight, cwidth, text, text_len, bbox, utf8);
-        if (rc) {
-          EXTEND(SP, rc);
-          for (i = 0; i < rc; ++i)
-            PUSHs(sv_2mortal(newSViv(bbox[i])));
-        }
-
-void
-i_ft2_bbox_r(font, cheight, cwidth, text, vlayout, utf8)
-        Imager::Font::FT2 font
-        double cheight
-        double cwidth
-        char *text
-        int vlayout
-        int utf8
-      PREINIT:
-        int bbox[8];
-        int i;
-      PPCODE:
-#ifdef SvUTF8
-        if (SvUTF8(ST(3)))
-          utf8 = 1;
-#endif
-        if (i_ft2_bbox_r(font, cheight, cwidth, text, strlen(text), vlayout,
-                         utf8, bbox)) {
-          EXTEND(SP, 8);
-          for (i = 0; i < 8; ++i)
-            PUSHs(sv_2mortal(newSViv(bbox[i])));
-        }
-
-undef_int
-i_ft2_text(font, im, tx, ty, cl, cheight, cwidth, text, align, aa, vlayout, utf8)
-        Imager::Font::FT2 font
-        Imager::ImgRaw im
-        int tx
-        int ty
-        Imager::Color cl
-        double cheight
-        double cwidth
-        int align
-        int aa
-        int vlayout
-        int utf8
-      PREINIT:
-        char *text;
-        STRLEN len;
-      CODE:
-#ifdef SvUTF8
-        if (SvUTF8(ST(7))) {
-          utf8 = 1;
-        }
-#endif
-        text = SvPV(ST(7), len);
-        RETVAL = i_ft2_text(font, im, tx, ty, cl, cheight, cwidth, text,
-                            len, align, aa, vlayout, utf8);
-      OUTPUT:
-        RETVAL
-
-undef_int
-i_ft2_cp(font, im, tx, ty, channel, cheight, cwidth, text_sv, align, aa, vlayout, utf8)
-        Imager::Font::FT2 font
-        Imager::ImgRaw im
-        int tx
-        int ty
-        int channel
-        double cheight
-        double cwidth
-        SV *text_sv
-        int align
-        int aa
-        int vlayout
-        int utf8
-      PREINIT:
-       char const *text;
-       STRLEN len;
-      CODE:
-#ifdef SvUTF8
-        if (SvUTF8(ST(7)))
-          utf8 = 1;
-#endif
-       text = SvPV(text_sv, len);
-        RETVAL = i_ft2_cp(font, im, tx, ty, channel, cheight, cwidth, text,
-                          len, align, aa, vlayout, 1);
-      OUTPUT:
-        RETVAL
-
-void
-ft2_transform_box(font, x0, x1, x2, x3)
-        Imager::Font::FT2 font
-        int x0
-        int x1
-        int x2
-        int x3
-      PREINIT:
-        int box[4];
-      PPCODE:
-        box[0] = x0; box[1] = x1; box[2] = x2; box[3] = x3;
-        ft2_transform_box(font, box);
-          EXTEND(SP, 4);
-          PUSHs(sv_2mortal(newSViv(box[0])));
-          PUSHs(sv_2mortal(newSViv(box[1])));
-          PUSHs(sv_2mortal(newSViv(box[2])));
-          PUSHs(sv_2mortal(newSViv(box[3])));
-
-void
-i_ft2_has_chars(handle, text_sv, utf8)
-        Imager::Font::FT2 handle
-        SV  *text_sv
-        int utf8
-      PREINIT:
-        char *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_ft2_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);
-
-void
-i_ft2_face_name(handle)
-        Imager::Font::FT2 handle
-      PREINIT:
-        char name[255];
-        int len;
-      PPCODE:
-        len = i_ft2_face_name(handle, name, sizeof(name));
-        if (len) {
-          EXTEND(SP, 1);
-          PUSHs(sv_2mortal(newSVpv(name, 0)));
-        }
-
-undef_int
-i_ft2_can_face_name()
-
-void
-i_ft2_glyph_name(handle, text_sv, utf8 = 0, reliable_only = 1)
-        Imager::Font::FT2 handle
-        SV *text_sv
-        int utf8
-        int reliable_only
-      PREINIT:
-        char const *text;
-        STRLEN work_len;
-        size_t len;
-        char name[255];
-      PPCODE:
-#ifdef SvUTF8
-        if (SvUTF8(text_sv))
-          utf8 = 1;
-#endif
-        text = SvPV(text_sv, work_len);
-        len = work_len;
-        while (len) {
-          unsigned long ch;
-          if (utf8) {
-            ch = i_utf8_advance(&text, &len);
-            if (ch == ~0UL) {
-              i_push_error(0, "invalid UTF8 character");
-              break;
-            }
-          }
-          else {
-            ch = *text++;
-            --len;
-          }
-          EXTEND(SP, 1);
-          if (i_ft2_glyph_name(handle, ch, name, sizeof(name), 
-                                         reliable_only)) {
-            PUSHs(sv_2mortal(newSVpv(name, 0)));
-          }
-          else {
-            PUSHs(&PL_sv_undef);
-          } 
-        }
-
-int
-i_ft2_can_do_glyph_names()
-
-int
-i_ft2_face_has_glyph_names(handle)
-        Imager::Font::FT2 handle
-
-int
-i_ft2_is_multiple_master(handle)
-        Imager::Font::FT2 handle
-
-void
-i_ft2_get_multiple_masters(handle)
-        Imager::Font::FT2 handle
-      PREINIT:
-        i_font_mm mm;
-        int i;
-      PPCODE:
-        if (i_ft2_get_multiple_masters(handle, &mm)) {
-          EXTEND(SP, 2+mm.num_axis);
-          PUSHs(sv_2mortal(newSViv(mm.num_axis)));
-          PUSHs(sv_2mortal(newSViv(mm.num_designs)));
-          for (i = 0; i < mm.num_axis; ++i) {
-            AV *av = newAV();
-            SV *sv;
-            av_extend(av, 3);
-            sv = newSVpv(mm.axis[i].name, strlen(mm.axis[i].name));
-            SvREFCNT_inc(sv);
-            av_store(av, 0, sv);
-            sv = newSViv(mm.axis[i].minimum);
-            SvREFCNT_inc(sv);
-            av_store(av, 1, sv);
-            sv = newSViv(mm.axis[i].maximum);
-            SvREFCNT_inc(sv);
-            av_store(av, 2, sv);
-            PUSHs(newRV_noinc((SV *)av));
-          }
-        }
-
-undef_int
-i_ft2_set_mm_coords(handle, ...)
-        Imager::Font::FT2 handle
-      PROTOTYPE: DISABLE
-      PREINIT:
-        long *coords;
-        int ix_coords, i;
-      CODE:
-        /* T_ARRAY handling by xsubpp seems to be busted in 5.6.1, so
-           transfer the array manually */
-        ix_coords = items-1;
-        coords = mymalloc(sizeof(long) * ix_coords);
-       for (i = 0; i < ix_coords; ++i) {
-          coords[i] = (long)SvIV(ST(1+i));
-        }
-        RETVAL = i_ft2_set_mm_coords(handle, ix_coords, coords);
-        myfree(coords);
-      OUTPUT:
-        RETVAL
-
-#endif
 
 MODULE = Imager         PACKAGE = Imager::FillHandle PREFIX=IFILL_
 
index 1663c43..dc9d06e 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -9,6 +9,19 @@ DynTest/DynTest.xs
 DynTest/Makefile.PL
 DynTest/linstretch.c
 DynTest/t/t00dyntest.t
+FT2/Makefile.PL
+FT2/FT2.pm
+FT2/FT2.xs
+FT2/freetyp2.c Implements freetype2 font support
+FT2/fontfiles/dodge.ttf
+FT2/fontfiles/ExistenceTest.afm
+FT2/fontfiles/ExistenceTest.pfb
+FT2/fontfiles/ExistenceTest.ttf
+FT2/fontfiles/ImUgly.ttf
+FT2/fontfiles/MMOne.pfb                multiple master test font
+FT2/fontfiles/NameTest.ttf
+FT2/imft2.h
+FT2/typemap
 Flines/Flines.pm
 Flines/Flines.xs
 Flines/Makefile.PL
@@ -192,14 +205,12 @@ fontfiles/ExistenceTest.afm     please edit ExistenceTest.sfd in CVS
 fontfiles/ExistenceTest.pfb     to change these files, edited and
 fontfiles/ExistenceTest.ttf     generated using pfaedit
 fontfiles/ImUgly.ttf
-fontfiles/MMOne.pfb            multiple master test font
-fontfiles/NameTest.ttf          test glyph_names() - see t38ft2font.t
+fontfiles/NameTest.ttf          test glyph_names() - see FT2/t/t10ft2.t
 fontfiles/SpaceTest.afm
 fontfiles/SpaceTest.pfb                test bounding box with spaces in t30t1font.t
 fontfiles/dcr10.afm
 fontfiles/dcr10.pfb
 fontfiles/dodge.ttf
-freetyp2.c     Implements freetype2 font support
 gaussian.im
 hlines.c       Manage sets of horizontal line segments
 image.c
@@ -329,7 +340,6 @@ t/t21draw.t             Basic drawing tests
 t/t30t1font.t
 t/t35ttfont.t
 t/t36oofont.t
-t/t38ft2font.t         Tests freetype2 support
 t/t40scale.t
 t/t50basicoo.t
 t/t55trans.t
index 7ddb5dd..8b9a8db 100644 (file)
@@ -641,25 +641,25 @@ are alot of badly designed fonts out there.}
 # This currently only works on under normal Win32 and cygwin.
 # DOCS
 #                  };
-  $formats{'freetype2'} = 
-  {
-   order=>'29',
-   def=>'HAVE_FT2',
-   # we always use a probe function
-   #inccheck=>sub { -e catfile($_[0], 'ft2build.h') },
-   #libcheck=>sub { $_[0] eq "libfreetype$aext" or $_[0] eq "libfreetype.$lext" },
-   libfiles=>'-lfreetype',
-   objfiles=>'freetyp2.o',
-   docs=><<DOCS,
-Freetype 2 supports both Truetype and Type 1 fonts, both of which are
-scalable.  It also supports a variety of other fonts.
-DOCS
-   code =>
-   [ 
-    \&freetype2_probe_ftconfig,
-    \&freetype2_probe_scan
-   ],
-  };
+  $formats{'freetype2'} = 
+  {
+   order=>'29',
+   def=>'HAVE_FT2',
+   # we always use a probe function
+   #inccheck=>sub { -e catfile($_[0], 'ft2build.h') },
+   #libcheck=>sub { $_[0] eq "libfreetype$aext" or $_[0] eq "libfreetype.$lext" },
+   libfiles=>'-lfreetype',
+   objfiles=>'freetyp2.o',
+   docs=><<DOCS,
+Freetype 2 supports both Truetype and Type 1 fonts, both of which are
+scalable.  It also supports a variety of other fonts.
+DOCS
+   code =>
+   [ 
+    \&freetype2_probe_ftconfig,
+    \&freetype2_probe_scan
+   ],
+  };
 
   # Make fix indent
   for (keys %formats) { $formats{$_}->{docs} =~ s/^\s+/  /mg; }
@@ -726,17 +726,17 @@ EOS
   close CONFIG;
 }
 
-# use pkg-config to probe for libraries
-# works around the junk that pkg-config dumps on FreeBSD
-sub _pkg_probe {
-  my ($pkg) = @_;
+# use pkg-config to probe for libraries
+# works around the junk that pkg-config dumps on FreeBSD
+sub _pkg_probe {
+  my ($pkg) = @_;
 
-  is_exe('pkg-config') or return;
+  is_exe('pkg-config') or return;
 
-  my $redir = $^O eq 'MSWin32' ? '' : '2>/dev/null';
+  my $redir = $^O eq 'MSWin32' ? '' : '2>/dev/null';
 
-  !system("pkg-config $pkg --exists $redir");
-}
+  !system("pkg-config $pkg --exists $redir");
+}
 
 # probes for freetype1 by scanning @incs for the includes and 
 # @libs for the libs.  This is done separately because freetype's headers
@@ -787,111 +787,111 @@ sub freetype1_probe {
 }
 
 # probes for freetype2 by trying to run freetype-config
-sub freetype2_probe_ftconfig {
-  my ($frm, $frmkey) = @_;
-
-  is_exe('freetype-config') or return;
-
-  my $cflags = `freetype-config --cflags`
-    and !$? or return;
-  chomp $cflags;
-
-  my $lflags = `freetype-config --libs`
-    and !$? or return;
-  chomp $lflags;
-
-  # before 2.1.5 freetype-config --cflags could output
-  # the -I options in the wrong order, causing a conflict with
-  # freetype1.x installed with the same --prefix
-  #
-  # can happen iff:
-  #  - both -Iprefix/include and -Iprefix/include/freetype2 are in cflags
-  #    in that order
-  #  - freetype 1.x headers are in prefix/include/freetype
-  my @incdirs = map substr($_, 2), grep /^-I/, split ' ', $cflags;
-  if (@incdirs == 2 
-      && $incdirs[1] eq "$incdirs[0]/freetype2"
-      && -e "$incdirs[0]/freetype/freetype.h"
-      && -e "$incdirs[0]/freetype/fterrid.h") {
-    print "** freetype-config provided -I options out of order, correcting\n"
-      if $VERBOSE;
-    $cflags = join(' ', grep(!/-I/, split ' ', $cflags),
-                  map "-I$_", reverse @incdirs);
-  }
-  $frm->{cflags} = $cflags;
-  $frm->{lflags} = $lflags;
+sub freetype2_probe_ftconfig {
+  my ($frm, $frmkey) = @_;
+
+  is_exe('freetype-config') or return;
+
+  my $cflags = `freetype-config --cflags`
+    and !$? or return;
+  chomp $cflags;
+
+  my $lflags = `freetype-config --libs`
+    and !$? or return;
+  chomp $lflags;
+
+  # before 2.1.5 freetype-config --cflags could output
+  # the -I options in the wrong order, causing a conflict with
+  # freetype1.x installed with the same --prefix
+  #
+  # can happen iff:
+  #  - both -Iprefix/include and -Iprefix/include/freetype2 are in cflags
+  #    in that order
+  #  - freetype 1.x headers are in prefix/include/freetype
+  my @incdirs = map substr($_, 2), grep /^-I/, split ' ', $cflags;
+  if (@incdirs == 2 
+      && $incdirs[1] eq "$incdirs[0]/freetype2"
+      && -e "$incdirs[0]/freetype/freetype.h"
+      && -e "$incdirs[0]/freetype/fterrid.h") {
+    print "** freetype-config provided -I options out of order, correcting\n"
+      if $VERBOSE;
+    $cflags = join(' ', grep(!/-I/, split ' ', $cflags),
+#                 map "-I$_", reverse @incdirs);
+  }
+  $frm->{cflags} = $cflags;
+  $frm->{lflags} = $lflags;
 
-  printf "%10s: configured via freetype-config\n", $frmkey;
+  printf "%10s: configured via freetype-config\n", $frmkey;
 
-  return 1;
-}
+  return 1;
+}
 
 # attempt to probe for freetype2 by scanning directories
 # we can't use the normal scan since we need to find the directory
 # containing most of the includes
-sub freetype2_probe_scan {
-  my ($frm, $frmkey) = @_;
-
-  my $found_inc;
-  my $found_inc2;
- INCS:
-  for my $inc (@incs) {
-    my $path = File::Spec->catfile($inc, 'ft2build.h');
-    -e $path or next;
-
-    # try to find what it's including
-    my $ftheader;
-    open FT2BUILD, "< $path"
-      or next;
-    while (<FT2BUILD>) {
-      if (m!^\s*\#\s*include\s+<([\w/.]+)>!
-         || m!^\s*\#\s*include\s+"([\w/.]+)"!) {
-       $ftheader = $1;
-       last;
-      }
-    }
-    close FT2BUILD;
-    $ftheader
-      or next;
-    # non-Unix installs put this directly under the same directory in
-    # theory
-    if (-e File::Spec->catfile($inc, $ftheader)) {
-      $found_inc = $inc;
-      last INCS;
-    }
-    for my $subdir (qw/freetype2 freetype/) {
-      $path = File::Spec->catfile($inc, $subdir, 'fterrors.h');
-      -e $path and next;
+sub freetype2_probe_scan {
+  my ($frm, $frmkey) = @_;
+
+  my $found_inc;
+  my $found_inc2;
+ INCS:
+  for my $inc (@incs) {
+    my $path = File::Spec->catfile($inc, 'ft2build.h');
+    -e $path or next;
+
+    # try to find what it's including
+    my $ftheader;
+    open FT2BUILD, "< $path"
+      or next;
+    while (<FT2BUILD>) {
+      if (m!^\s*\#\s*include\s+<([\w/.]+)>!
+#        || m!^\s*\#\s*include\s+"([\w/.]+)"!) {
+#      $ftheader = $1;
+#      last;
+      }
+    }
+    close FT2BUILD;
+    $ftheader
+      or next;
+    # non-Unix installs put this directly under the same directory in
+    # theory
+    if (-e File::Spec->catfile($inc, $ftheader)) {
+      $found_inc = $inc;
+      last INCS;
+    }
+    for my $subdir (qw/freetype2 freetype/) {
+      $path = File::Spec->catfile($inc, $subdir, 'fterrors.h');
+      -e $path and next;
 
-      $found_inc = $inc;
-      $found_inc2 = File::Spec->catdir($inc, $subdir);
-      last INCS;
-    }
-  }
+      $found_inc = $inc;
+      $found_inc2 = File::Spec->catdir($inc, $subdir);
+      last INCS;
+    }
+  }
 
-  my $found_lib;
- LIBS:
-  for my $lib (@libs) {
-    my $a_path = File::Spec->catfile($lib, "libfreetype$aext");
-    my $l_path = File::Spec->catfile($lib, "libfreetype.$lext");
-    if (-e $a_path || -e $l_path) {
-      $found_lib = $lib;
-      last LIBS;
-    }
-  }
+  my $found_lib;
+ LIBS:
+  for my $lib (@libs) {
+    my $a_path = File::Spec->catfile($lib, "libfreetype$aext");
+    my $l_path = File::Spec->catfile($lib, "libfreetype.$lext");
+    if (-e $a_path || -e $l_path) {
+      $found_lib = $lib;
+      last LIBS;
+    }
+  }
 
-  printf("%10s: includes %s - libraries %s\n", $frmkey,
-        ($found_inc ? 'found' : 'not found'), 
-        ($found_lib ? 'found' : 'not found'));
+  printf("%10s: includes %s - libraries %s\n", $frmkey,
+#       ($found_inc ? 'found' : 'not found'), 
+#       ($found_lib ? 'found' : 'not found'));
 
-  return unless $found_inc && $found_lib;
+  return unless $found_inc && $found_lib;
 
-  $frm->{cflags} = _make_I($found_inc);
-  $frm->{cflags} .= " " . _make_I($found_inc2) if $found_inc2;
-  $frm->{libfiles} = "-lfreetype";
+  $frm->{cflags} = _make_I($found_inc);
+  $frm->{cflags} .= " " . _make_I($found_inc2) if $found_inc2;
+  $frm->{libfiles} = "-lfreetype";
 
-  return 1;
-}
+  return 1;
+}
 
 sub _make_I {
   my ($inc_dir) = @_;
@@ -903,57 +903,57 @@ sub _make_I {
 }
 
 # probes for libpng via pkg-config
-sub png_probe {
-  my ($frm, $frmkey) = @_;
+sub png_probe {
+  my ($frm, $frmkey) = @_;
 
-  is_exe('pkg-config') or return;
+  is_exe('pkg-config') or return;
 
-  my $config;
-  for my $check_conf (qw(libpng libpng12 libpng10)) {
-    if (_pkg_probe($check_conf)) {
-      $config = $check_conf;
-      last;
-    }
-  }
-  $config or return;
+  my $config;
+  for my $check_conf (qw(libpng libpng12 libpng10)) {
+    if (_pkg_probe($check_conf)) {
+      $config = $check_conf;
+      last;
+    }
+  }
+  $config or return;
 
-  my $cflags = `pkg-config $config --cflags`
-    and !$? or return;
+  my $cflags = `pkg-config $config --cflags`
+    and !$? or return;
 
-  my $lflags = `pkg-config $config --libs`
-    and !$? or return;
+  my $lflags = `pkg-config $config --libs`
+    and !$? or return;
 
-  chomp $cflags;
-  chomp $lflags;
-  $frm->{cflags} = $cflags;
-  $frm->{lflags} = $lflags;
+  chomp $cflags;
+  chomp $lflags;
+  $frm->{cflags} = $cflags;
+  $frm->{lflags} = $lflags;
 
-  printf "%10s: configured via `pkg-config $config ...`\n", $frmkey;
+  printf "%10s: configured via `pkg-config $config ...`\n", $frmkey;
 
-  return 1;
-}
+  return 1;
+}
 
 sub catfile {
   return File::Spec->catfile(@_);
 }
 
-sub is_exe {
-  my ($name) = @_;
+sub is_exe {
+  my ($name) = @_;
 
-  my @exe_suffix = $Config{_exe};
-  if ($^O eq 'MSWin32') {
-    push @exe_suffix, qw/.bat .cmd/;
-  }
+  my @exe_suffix = $Config{_exe};
+  if ($^O eq 'MSWin32') {
+    push @exe_suffix, qw/.bat .cmd/;
+  }
 
-  for my $dir (File::Spec->path) {
-    for my $suffix (@exe_suffix) {
-      -x catfile($dir, "$name$suffix")
-       and return 1;
-    }
-  }
+  for my $dir (File::Spec->path) {
+    for my $suffix (@exe_suffix) {
+      -x catfile($dir, "$name$suffix")
+#      and return 1;
+    }
+  }
 
-  return;
-}
+  return;
+}
 
 sub usage {
   print STDERR <<EOS;
index 87c79b3..7a8e593 100644 (file)
@@ -128,7 +128,7 @@ for my $cat (sort { lc $a cmp lc $b } keys %cats) {
   print OUT "\n=back\n\n";
 }
 
-# see if we have an uncategorized section
+# see if we have an uncategorised section
 if (grep $alldocs{$_}, keys %undoc) {
   print OUT "=head2 Uncategorized functions\n\n=over\n\n";
   #print join(",", grep !exists $order{$_}, @funcs), "\n";
diff --git a/fills.c b/fills.c
index 0e8f417..b92eaaf 100644 (file)
--- a/fills.c
+++ b/fills.c
@@ -163,10 +163,10 @@ typedef struct
   i_fcolor fc;
 } i_fill_solid_t;
 
-static void fill_solid(i_fill_t *, int x, int y, int width, int channels, 
-                       i_color *);
-static void fill_solidf(i_fill_t *, int x, int y, int width, int channels, 
-                        i_fcolor *);
+static void fill_solid(i_fill_t *, i_img_dim x, i_img_dim y, i_img_dim width,
+                      int channels, i_color *);
+static void fill_solidf(i_fill_t *, i_img_dim x, i_img_dim y, i_img_dim width,
+                       int channels, i_fcolor *);
 
 static i_fill_solid_t base_solid_fill =
 {
@@ -401,10 +401,10 @@ typedef struct
   int dx, dy;
 } i_fill_hatch_t;
 
-static void fill_hatch(i_fill_t *fill, int x, int y, int width, int channels, 
-                       i_color *data);
-static void fill_hatchf(i_fill_t *fill, int x, int y, int width, int channels, 
-                        i_fcolor *data);
+static void fill_hatch(i_fill_t *fill, i_img_dim x, i_img_dim y,
+                      i_img_dim width, int channels, i_color *data);
+static void fill_hatchf(i_fill_t *fill, i_img_dim x, i_img_dim y,
+                       i_img_dim width, int channels, i_fcolor *data);
 static
 i_fill_t *
 i_new_hatch_low(const i_color *fg, const i_color *bg, const i_fcolor *ffg, const i_fcolor *fbg, 
@@ -467,10 +467,10 @@ i_new_fill_hatchf(const i_fcolor *fg, const i_fcolor *bg, int combine, int hatch
                          dx, dy);
 }
 
-static void fill_image(i_fill_t *fill, int x, int y, int width, int channels,
-                       i_color *data);
-static void fill_imagef(i_fill_t *fill, int x, int y, int width, int channels,
-                       i_fcolor *data);
+static void fill_image(i_fill_t *fill, i_img_dim x, i_img_dim y,
+                      i_img_dim width, int channels, i_color *data);
+static void fill_imagef(i_fill_t *fill, i_img_dim x, i_img_dim y,
+                       i_img_dim width, int channels, i_fcolor *data);
 struct i_fill_image_t {
   i_fill_t base;
   i_img *src;
@@ -533,10 +533,10 @@ i_new_fill_image(i_img *im, const double *matrix, int xoff, int yoff, int combin
   return &fill->base;
 }
 
-static void fill_opacity(i_fill_t *fill, int x, int y, int width, int channels,
-                       i_color *data);
-static void fill_opacityf(i_fill_t *fill, int x, int y, int width, int channels,
-                       i_fcolor *data);
+static void fill_opacity(i_fill_t *fill, i_img_dim x, i_img_dim y,
+                        i_img_dim width, int channels, i_color *data);
+static void fill_opacityf(i_fill_t *fill, i_img_dim x, i_img_dim y,
+                         i_img_dim width, int channels, i_fcolor *data);
 
 struct i_fill_opacity_t {
   i_fill_t base;
@@ -587,8 +587,8 @@ The 8-bit sample fill function for non-combining solid fills.
 =cut
 */
 static void
-fill_solid(i_fill_t *fill, int x, int y, int width, int channels, 
-           i_color *data) {
+fill_solid(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
+          int channels, i_color *data) {
   i_color c = T_SOLID_FILL(fill)->c;
   i_adapt_colors(channels > 2 ? 4 : 2, 4, &c, 1);
   while (width-- > 0) {
@@ -604,8 +604,8 @@ The floating sample fill function for non-combining solid fills.
 =cut
 */
 static void
-fill_solidf(i_fill_t *fill, int x, int y, int width, int channels, 
-           i_fcolor *data) {
+fill_solidf(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
+           int channels, i_fcolor *data) {
   i_fcolor c = T_SOLID_FILL(fill)->fc;
   i_adapt_fcolors(channels > 2 ? 4 : 2, 4, &c, 1);
   while (width-- > 0) {
@@ -686,8 +686,9 @@ The 8-bit sample fill function for hatched fills.
 
 =cut
 */
-static void fill_hatch(i_fill_t *fill, int x, int y, int width, int channels, 
-                       i_color *data) {
+static void 
+fill_hatch(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
+          int channels, i_color *data) {
   i_fill_hatch_t *f = (i_fill_hatch_t *)fill;
   int byte = f->hatch[(y + f->dy) & 7];
   int xpos = (x + f->dx) & 7;
@@ -719,8 +720,9 @@ The floating sample fill function for hatched fills.
 
 =back
 */
-static void fill_hatchf(i_fill_t *fill, int x, int y, int width, int channels, 
-                        i_fcolor *data) {
+static void
+fill_hatchf(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
+           int channels, i_fcolor *data) {
   i_fill_hatch_t *f = (i_fill_hatch_t *)fill;
   int byte = f->hatch[(y + f->dy) & 7];
   int xpos = (x + f->dx) & 7;
@@ -793,10 +795,11 @@ static i_fcolor interp_i_fcolor(i_fcolor before, i_fcolor after, double pos,
 
 =cut
 */
-static void fill_image(i_fill_t *fill, int x, int y, int width, int channels,
-                       i_color *data) {
+static void
+fill_image(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
+          int channels, i_color *data) {
   struct i_fill_image_t *f = (struct i_fill_image_t *)fill;
-  int i = 0;
+  i_img_dim i = 0;
   i_color *out = data;
   int want_channels = channels > 2 ? 4 : 2;
   
@@ -809,7 +812,7 @@ static void fill_image(i_fill_t *fill, int x, int y, int width, int channels,
       double iy = floor(ry / f->src->ysize);
       i_color c[2][2];
       i_color c2[2];
-      int dy;
+      i_img_dim dy;
 
       if (f->xoff) {
         rx += iy * f->xoff;
@@ -841,10 +844,10 @@ static void fill_image(i_fill_t *fill, int x, int y, int width, int channels,
     /* the easy way */
     /* this should be possible to optimize to use i_glin() */
     while (i < width) {
-      int rx = x+i;
-      int ry = y;
-      int ix = rx / f->src->xsize;
-      int iy = ry / f->src->ysize;
+      i_img_dim rx = x+i;
+      i_img_dim ry = y;
+      i_img_dim ix = rx / f->src->xsize;
+      i_img_dim iy = ry / f->src->ysize;
 
       if (f->xoff) {
         rx += iy * f->xoff;
@@ -870,10 +873,11 @@ static void fill_image(i_fill_t *fill, int x, int y, int width, int channels,
 
 =cut
 */
-static void fill_imagef(i_fill_t *fill, int x, int y, int width, int channels,
-                       i_fcolor *data) {
+static void
+fill_imagef(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
+           int channels, i_fcolor *data) {
   struct i_fill_image_t *f = (struct i_fill_image_t *)fill;
-  int i = 0;
+  i_img_dim i = 0;
   int want_channels = channels > 2 ? 4 : 2;
   
   if (f->has_matrix) {
@@ -886,7 +890,7 @@ static void fill_imagef(i_fill_t *fill, int x, int y, int width, int channels,
       double iy = floor(ry / f->src->ysize);
       i_fcolor c[2][2];
       i_fcolor c2[2];
-      int dy;
+      i_img_dim dy;
 
       if (f->xoff) {
         rx += iy * f->xoff;
@@ -919,10 +923,10 @@ static void fill_imagef(i_fill_t *fill, int x, int y, int width, int channels,
     /* the easy way */
     /* this should be possible to optimize to use i_glin() */
     while (i < width) {
-      int rx = x+i;
-      int ry = y;
-      int ix = rx / f->src->xsize;
-      int iy = ry / f->src->ysize;
+      i_img_dim rx = x+i;
+      i_img_dim ry = y;
+      i_img_dim ix = rx / f->src->xsize;
+      i_img_dim iy = ry / f->src->ysize;
 
       if (f->xoff) {
         rx += iy * f->xoff;
@@ -944,8 +948,8 @@ static void fill_imagef(i_fill_t *fill, int x, int y, int width, int channels,
 }
 
 static void 
-fill_opacity(i_fill_t *fill, int x, int y, int width, int channels,
-            i_color *data) {
+fill_opacity(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
+            int channels, i_color *data) {
   struct i_fill_opacity_t *f = (struct i_fill_opacity_t *)fill;
   int alpha_chan = channels > 2 ? 3 : 1;
   i_color *datap = data;
@@ -963,8 +967,8 @@ fill_opacity(i_fill_t *fill, int x, int y, int width, int channels,
   }
 }
 static void 
-fill_opacityf(i_fill_t *fill, int x, int y, int width, int channels,
-           i_fcolor *data) {
+fill_opacityf(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
+             int channels, i_fcolor *data) {
   struct i_fill_opacity_t *f = (struct i_fill_opacity_t *)fill;
   int alpha_chan = channels > 2 ? 3 : 1;
   i_fcolor *datap = data;
index b27514e..9ebb0af 100644 (file)
@@ -1729,7 +1729,7 @@ typedef struct {
 } i_fill_fountain_t;
 
 static void
-fill_fountf(i_fill_t *fill, int x, int y, int width, int channels, 
+fill_fountf(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width, int channels, 
             i_fcolor *data);
 static void
 fount_fill_destroy(i_fill_t *fill);
@@ -2367,8 +2367,8 @@ The fill function for fountain fills.
 =cut
 */
 static void
-fill_fountf(i_fill_t *fill, int x, int y, int width, int channels, 
-            i_fcolor *data) {
+fill_fountf(i_fill_t *fill, i_img_dim x, i_img_dim y, i_img_dim width,
+           int channels, i_fcolor *data) {
   i_fill_fountain_t *f = (i_fill_fountain_t *)fill;
   
   while (width--) {
diff --git a/fontfiles/MMOne.pfb b/fontfiles/MMOne.pfb
deleted file mode 100644 (file)
index 7f83901..0000000
Binary files a/fontfiles/MMOne.pfb and /dev/null differ
diff --git a/freetyp2.c b/freetyp2.c
deleted file mode 100644 (file)
index 5076040..0000000
+++ /dev/null
@@ -1,1148 +0,0 @@
-/*
-=head1 NAME
-
-freetyp2.c - font support via the FreeType library version 2.
-
-=head1 SYNOPSIS
-
-  if (!i_ft2_init()) { error }
-  FT2_Fonthandle *font;
-  font = i_ft2_new(name, index);
-  if (!i_ft2_setdpi(font, xdpi, ydpi)) { error }
-  if (!i_ft2_getdpi(font, &xdpi, &ydpi)) { error }
-  double matrix[6];
-  if (!i_ft2_settransform(font, matrix)) { error }
-  int bbox[BOUNDING_BOX_COUNT];
-  if (!i_ft2_bbox(font, cheight, cwidth, text, length, bbox, utf8)) { error }
-  i_img *im = ...;
-  i_color cl;
-  if (!i_ft2_text(font, im, tx, ty, cl, cheight, cwidth, text, length, align,
-                  aa)) { error }
-  if (!i_ft2_cp(font, im, tx, ty, channel, cheight, cwidth, text, length,
-                align, aa)) { error }
-  i_ft2_destroy(font);
-
-=head1 DESCRIPTION
-
-Implements Imager font support using the FreeType2 library.
-
-The FreeType2 library understands several font file types, including
-Truetype, Type1 and Windows FNT.
-
-=over 
-
-=cut
-*/
-
-#include "imager.h"
-#include <stdio.h>
-#include <ft2build.h>
-#include FT_FREETYPE_H
-#ifdef FT_MULTIPLE_MASTERS_H
-#ifndef T1_CONFIG_OPTION_NO_MM_SUPPORT
-#define IM_FT2_MM
-#include FT_MULTIPLE_MASTERS_H
-#endif
-#endif
-
-static void ft2_push_message(int code);
-
-static int ft2_initialized = 0;
-static FT_Library library;
-
-/*
-=item i_ft2_init(void)
-
-Initializes the Freetype 2 library.
-
-Returns true on success, false on failure.
-
-=cut
-*/
-int
-i_ft2_init(void) {
-  FT_Error error;
-
-  i_clear_error();
-  error = FT_Init_FreeType(&library);
-  if (error) {
-    ft2_push_message(error);
-    i_push_error(0, "Initializing Freetype2");
-    return 0;
-  }
-
-  ft2_initialized = 1;
-
-  return 1;
-}
-
-struct FT2_Fonthandle {
-  FT_Face face;
-  int xdpi, ydpi;
-  int hint;
-  FT_Encoding encoding;
-
-  /* used to adjust so we can align the draw point to the top-left */
-  double matrix[6];
-
-#ifdef IM_FT2_MM
-  /* Multiple master data if any */
-  int has_mm;
-  FT_Multi_Master mm;
-#endif
-};
-
-/* the following is used to select a "best" encoding */
-static struct enc_score {
-  FT_Encoding encoding;
-  int score;
-} enc_scores[] =
-{
-  /* the selections here are fairly arbitrary
-     ideally we need to give the user a list of encodings available
-     and a mechanism to choose one */
-  { ft_encoding_unicode,        10 },
-  { ft_encoding_sjis,            8 },
-  { ft_encoding_gb2312,          8 },
-  { ft_encoding_big5,            8 },
-  { ft_encoding_wansung,         8 },
-  { ft_encoding_johab,           8 },  
-  { ft_encoding_latin_2,         6 },
-  { ft_encoding_apple_roman,     6 },
-  { ft_encoding_adobe_standard,  6 },
-  { ft_encoding_adobe_expert,    6 },
-};
-
-/*
-=item i_ft2_new(char *name, int index)
-
-Creates a new font object, from the file given by I<name>.  I<index>
-is the index of the font in a file with multiple fonts, where 0 is the
-first font.
-
-Return NULL on failure.
-
-=cut
-*/
-
-FT2_Fonthandle *
-i_ft2_new(const char *name, int index) {
-  FT_Error error;
-  FT2_Fonthandle *result;
-  FT_Face face;
-  int i, j;
-  FT_Encoding encoding;
-  int score;
-
-  mm_log((1, "i_ft2_new(name %p, index %d)\n", name, index));
-
-  if (!ft2_initialized && !i_ft2_init())
-    return NULL;
-
-  i_clear_error();
-  error = FT_New_Face(library, name, index, &face);
-  if (error) {
-    ft2_push_message(error);
-    i_push_error(error, "Opening face");
-    mm_log((2, "error opening face '%s': %d\n", name, error));
-    return NULL;
-  }
-
-  encoding = face->num_charmaps ? face->charmaps[0]->encoding : ft_encoding_unicode;
-  score = 0;
-  for (i = 0; i < face->num_charmaps; ++i) {
-    FT_Encoding enc_entry = face->charmaps[i]->encoding;
-    mm_log((2, "i_ft2_new, encoding %lX platform %u encoding %u\n",
-            enc_entry, face->charmaps[i]->platform_id,
-            face->charmaps[i]->encoding_id));
-    for (j = 0; j < sizeof(enc_scores) / sizeof(*enc_scores); ++j) {
-      if (enc_scores[j].encoding == enc_entry && enc_scores[j].score > score) {
-        encoding = enc_entry;
-        score = enc_scores[j].score;
-        break;
-      }
-    }
-  }
-  FT_Select_Charmap(face, encoding);
-  mm_log((2, "i_ft2_new, selected encoding %lX\n", encoding));
-
-  result = mymalloc(sizeof(FT2_Fonthandle));
-  result->face = face;
-  result->xdpi = result->ydpi = 72;
-  result->encoding = encoding;
-
-  /* by default we disable hinting on a call to i_ft2_settransform()
-     if we don't do this, then the hinting can the untransformed text
-     to be a different size to the transformed text.
-     Obviously we have it initially enabled.
-  */
-  result->hint = 1; 
-
-  /* I originally forgot this:   :/ */
-  /*i_ft2_settransform(result, matrix); */
-  result->matrix[0] = 1; result->matrix[1] = 0; result->matrix[2] = 0;
-  result->matrix[3] = 0; result->matrix[4] = 1; result->matrix[5] = 0;
-
-#ifdef IM_FT2_MM
- {
-   FT_Multi_Master *mm = &result->mm;
-   int i;
-
-   if ((face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS) != 0 
-       && (error = FT_Get_Multi_Master(face, mm)) == 0) {
-     mm_log((2, "MM Font, %d axes, %d designs\n", mm->num_axis, mm->num_designs));
-     for (i = 0; i < mm->num_axis; ++i) {
-       mm_log((2, "  axis %d name %s range %ld - %ld\n", i, mm->axis[i].name,
-               (long)(mm->axis[i].minimum), (long)(mm->axis[i].maximum)));
-     }
-     result->has_mm = 1;
-   }
-   else {
-     mm_log((2, "No multiple masters\n"));
-     result->has_mm = 0;
-   }
- }
-#endif
-
-  return result;
-}
-
-/*
-=item i_ft2_destroy(FT2_Fonthandle *handle)
-
-Destroys a font object, which must have been the return value of
-i_ft2_new().
-
-=cut
-*/
-void
-i_ft2_destroy(FT2_Fonthandle *handle) {
-  FT_Done_Face(handle->face);
-  myfree(handle);
-}
-
-/*
-=item i_ft2_setdpi(FT2_Fonthandle *handle, int xdpi, int ydpi)
-
-Sets the resolution in dots per inch at which point sizes scaled, by
-default xdpi and ydpi are 72, so that 1 point maps to 1 pixel.
-
-Both xdpi and ydpi should be positive.
-
-Return true on success.
-
-=cut
-*/
-int
-i_ft2_setdpi(FT2_Fonthandle *handle, int xdpi, int ydpi) {
-  i_clear_error();
-  if (xdpi > 0 && ydpi > 0) {
-    handle->xdpi = xdpi;
-    handle->ydpi = ydpi;
-    return 0;
-  }
-  else {
-    i_push_error(0, "resolutions must be positive");
-    return 0;
-  }
-}
-
-/*
-=item i_ft2_getdpi(FT2_Fonthandle *handle, int *xdpi, int *ydpi)
-
-Retrieves the current horizontal and vertical resolutions at which
-point sizes are scaled.
-
-=cut
-*/
-int
-i_ft2_getdpi(FT2_Fonthandle *handle, int *xdpi, int *ydpi) {
-  *xdpi = handle->xdpi;
-  *ydpi = handle->ydpi;
-
-  return 1;
-}
-
-/*
-=item i_ft2_settransform(FT2_FontHandle *handle, double *matrix)
-
-Sets a transormation matrix for output.
-
-This should be a 2 x 3 matrix like:
-
- matrix[0]   matrix[1]   matrix[2]
- matrix[3]   matrix[4]   matrix[5]
-
-=cut
-*/
-int
-i_ft2_settransform(FT2_Fonthandle *handle, const double *matrix) {
-  FT_Matrix m;
-  FT_Vector v;
-  int i;
-
-  m.xx = matrix[0] * 65536;
-  m.xy = matrix[1] * 65536;
-  v.x  = matrix[2]; /* this could be pels of 26.6 fixed - not sure */
-  m.yx = matrix[3] * 65536;
-  m.yy = matrix[4] * 65536;
-  v.y  = matrix[5]; /* see just above */
-
-  FT_Set_Transform(handle->face, &m, &v);
-
-  for (i = 0; i < 6; ++i)
-    handle->matrix[i] = matrix[i];
-  handle->hint = 0;
-
-  return 1;
-}
-
-/*
-=item i_ft2_sethinting(FT2_Fonthandle *handle, int hinting)
-
-If hinting is non-zero then glyph hinting is enabled, otherwise disabled.
-
-i_ft2_settransform() disables hinting to prevent distortions in
-gradual text transformations.
-
-=cut
-*/
-int i_ft2_sethinting(FT2_Fonthandle *handle, int hinting) {
-  handle->hint = hinting;
-  return 1;
-}
-
-/*
-=item i_ft2_bbox(FT2_Fonthandle *handle, double cheight, double cwidth, char *text, size_t len, int *bbox)
-
-Retrieves bounding box information for the font at the given 
-character width and height.  This ignores the transformation matrix.
-
-Returns non-zero on success.
-
-=cut
-*/
-int
-i_ft2_bbox(FT2_Fonthandle *handle, double cheight, double cwidth, 
-           char const *text, size_t len, int *bbox, int utf8) {
-  FT_Error error;
-  int width;
-  int index;
-  int first;
-  int ascent = 0, descent = 0;
-  int glyph_ascent, glyph_descent;
-  FT_Glyph_Metrics *gm;
-  int start = 0;
-  int loadFlags = FT_LOAD_DEFAULT;
-  int rightb = 0;
-
-  mm_log((1, "i_ft2_bbox(handle %p, cheight %f, cwidth %f, text %p, len %d, bbox %p)\n",
-         handle, cheight, cwidth, text, len, bbox));
-
-  error = FT_Set_Char_Size(handle->face, cwidth*64, cheight*64, 
-                           handle->xdpi, handle->ydpi);
-  if (error) {
-    ft2_push_message(error);
-    i_push_error(0, "setting size");
-  }
-
-  if (!handle->hint)
-    loadFlags |= FT_LOAD_NO_HINTING;
-
-  first = 1;
-  width = 0;
-  while (len) {
-    unsigned long c;
-    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;
-    }
-
-    index = FT_Get_Char_Index(handle->face, c);
-    error = FT_Load_Glyph(handle->face, index, loadFlags);
-    if (error) {
-      ft2_push_message(error);
-      i_push_errorf(0, "loading glyph for character \\x%02x (glyph 0x%04X)", 
-                    c, index);
-      return 0;
-    }
-    gm = &handle->face->glyph->metrics;
-    glyph_ascent = gm->horiBearingY / 64;
-    glyph_descent = glyph_ascent - gm->height/64;
-    if (first) {
-      start = gm->horiBearingX / 64;
-      /* handles -ve values properly */
-      ascent = glyph_ascent;
-      descent = glyph_descent;
-      first = 0;
-    }
-
-    if (glyph_ascent > ascent)
-      ascent = glyph_ascent;
-    if (glyph_descent < descent)
-      descent = glyph_descent;
-
-    width += gm->horiAdvance / 64;
-
-    if (len == 0) {
-      /* last character 
-       handle the case where the right the of the character overlaps the 
-       right*/
-      rightb = (gm->horiAdvance - gm->horiBearingX - gm->width)/64;
-      /*if (rightb > 0)
-        rightb = 0;*/
-    }
-  }
-
-  bbox[BBOX_NEG_WIDTH] = start;
-  bbox[BBOX_GLOBAL_DESCENT] = handle->face->size->metrics.descender / 64;
-  bbox[BBOX_POS_WIDTH] = width;
-  if (rightb < 0)
-    bbox[BBOX_POS_WIDTH] -= rightb;
-  bbox[BBOX_GLOBAL_ASCENT] = handle->face->size->metrics.ascender / 64;
-  bbox[BBOX_DESCENT] = descent;
-  bbox[BBOX_ASCENT] = ascent;
-  bbox[BBOX_ADVANCE_WIDTH] = width;
-  bbox[BBOX_RIGHT_BEARING] = rightb;
-  mm_log((1, " bbox=> negw=%d glob_desc=%d pos_wid=%d glob_asc=%d desc=%d asc=%d adv_width=%d rightb=%d\n", bbox[0], bbox[1], bbox[2], bbox[3], bbox[4], bbox[5], bbox[6], bbox[7]));
-
-  return BBOX_RIGHT_BEARING + 1;
-}
-
-/*
-=item transform_box(FT2_FontHandle *handle, int bbox[4])
-
-bbox contains coorinates of a the top-left and bottom-right of a bounding 
-box relative to a point.
-
-This is then transformed and the values in bbox[4] are the top-left
-and bottom-right of the new bounding box.
-
-This is meant to provide the bounding box of a transformed character
-box.  The problem is that if the character was round and is rotated,
-the real bounding box isn't going to be much different from the
-original, but this function will return a _bigger_ bounding box.  I
-suppose I could work my way through the glyph outline, but that's
-too much hard work.
-
-=cut
-*/
-void ft2_transform_box(FT2_Fonthandle *handle, int bbox[4]) {
-  double work[8];
-  double *matrix = handle->matrix;
-  
-  work[0] = matrix[0] * bbox[0] + matrix[1] * bbox[1];
-  work[1] = matrix[3] * bbox[0] + matrix[4] * bbox[1];
-  work[2] = matrix[0] * bbox[2] + matrix[1] * bbox[1];
-  work[3] = matrix[3] * bbox[2] + matrix[4] * bbox[1];
-  work[4] = matrix[0] * bbox[0] + matrix[1] * bbox[3];
-  work[5] = matrix[3] * bbox[0] + matrix[4] * bbox[3];
-  work[6] = matrix[0] * bbox[2] + matrix[1] * bbox[3];
-  work[7] = matrix[3] * bbox[2] + matrix[4] * bbox[3];
-
-  bbox[0] = floor(i_min(i_min(work[0], work[2]),i_min(work[4], work[6])));
-  bbox[1] = floor(i_min(i_min(work[1], work[3]),i_min(work[5], work[7])));
-  bbox[2] = ceil(i_max(i_max(work[0], work[2]),i_max(work[4], work[6])));
-  bbox[3] = ceil(i_max(i_max(work[1], work[3]),i_max(work[5], work[7])));
-}
-
-/*
-=item expand_bounds(int bbox[4], int bbox2[4]) 
-
-Treating bbox[] and bbox2[] as 2 bounding boxes, produces a new
-bounding box in bbox[] that encloses both.
-
-=cut
-*/
-static void expand_bounds(int bbox[4], int bbox2[4]) {
-  bbox[0] = i_min(bbox[0], bbox2[0]);
-  bbox[1] = i_min(bbox[1], bbox2[1]);
-  bbox[2] = i_max(bbox[2], bbox2[2]);
-  bbox[3] = i_max(bbox[3], bbox2[3]);
-}
-
-/*
-=item i_ft2_bbox_r(FT2_Fonthandle *handle, double cheight, double cwidth, char *text, size_t len, int vlayout, int utf8, int *bbox)
-
-Retrieves bounding box information for the font at the given 
-character width and height.
-
-This version finds the rectangular bounding box of the glyphs, with
-the text as transformed by the transformation matrix.  As with
-i_ft2_bbox (bbox[0], bbox[1]) will the the offset from the start of
-the topline to the top-left of the bounding box.  Unlike i_ft2_bbox()
-this could be near the bottom left corner of the box.
-
-(bbox[4], bbox[5]) is the offset to the start of the baseline.
-(bbox[6], bbox[7]) is the offset from the start of the baseline to the
-end of the baseline.
-
-Returns non-zero on success.
-
-=cut
-*/
-int
-i_ft2_bbox_r(FT2_Fonthandle *handle, double cheight, double cwidth, 
-           char const *text, size_t len, int vlayout, int utf8, int *bbox) {
-  FT_Error error;
-  int width;
-  int index;
-  int first;
-  int ascent = 0, descent = 0;
-  int glyph_ascent, glyph_descent;
-  FT_Glyph_Metrics *gm;
-  int work[4];
-  int bounds[4];
-  double x = 0, y = 0;
-  int i;
-  FT_GlyphSlot slot;
-  int loadFlags = FT_LOAD_DEFAULT;
-
-  if (vlayout)
-    loadFlags |= FT_LOAD_VERTICAL_LAYOUT;
-  if (!handle->hint)
-    loadFlags |= FT_LOAD_NO_HINTING;
-
-  error = FT_Set_Char_Size(handle->face, cwidth*64, cheight*64, 
-                           handle->xdpi, handle->ydpi);
-  if (error) {
-    ft2_push_message(error);
-    i_push_error(0, "setting size");
-  }
-
-  first = 1;
-  width = 0;
-  while (len) {
-    unsigned long c;
-    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;
-    }
-
-    index = FT_Get_Char_Index(handle->face, c);
-    error = FT_Load_Glyph(handle->face, index, loadFlags);
-    if (error) {
-      ft2_push_message(error);
-      i_push_errorf(0, "loading glyph for character \\x%02x (glyph 0x%04X)", 
-                    c, index);
-      return 0;
-    }
-    slot = handle->face->glyph; 
-    gm = &slot->metrics;
-
-    /* these probably don't mean much for vertical layouts */
-    glyph_ascent = gm->horiBearingY / 64;
-    glyph_descent = glyph_ascent - gm->height/64;
-    if (vlayout) {
-      work[0] = gm->vertBearingX;
-      work[1] = gm->vertBearingY;
-    }
-    else {
-      work[0] = gm->horiBearingX;
-      work[1] = gm->horiBearingY;
-    }
-    work[2] = gm->width  + work[0];
-    work[3] = work[1] - gm->height;
-    if (first) {
-      bbox[4] = work[0] * handle->matrix[0] + work[1] * handle->matrix[1] + handle->matrix[2];
-      bbox[5] = work[0] * handle->matrix[3] + work[1] * handle->matrix[4] + handle->matrix[5];
-      bbox[4] = bbox[4] < 0 ? -(-bbox[4] + 32)/64 : (bbox[4] + 32) / 64;
-      bbox[5] /= 64;
-    }
-    ft2_transform_box(handle, work);
-    for (i = 0; i < 4; ++i)
-      work[i] /= 64;
-    work[0] += x;
-    work[1] += y;
-    work[2] += x;
-    work[3] += y;
-    if (first) {
-      for (i = 0; i < 4; ++i)
-        bounds[i] = work[i];
-      ascent = glyph_ascent;
-      descent = glyph_descent;
-      first = 0;
-    }
-    else {
-      expand_bounds(bounds, work);
-    }
-    x += slot->advance.x / 64;
-    y += slot->advance.y / 64;
-
-    if (glyph_ascent > ascent)
-      ascent = glyph_ascent;
-    if (glyph_descent > descent)
-      descent = glyph_descent;
-
-    if (len == 0) {
-      /* last character 
-       handle the case where the right the of the character overlaps the 
-       right*/
-      /*int rightb = gm->horiAdvance - gm->horiBearingX - gm->width;
-      if (rightb < 0)
-      width -= rightb / 64;*/
-    }
-  }
-
-  /* at this point bounds contains the bounds relative to the CP,
-     and x, y hold the final position relative to the CP */
-  /*bounds[0] -= x;
-  bounds[1] -= y;
-  bounds[2] -= x;
-  bounds[3] -= y;*/
-
-  bbox[0] = bounds[0];
-  bbox[1] = -bounds[3];
-  bbox[2] = bounds[2];
-  bbox[3] = -bounds[1];
-  bbox[6] = x;
-  bbox[7] = -y;
-
-  return 1;
-}
-
-static int
-make_bmp_map(FT_Bitmap *bitmap, unsigned char *map);
-
-/*
-=item i_ft2_text(FT2_Fonthandle *handle, i_img *im, int tx, int ty, i_color *cl, double cheight, double cwidth, char *text, size_t len, int align, int aa)
-
-Renders I<text> to (I<tx>, I<ty>) in I<im> using color I<cl> at the given 
-I<cheight> and I<cwidth>.
-
-If align is 0, then the text is rendered with the top-left of the
-first character at (I<tx>, I<ty>).  If align is non-zero then the text
-is rendered with (I<tx>, I<ty>) aligned with the base-line of the
-characters.
-
-If aa is non-zero then the text is anti-aliased.
-
-Returns non-zero on success.
-
-=cut
-*/
-int
-i_ft2_text(FT2_Fonthandle *handle, i_img *im, int tx, int ty, const i_color *cl,
-           double cheight, double cwidth, char const *text, size_t len,
-          int align, int aa, int vlayout, int utf8) {
-  FT_Error error;
-  int index;
-  FT_Glyph_Metrics *gm;
-  int bbox[BOUNDING_BOX_COUNT];
-  FT_GlyphSlot slot;
-  int x, y;
-  unsigned char *bmp;
-  unsigned char map[256];
-  char last_mode = ft_pixel_mode_none; 
-  int last_grays = -1;
-  int loadFlags = FT_LOAD_DEFAULT;
-  i_render render;
-
-  mm_log((1, "i_ft2_text(handle %p, im %p, tx %d, ty %d, cl %p, cheight %f, cwidth %f, text %p, len %d, align %d, aa %d)\n",
-         handle, im, tx, ty, cl, cheight, cwidth, text, align, aa));
-
-  if (vlayout) {
-    if (!FT_HAS_VERTICAL(handle->face)) {
-      i_push_error(0, "face has no vertical metrics");
-      return 0;
-    }
-    loadFlags |= FT_LOAD_VERTICAL_LAYOUT;
-  }
-  if (!handle->hint)
-    loadFlags |= FT_LOAD_NO_HINTING;
-
-  /* set the base-line based on the string ascent */
-  if (!i_ft2_bbox(handle, cheight, cwidth, text, len, bbox, utf8))
-    return 0;
-
-  if (aa)
-    i_render_init(&render, im, bbox[BBOX_POS_WIDTH] - bbox[BBOX_NEG_WIDTH]);
-
-  if (!align) {
-    /* this may need adjustment */
-    tx -= bbox[0] * handle->matrix[0] + bbox[5] * handle->matrix[1] + handle->matrix[2];
-    ty += bbox[0] * handle->matrix[3] + bbox[5] * handle->matrix[4] + handle->matrix[5];
-  }
-  while (len) {
-    unsigned long c;
-    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;
-    }
-    
-    index = FT_Get_Char_Index(handle->face, c);
-    error = FT_Load_Glyph(handle->face, index, loadFlags);
-    if (error) {
-      ft2_push_message(error);
-      i_push_errorf(0, "loading glyph for character \\x%02x (glyph 0x%04X)", 
-                    c, index);
-      if (aa)
-        i_render_done(&render);
-      return 0;
-    }
-    slot = handle->face->glyph;
-    gm = &slot->metrics;
-
-    if (gm->width) {
-      error = FT_Render_Glyph(slot, aa ? ft_render_mode_normal : ft_render_mode_mono);
-      if (error) {
-       ft2_push_message(error);
-       i_push_errorf(0, "rendering glyph 0x%04X (character \\x%02X)");
-      if (aa)
-        i_render_done(&render);
-       return 0;
-      }
-      if (slot->bitmap.pixel_mode == ft_pixel_mode_mono) {
-       bmp = slot->bitmap.buffer;
-       for (y = 0; y < slot->bitmap.rows; ++y) {
-         int pos = 0;
-         int bit = 0x80;
-         for (x = 0; x < slot->bitmap.width; ++x) {
-           if (bmp[pos] & bit)
-             i_ppix(im, tx+x+slot->bitmap_left, ty+y-slot->bitmap_top, cl);
-           
-           bit >>= 1;
-           if (bit == 0) {
-             bit = 0x80;
-             ++pos;
-           }
-         }
-         bmp += slot->bitmap.pitch;
-       }
-      }
-      else {
-       /* grey scale or something we can treat as greyscale */
-       /* we create a map to convert from the bitmap values to 0-255 */
-       if (last_mode != slot->bitmap.pixel_mode 
-           || last_grays != slot->bitmap.num_grays) {
-         if (!make_bmp_map(&slot->bitmap, map))
-           return 0;
-         last_mode = slot->bitmap.pixel_mode;
-         last_grays = slot->bitmap.num_grays;
-       }
-
-       bmp = slot->bitmap.buffer;
-       for (y = 0; y < slot->bitmap.rows; ++y) {
-          if (last_mode == ft_pixel_mode_grays &&
-              last_grays != 255) {
-            for (x = 0; x < slot->bitmap.width; ++x) 
-              bmp[x] = map[bmp[x]];
-          }
-          i_render_color(&render, tx + slot->bitmap_left, ty-slot->bitmap_top+y,
-                         slot->bitmap.width, bmp, cl);
-         bmp += slot->bitmap.pitch;
-       }
-      }
-    }
-
-    tx += slot->advance.x / 64;
-    ty -= slot->advance.y / 64;
-  }
-
-  if (aa)
-    i_render_done(&render);
-
-  return 1;
-}
-
-/*
-=item i_ft2_cp(FT2_Fonthandle *handle, i_img *im, int tx, int ty, int channel, double cheight, double cwidth, char *text, size_t len, int align, int aa)
-
-Renders I<text> to (I<tx>, I<ty>) in I<im> to I<channel> at the given 
-I<cheight> and I<cwidth>.
-
-If align is 0, then the text is rendered with the top-left of the
-first character at (I<tx>, I<ty>).  If align is non-zero then the text
-is rendered with (I<tx>, I<ty>) aligned with the base-line of the
-characters.
-
-If aa is non-zero then the text is anti-aliased.
-
-Returns non-zero on success.
-
-=cut
-*/
-
-int
-i_ft2_cp(FT2_Fonthandle *handle, i_img *im, int tx, int ty, int channel,
-         double cheight, double cwidth, char const *text, size_t len, int align,
-         int aa, int vlayout, int utf8) {
-  int bbox[8];
-  i_img *work;
-  i_color cl, cl2;
-  int x, y;
-
-  mm_log((1, "i_ft2_cp(handle %p, im %p, tx %d, ty %d, channel %d, cheight %f, cwidth %f, text %p, len %d, ...)\n", 
-         handle, im, tx, ty, channel, cheight, cwidth, text, len));
-
-  if (vlayout && !FT_HAS_VERTICAL(handle->face)) {
-    i_push_error(0, "face has no vertical metrics");
-    return 0;
-  }
-
-  if (!i_ft2_bbox_r(handle, cheight, cwidth, text, len, vlayout, utf8, bbox))
-    return 0;
-
-  work = i_img_empty_ch(NULL, bbox[2]-bbox[0]+1, bbox[3]-bbox[1]+1, 1);
-  cl.channel[0] = 255;
-  if (!i_ft2_text(handle, work, -bbox[0], -bbox[1], &cl, cheight, cwidth, 
-                  text, len, 1, aa, vlayout, utf8))
-    return 0;
-
-  if (!align) {
-    tx -= bbox[4];
-    ty += bbox[5];
-  }
-  
-  /* render to the specified channel */
-  /* this will be sped up ... */
-  for (y = 0; y < work->ysize; ++y) {
-    for (x = 0; x < work->xsize; ++x) {
-      i_gpix(work, x, y, &cl);
-      i_gpix(im, tx + x + bbox[0], ty + y + bbox[1], &cl2);
-      cl2.channel[channel] = cl.channel[0];
-      i_ppix(im, tx + x + bbox[0], ty + y + bbox[1], &cl2);
-    }
-  }
-  i_img_destroy(work);
-  return 1;
-}
-
-/*
-=item i_ft2_has_chars(handle, char *text, size_t len, int utf8, char *out)
-
-Check if the given characters are defined by the font.
-
-Returns the number of characters that were checked.
-
-=cut
-*/
-int i_ft2_has_chars(FT2_Fonthandle *handle, char const *text, size_t len, 
-                    int utf8, char *out) {
-  int count = 0;
-  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;
-    }
-    
-    index = FT_Get_Char_Index(handle->face, c);
-    *out++ = index != 0;
-    ++count;
-  }
-
-  return count;
-}
-
-/* uses a method described in fterrors.h to build an error translation
-   function
-*/
-#undef __FTERRORS_H__
-#define FT_ERRORDEF(e, v, s) case v: i_push_error(code, s); return;
-#define FT_ERROR_START_LIST 
-#define FT_ERROR_END_LIST 
-
-/*
-=back
-
-=head2 Internal Functions
-
-These functions are used in the implementation of freetyp2.c and should not
-(usually cannot) be called from outside it.
-
-=over
-
-=item ft2_push_message(int code)
-
-Pushes an error message corresponding to code onto the error stack.
-
-=cut
-*/
-static void ft2_push_message(int code) {
-  char unknown[40];
-
-  switch (code) {
-#include FT_ERRORS_H
-  }
-
-  sprintf(unknown, "Unknown Freetype2 error code 0x%04X\n", code);
-  i_push_error(code, unknown);
-}
-
-/*
-=item make_bmp_map(FT_Bitmap *bitmap, unsigned char *map)
-
-Creates a map to convert grey levels from the glyphs bitmap into
-values scaled 0..255.
-
-=cut
-*/
-static int
-make_bmp_map(FT_Bitmap *bitmap, unsigned char *map) {
-  int scale;
-  int i;
-
-  switch (bitmap->pixel_mode) {
-  case ft_pixel_mode_grays:
-    scale = bitmap->num_grays;
-    break;
-    
-  default:
-    i_push_errorf(0, "I can't handle pixel mode %d", bitmap->pixel_mode);
-    return 0;
-  }
-
-  /* build the table */
-  for (i = 0; i < scale; ++i)
-    map[i] = i * 255 / (bitmap->num_grays - 1);
-
-  return 1;
-}
-
-/* FREETYPE_PATCH was introduced in 2.0.6, we don't want a false 
-   positive on 2.0.0 to 2.0.4, so we accept a false negative in 2.0.5 */
-#ifndef FREETYPE_PATCH
-#define FREETYPE_PATCH 4
-#endif
-
-/* FT_Get_Postscript_Name() was introduced in FT2.0.5 */
-#define IM_HAS_FACE_NAME (FREETYPE_MINOR > 0 || FREETYPE_PATCH >= 5)
-/* #define IM_HAS_FACE_NAME 0 */ 
-
-/*
-=item i_ft2_face_name(handle, name_buf, name_buf_size)
-
-Fills the given buffer with the Postscript Face name of the font,
-if there is one.
-
-=cut
-*/
-
-int
-i_ft2_face_name(FT2_Fonthandle *handle, char *name_buf, size_t name_buf_size) {
-#if IM_HAS_FACE_NAME
-  char const *name = FT_Get_Postscript_Name(handle->face);
-
-  i_clear_error();
-
-  if (name) {
-    strncpy(name_buf, name, name_buf_size);
-    name_buf[name_buf_size-1] = '\0';
-
-    return strlen(name) + 1;
-  }
-  else {
-    i_push_error(0, "no face name available");
-    *name_buf = '\0';
-
-    return 0;
-  }
-#else
-  i_clear_error();
-  i_push_error(0, "Freetype 2.0.6 or later required");
-  *name_buf = '\0';
-
-  return 0;
-#endif
-}
-
-int
-i_ft2_can_face_name(void) {
-  return IM_HAS_FACE_NAME;
-}
-
-/* FT_Has_PS_Glyph_Names() was introduced in FT2.1.1 */
-/* well, I assume FREETYPE_MAJOR is 2, since we're here */
-#if FREETYPE_MINOR < 1 || (FREETYPE_MINOR == 1 && FREETYPE_PATCH < 1)
-#define FT_Has_PS_Glyph_Names(face) (FT_HAS_GLYPH_NAMES(face))
-#endif
-
-int
-i_ft2_glyph_name(FT2_Fonthandle *handle, unsigned long ch, char *name_buf, 
-                 size_t name_buf_size, int reliable_only) {
-#ifdef FT_CONFIG_OPTION_NO_GLYPH_NAMES
-  i_clear_error();
-  *name_buf = '\0';
-  i_push_error(0, "FT2 configured without glyph name support");
-
-  return 0;
-#else
-  FT_UInt index;
-
-  i_clear_error();
-
-  if (!FT_HAS_GLYPH_NAMES(handle->face)) {
-    i_push_error(0, "no glyph names in font");
-    *name_buf = '\0';
-    return 0;
-  }
-  if (reliable_only && !FT_Has_PS_Glyph_Names(handle->face)) {
-    i_push_error(0, "no reliable glyph names in font - set reliable_only to 0 to try anyway");
-    *name_buf = '\0';
-    return 0;
-  }
-
-  index = FT_Get_Char_Index(handle->face, ch);
-  
-  if (index) {
-    FT_Error error = FT_Get_Glyph_Name(handle->face, index, name_buf, 
-                                       name_buf_size);
-    if (error) {
-      ft2_push_message(error);
-      *name_buf = '\0';
-      return 0;
-    }
-    if (*name_buf) {
-      return strlen(name_buf) + 1;
-    }
-    else {
-      return 0;
-    }
-  }
-  else {
-    i_push_error(0, "no glyph for that character");
-    *name_buf = 0;
-    return 0;
-  }
-#endif
-}
-
-int
-i_ft2_can_do_glyph_names(void) {
-#ifdef FT_CONFIG_OPTION_NO_GLYPH_NAMES
-  return 0;
-#else
-  return 1;
-#endif
-}
-
-int 
-i_ft2_face_has_glyph_names(FT2_Fonthandle *handle) {
-#ifdef FT_CONFIG_OPTION_NO_GLYPH_NAMES
-  return 0;
-#else
-  return FT_Has_PS_Glyph_Names(handle->face);
-#endif
-}
-
-int
-i_ft2_is_multiple_master(FT2_Fonthandle *handle) {
-  i_clear_error();
-#ifdef IM_FT2_MM
-  return handle->has_mm;
-#else
-  return 0;
-#endif
-}
-
-int
-i_ft2_get_multiple_masters(FT2_Fonthandle *handle, i_font_mm *mm) {
-#ifdef IM_FT2_MM
-  int i;
-  FT_Multi_Master *mms = &handle->mm;
-
-  i_clear_error();
-  if (!handle->has_mm) {
-    i_push_error(0, "Font has no multiple masters");
-    return 0;
-  }
-  mm->num_axis = mms->num_axis;
-  mm->num_designs = mms->num_designs;
-  for (i = 0; i < mms->num_axis; ++i) {
-    mm->axis[i].name = mms->axis[i].name;
-    mm->axis[i].minimum = mms->axis[i].minimum;
-    mm->axis[i].maximum = mms->axis[i].maximum;
-  }
-
-  return 1;
-#else
-  i_clear_error();
-  i_push_error(0, "Multiple master functions unavailable");
-  return 0;
-#endif
-}
-
-int
-i_ft2_set_mm_coords(FT2_Fonthandle *handle, int coord_count, const long *coords) {
-#ifdef IM_FT2_MM
-  int i;
-  FT_Long ftcoords[T1_MAX_MM_AXIS];
-  FT_Error error;
-
-  i_clear_error();
-  if (!handle->has_mm) {
-    i_push_error(0, "Font has no multiple masters");
-    return 0;
-  }
-  if (coord_count != handle->mm.num_axis) {
-    i_push_error(0, "Number of MM coords doesn't match MM axis count");
-    return 0;
-  }
-  for (i = 0; i < coord_count; ++i)
-    ftcoords[i] = coords[i];
-
-  error = FT_Set_MM_Design_Coordinates(handle->face, coord_count, ftcoords);
-  if (error) {
-    ft2_push_message(error);
-    return 0;
-  }
-  
-  return 1;
-#else 
-  i_clear_error();
-  i_push_error(0, "Multiple master functions unavailable");
-
-  return 0;
-#endif
-}
-
-/*
-=back
-
-=head1 AUTHOR
-
-Tony Cook <tony@develop-help.com>, with a fair amount of help from
-reading the code in font.c.
-
-=head1 SEE ALSO
-
-font.c, Imager::Font(3), Imager(3)
-
-http://www.freetype.org/
-
-=cut
-*/
-
index a58c802..89adcf4 100644 (file)
--- a/imager.h
+++ b/imager.h
@@ -257,46 +257,6 @@ int i_tt_glyph_name(TT_Fonthandle *handle, unsigned long ch, char *name_buf,
 
 #endif  /* End of freetype headers */
 
-#ifdef HAVE_FT2
-
-extern int i_ft2_init(void);
-extern FT2_Fonthandle * i_ft2_new(const char *name, int index);
-extern void i_ft2_destroy(FT2_Fonthandle *handle);
-extern int i_ft2_setdpi(FT2_Fonthandle *handle, int xdpi, int ydpi);
-extern int i_ft2_getdpi(FT2_Fonthandle *handle, int *xdpi, int *ydpi);
-extern int i_ft2_settransform(FT2_Fonthandle *handle, const double *matrix);
-extern int i_ft2_sethinting(FT2_Fonthandle *handle, int hinting);
-extern int i_ft2_bbox(FT2_Fonthandle *handle, double cheight, double cwidth, 
-                      char const *text, size_t len, int *bbox, int utf8);
-extern int i_ft2_bbox_r(FT2_Fonthandle *handle, double cheight, double cwidth, 
-                     char const *text, size_t len, int vlayout, int utf8, int *bbox);
-extern int i_ft2_text(FT2_Fonthandle *handle, i_img *im, int tx, int ty, 
-                      const i_color *cl, double cheight, double cwidth, 
-                      char const *text, size_t len, int align, int aa, 
-                      int vlayout, int utf8);
-extern int i_ft2_cp(FT2_Fonthandle *handle, i_img *im, int tx, int ty, 
-                    int channel, double cheight, double cwidth, 
-                    char const *text, size_t len, int align, int aa, 
-                   int vlayout, int utf8);
-extern int i_ft2_has_chars(FT2_Fonthandle *handle, char const *text, size_t len,
-                           int utf8, char *work);
-extern int i_ft2_face_name(FT2_Fonthandle *handle, char *name_buf, 
-                           size_t name_buf_size);
-extern int i_ft2_can_face_name(void);
-extern int i_ft2_glyph_name(FT2_Fonthandle *handle, unsigned long ch, 
-                            char *name_buf, size_t name_buf_size,
-                            int reliable_only);
-extern int i_ft2_can_do_glyph_names(void);
-extern int i_ft2_face_has_glyph_names(FT2_Fonthandle *handle);
-
-extern int i_ft2_get_multiple_masters(FT2_Fonthandle *handle,
-                                      i_font_mm *mm);
-extern int
-i_ft2_is_multiple_master(FT2_Fonthandle *handle);
-extern int
-i_ft2_set_mm_coords(FT2_Fonthandle *handle, int coord_count, const long *coords);
-#endif
-
 /* functions for reading and writing formats */
 
 /* general reader callback 
index e01df46..36d6ed9 100644 (file)
--- a/imageri.h
+++ b/imageri.h
@@ -108,4 +108,10 @@ extern void im_assert_fail(char const *, int, char const *);
 #define im_assert(x) (void)(0)
 #endif 
 
+i_img_dim i_minx(i_img_dim a, i_img_dim b);
+i_img_dim i_maxx(i_img_dim x, i_img_dim y);
+
+#define i_min(a, b) i_minx((a), (b))
+#define i_max(a, b) i_maxx((a), (b))
+
 #endif
index 7b6e659..7866d7b 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef _DATATYPES_H_
 #define _DATATYPES_H_
 
+#include <stddef.h>
 #include "imconfig.h"
 #include "imio.h"
 
@@ -173,6 +174,7 @@ May be larger than int on some platforms.
 
 =cut
 */
+
 typedef int i_img_dim;
 
 /*
@@ -413,10 +415,10 @@ enum bounding_box_index_t {
 struct i_fill_tag;
 
 typedef void (*i_fill_with_color_f)
-     (struct i_fill_tag *fill, int x, int y, int width, int channels, 
+(struct i_fill_tag *fill, i_img_dim x, i_img_dim y, i_img_dim width, int channels, 
       i_color *data);
 typedef void (*i_fill_with_fcolor_f)
-     (struct i_fill_tag *fill, int x, int y, int width, int channels,
+     (struct i_fill_tag *fill, i_img_dim x, i_img_dim y, i_img_dim width, int channels,
       i_fcolor *data);
 typedef void (*i_fill_destroy_f)(struct i_fill_tag *fill);
 
@@ -430,9 +432,9 @@ typedef void (*i_fill_destroy_f)(struct i_fill_tag *fill);
 */
 
 typedef void (*i_fill_combine_f)(i_color *out, i_color *in, int channels, 
-                                 int count);
+                                 i_img_dim count);
 typedef void (*i_fill_combinef_f)(i_fcolor *out, i_fcolor *in, int channels,
-                                  int count);
+                                  i_img_dim count);
 
 /* fountain fill types */
 typedef enum {
@@ -558,12 +560,6 @@ typedef struct TT_Fonthandle_ TT_Fonthandle;
 
 #endif
 
-#ifdef HAVE_FT2
-
-typedef struct FT2_Fonthandle FT2_Fonthandle;
-
-#endif
-
 /* transparency handling for quantized output */
 typedef enum i_transp_tag {
   tr_none, /* ignore any alpha channel */
@@ -713,7 +709,7 @@ enum {
 
 #include "iolayert.h"
 
-#include "rendert.h"
+typedef struct i_render_tag i_render;
 
 #endif
 
diff --git a/imext.c b/imext.c
index 8a67b48..ed5c416 100644 (file)
--- a/imext.c
+++ b/imext.c
@@ -1,5 +1,6 @@
 #include "imexttypes.h"
 #include "imager.h"
+#include "imio.h"
 
 /*
  DON'T ADD CASTS TO THESE
@@ -124,7 +125,13 @@ im_ext_funcs imager_function_table =
     i_gsampf_bg,
     i_get_file_background,
     i_get_file_backgroundf,
-    i_utf8_advance
+    i_utf8_advance,
+    i_render_new,
+    i_render_delete,
+    i_render_color,
+    i_render_fill,
+    i_render_line,
+    i_render_linef
   };
 
 /* in general these functions aren't called by Imager internally, but
diff --git a/imext.h b/imext.h
index c9d6f46..9c55b4b 100644 (file)
--- a/imext.h
+++ b/imext.h
@@ -221,4 +221,15 @@ extern im_ext_funcs *imager_function_ext_table;
 
 #define i_utf8_advance(p, s) ((im_extt->f_i_utf8_advance)((p), (s)))
 
+#define i_render_new(im, width) ((im_extt->f_i_render_new)((im), (width)))
+#define i_render_delete(r) ((im_extt->f_i_render_delete)(r))
+#define i_render_color(r, x, y, width, src, color) \
+  ((im_extt->f_i_render_color)((r), (x), (y), (width), (src), (color)))
+#define i_render_fill(r, x, y, width, src, fill) \
+  ((im_extt->f_i_render_fill)((r), (x), (y), (width), (src), (fill)))
+#define i_render_line(r, x, y, width, src, line, combine) \
+  ((im_extt->f_i_render_line)((r), (x), (y), (width), (src), (line), (combine)))
+#define i_render_linef(r, x, y, width, src, line, combine) \
+  ((im_extt->f_i_render_linef)((r), (x), (y), (width), (src), (line), (combine)))
+
 #endif
index a0d0172..f1561d4 100644 (file)
@@ -165,6 +165,20 @@ typedef struct {
   void (*f_i_get_file_background)(i_img *im, i_color *bg);
   void (*f_i_get_file_backgroundf)(i_img *im, i_fcolor *bg);
   unsigned long (*f_i_utf8_advance)(char const **p, size_t *len);
+  i_render *(*f_i_render_new)(i_img *im, i_img_dim width);
+  void (*f_i_render_delete)(i_render *r);
+  void (*f_i_render_color)(i_render *r, i_img_dim x, i_img_dim y,
+                          i_img_dim width, unsigned char const *src,
+                          i_color const *color);
+  void (*f_i_render_fill)(i_render *r, i_img_dim x, i_img_dim y,
+                         i_img_dim width, unsigned char const *src,
+                         i_fill_t *fill);
+  void (*f_i_render_line)(i_render *r, i_img_dim x, i_img_dim y,
+                         i_img_dim width, const i_sample_t *src,
+                         i_color *line, i_fill_combine_f combine);
+  void (*f_i_render_linef)(i_render *r, i_img_dim x, i_img_dim y,
+                         i_img_dim width, const double *src,
+                         i_fcolor *line, i_fill_combinef_f combine);
 
   /* IMAGER_API_LEVEL 6 functions will be added here */
 } im_ext_funcs;
diff --git a/imio.h b/imio.h
index 557097b..6d5cea4 100644 (file)
--- a/imio.h
+++ b/imio.h
@@ -17,8 +17,6 @@ void  i_mempool_extend(i_mempool *mp);
 void *i_mempool_alloc(i_mempool *mp, size_t size);
 void  i_mempool_destroy(i_mempool *mp);
 
-
-
 #ifdef _MSC_VER
 #undef min
 #undef max
@@ -26,9 +24,4 @@ void  i_mempool_destroy(i_mempool *mp);
 
 extern unsigned long i_utf8_advance(char const **p, size_t *len);
 
-/* XXX Shouldn't these go away? */
-
-int i_min(int a,int b);
-int i_max(int x,int y);
-
 #endif
index fad1d66..9403347 100644 (file)
--- a/imperl.h
+++ b/imperl.h
@@ -19,10 +19,6 @@ typedef i_img * Imager;
 typedef TT_Fonthandle* Imager__Font__TT;
 #endif
 
-#ifdef HAVE_FT2
-typedef FT2_Fonthandle* Imager__Font__FT2;
-#endif
-
 /* for the fill objects
    Since a fill object may later have dependent images, (or fills!)
    we need perl wrappers - oh well
index 9ded022..69760ec 100644 (file)
@@ -4,20 +4,25 @@
 #include "rendert.h"
 
 extern void
-i_render_init(i_render *r, i_img *im, int width);
+i_render_init(i_render *r, i_img *im, i_img_dim width);
 extern void
 i_render_done(i_render *r);
 extern void
-i_render_color(i_render *r, int x, int y, int width, unsigned char const *src,
-               i_color const *color);
+i_render_color(i_render *r, i_img_dim x, i_img_dim y, i_img_dim width,
+              unsigned char const *src, i_color const *color);
 extern void
-i_render_fill(i_render *r, int x, int y, int width, unsigned char const *src,
-             i_fill_t *fill);
+i_render_fill(i_render *r, i_img_dim x, i_img_dim y, i_img_dim width,
+             unsigned char const *src, i_fill_t *fill);
 extern void
-i_render_line(i_render *r, int x, int y, int width, const i_sample_t *src,
-             i_color *line, i_fill_combine_f combine);
+i_render_line(i_render *r, i_img_dim x, i_img_dim y, i_img_dim width,
+             const i_sample_t *src, i_color *line, i_fill_combine_f combine);
 extern void
-i_render_linef(i_render *r, int x, int y, int width, const double *src,
-             i_fcolor *line, i_fill_combinef_f combine);
+i_render_linef(i_render *r, i_img_dim x, i_img_dim y, i_img_dim width,
+              const double *src, i_fcolor *line, i_fill_combinef_f combine);
+
+extern i_render *
+i_render_new(i_img *im, i_img_dim width);
+extern void
+i_render_delete(i_render *r);
 
 #endif
diff --git a/io.c b/io.c
index 4576bf9..df00421 100644 (file)
--- a/io.c
+++ b/io.c
@@ -1,4 +1,5 @@
 #include "imager.h"
+#include "imageri.h"
 #include <stdlib.h>
 #ifndef _MSC_VER
 #include <unistd.h>
@@ -320,13 +321,13 @@ i_mempool_destroy(i_mempool *mp) {
 #undef min
 #undef max
 
-int
-i_min(int a,int b) {
+i_img_dim
+i_minx(i_img_dim a, i_img_dim b) {
   if (a<b) return a; else return b;
 }
 
-int
-i_max(int a,int b) {
+i_img_dim
+i_maxx(i_img_dim a, i_img_dim b) {
   if (a>b) return a; else return b;
 }
 
@@ -345,16 +346,16 @@ struct utf8_size utf8_sizes[] =
 };
 
 /*
-=item utf8_advance(char **p, int *len)
+=item i_utf8_advance(char **p, size_t *len)
 
-Retreive a UTF8 character from the stream.
+Retrieve a C<UTF-8> character from the stream.
 
 Modifies *p and *len to indicate the consumed characters.
 
-This doesn't support the extended UTF8 encoding used by later versions
-of Perl.
+This doesn't support the extended C<UTF-8> encoding used by later
+versions of Perl.
 
-This doesn't check that the UTF8 charecter is using the shortest
+This doesn't check that the C<UTF-8> character is using the shortest
 possible representation.
 
 =cut
index 0072abb..5f49976 100644 (file)
--- a/iolayer.c
+++ b/iolayer.c
@@ -9,6 +9,7 @@
 #endif
 #include <string.h>
 #include <errno.h>
+#include "imageri.h"
 
 #define IOL_DEB(x)
 
index 4f2f571..c9e5b48 100644 (file)
@@ -14,6 +14,8 @@ Imager::APIRef - Imager's C API - reference.
   color.rgba.r = 255; color.rgba.g = 0; color.rgba.b = 255;
 
 
+  # Blit tools
+
   # Data Types
   i_img *img;
   i_color black;
@@ -90,6 +92,67 @@ Imager::APIRef - Imager's C API - reference.
 
 =head1 DESCRIPTION
 
+=head2 Blit tools
+
+=over
+
+=item i_render_color(r, x, y, width, source, color)
+
+Render the given color with the coverage specified by C<source[0]> to
+C<source[width-1]>.
+
+Renders in normal combine mode.
+
+
+=for comment
+From: File render.im
+
+=item i_render_delete(r)
+
+Release an C<i_render> object.
+
+
+=for comment
+From: File render.im
+
+=item i_render_fill(r, x, y, width, source, fill)
+
+Render the given fill with the coverage in C<source[0]> through
+C<source[width-1]>.
+
+
+=for comment
+From: File render.im
+
+=item i_render_line(r, x, y, width, source, fill)
+
+Render the given fill with the coverage in C<source[0]> through
+C<source[width-1]>.
+
+
+=for comment
+From: File render.im
+
+=item i_render_linef(r, x, y, width, source, fill)
+
+Render the given fill with the coverage in C<source[0]> through
+C<source[width-1]>.
+
+
+=for comment
+From: File render.im
+
+=item i_render_new(im, width)
+
+Allocate a new C<i_render> object and initialize it.
+
+
+=for comment
+From: File render.im
+
+
+=back
+
 =head2 Data Types
 
 =over
@@ -471,6 +534,19 @@ channel_count)
 =for comment
 From: File imext.c
 
+=item i_gsamp_bg(im, l, r, y, samples, out_channels, background)
+
+
+Like C<i_gsampf()> but applies the source image color over a supplied
+background color.
+
+This is intended for output to image formats that don't support alpha
+channels.
+
+
+=for comment
+From: File paste.im
+
 =item i_gsampf(im, left, right, y, samples, channels, channel_count)
 
 
@@ -1515,21 +1591,25 @@ From: File tags.c
 
 =back
 
+=head2 Uncategorized functions
 
-=head1 UNDOCUMENTED
+=over
 
-The following API functions are undocumented so far, hopefully this
-will change:
+=item i_utf8_advance(char **p, size_t *len)
 
-=over
+Retrieve a C<UTF-8> character from the stream.
 
-=item *
+Modifies *p and *len to indicate the consumed characters.
 
-B<i_gsamp_bg>
+This doesn't support the extended C<UTF-8> encoding used by later
+versions of Perl.
+
+This doesn't check that the C<UTF-8> character is using the shortest
+possible representation.
 
-=item *
 
-B<i_utf8_advance>
+=for comment
+From: File io.c
 
 
 
index 53b150f..92c121b 100644 (file)
@@ -26,8 +26,8 @@ my %drivers =
        description => 'T1Lib',
        },
    ft2=>{
-         class=>'Imager::Font::FreeType2',
-         module=>'Imager/Font/FreeType2.pm',
+         class=>'Imager::Font::FT2',
+         module=>'Imager/Font/FT2.pm',
          files=>'.*\.(pfa|pfb|otf|ttf|fon|fnt|dfont|pcf(\.gz)?)$',
         description => 'FreeType 2.x',
         },
@@ -46,21 +46,6 @@ my %drivers =
 # this currently should only contain file based types, don't add w32
 my @priority = qw(t1 tt ft2 ifs);
 
-# when Imager::Font is loaded, Imager.xs has not been bootstrapped yet
-# this function is called from Imager.pm to finish initialization
-sub __init {
-  @priority = grep Imager::i_has_format($_), @priority;
-  for my $driver_name (grep Imager::i_has_format($_), keys %drivers) {
-    $drivers{$driver_name}{enabled} = 1;
-  }
-}
-
-# search method
-# 1. start by checking if file is the parameter
-# 1a. if so qualify path and compare to the cache.
-# 2a. if in cache - take it's id from there and increment count.
-#
-
 sub new {
   my $class = shift;
   my $self = {};
@@ -75,7 +60,18 @@ sub new {
     $file = $hsh{'file'};
 
     $type = $hsh{'type'};
-    if (!defined($type) or !$drivers{$type} or !$drivers{$type}{enabled}) {
+    if (defined $type) {
+      unless ($drivers{$type}) {
+       Imager->_set_error("Unknown font type $type");
+       return;
+      }
+
+      unless ($Imager::formats{$type}) {
+       Imager->_set_error("The $type {$drivers{$type}) font driver is not installed");
+       return;
+      }
+    }
+    else {
       for my $drv (@priority) {
         undef $type;
         my $re = $drivers{$drv}{files} or next;
index beac637..279dfad 100644 (file)
 package Imager::Font::FreeType2;
 use strict;
-use Imager::Color;
+use Imager::Font::FT2;
 use vars qw(@ISA $VERSION);
-@ISA = qw(Imager::Font);
-
-$VERSION = "1.014";
-
-*_first = \&Imager::Font::_first;
-
-sub new {
-  my $class = shift;
-  my %hsh=(color=>Imager::Color->new(255,0,0,0),
-          size=>15,
-          @_);
-
-  unless ($hsh{file}) {
-    $Imager::ERRSTR = "No font file specified";
-    return;
-  }
-  unless (-e $hsh{file}) {
-    $Imager::ERRSTR = "Font file $hsh{file} not found";
-    return;
-  }
-  unless ($Imager::formats{ft2}) {
-    $Imager::ERRSTR = "Freetype2 not supported in this build";
-    return;
-  }
-  my $id = i_ft2_new($hsh{file}, $hsh{'index'} || 0);
-  unless ($id) { # the low-level code may miss some error handling
-    $Imager::ERRSTR = Imager::_error_as_msg();
-    return;
-  }
-  return bless {
-               id       => $id,
-               aa       => $hsh{aa} || 0,
-               file     => $hsh{file},
-               type     => 't1',
-               size     => $hsh{size},
-               color    => $hsh{color},
-                utf8     => $hsh{utf8},
-                vlayout  => $hsh{vlayout},
-              }, $class;
-}
-
-sub _draw {
-  my $self = shift;
-  my %input = @_;
-  if (exists $input{channel}) {
-    i_ft2_cp($self->{id}, $input{image}{IMG}, $input{'x'}, $input{'y'},
-             $input{channel}, $input{size}, $input{sizew} || 0,
-             $input{string}, , $input{align}, $input{aa}, $input{vlayout},
-             $input{utf8});
-  } else {
-    i_ft2_text($self->{id}, $input{image}{IMG},
-               $input{'x'}, $input{'y'},
-               $input{color}, $input{size}, $input{sizew} || 0,
-               $input{string}, $input{align}, $input{aa}, $input{vlayout},
-               $input{utf8});
-  }
-}
-
-sub _bounding_box {
-  my $self = shift;
-  my %input = @_;
-
-  return i_ft2_bbox($self->{id}, $input{size}, $input{sizew}, $input{string}, 
-                   $input{utf8});
-}
-
-sub dpi {
-  my $self = shift;
-  my @old = i_ft2_getdpi($self->{id});
-  if (@_) {
-    my %hsh = @_;
-    my $result;
-    unless ($hsh{xdpi} && $hsh{ydpi}) {
-      if ($hsh{dpi}) {
-        $hsh{xdpi} = $hsh{ydpi} = $hsh{dpi};
-      }
-      else {
-        $Imager::ERRSTR = "dpi method requires xdpi and ydpi or just dpi";
-        return;
-      }
-      i_ft2_setdpi($self->{id}, $hsh{xdpi}, $hsh{ydpi}) or return;
-    }
-  }
-  
-  return @old;
-}
-
-sub hinting {
-  my ($self, %opts) = @_;
-
-  i_ft2_sethinting($self->{id}, $opts{hinting} || 0);
-}
-
-sub _transform {
-  my $self = shift;
-
-  my %hsh = @_;
-  my $matrix = $hsh{matrix} or return undef;
-
-  return i_ft2_settransform($self->{id}, $matrix)
-}
-
-sub utf8 {
-  return 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 i_ft2_has_chars($self->{id}, $hsh{string}, 
-                        _first($hsh{'utf8'}, $self->{utf8}, 0));
-}
-
-sub face_name {
-  my ($self) = @_;
-
-  i_ft2_face_name($self->{id});
-}
-
-sub can_glyph_names {
-  i_ft2_can_do_glyph_names();
-}
-
-sub glyph_names {
-  my ($self, %input) = @_;
-
-  my $string = $input{string};
-  defined $string
-    or return Imager->_set_error("no string parameter passed to glyph_names");
-  my $utf8 = _first($input{utf8}, 0);
-  my $reliable_only = _first($input{reliable_only}, 1);
-
-  my @names = i_ft2_glyph_name($self->{id}, $string, $utf8, $reliable_only);
-  @names or return Imager->_set_error(Imager->_error_as_msg);
-
-  return @names if wantarray;
-  return pop @names;
-}
-
-sub is_mm {
-  my ($self) = @_;
-
-  i_ft2_is_multiple_master($self->{id});
-}
-
-sub mm_axes {
-  my ($self) = @_;
-
-  my ($num_axis, $num_design, @axes) =
-    i_ft2_get_multiple_masters($self->{id})
-      or return Imager->_set_error(Imager->_error_as_msg);
-
-  return @axes;
-}
-
-sub set_mm_coords {
-  my ($self, %opts) = @_;
-
-  $opts{coords}
-    or return Imager->_set_error("Missing coords parameter");
-  ref($opts{coords}) && $opts{coords} =~ /ARRAY\(0x[\da-f]+\)$/
-    or return Imager->_set_error("coords parameter must be an ARRAY ref");
-
-  i_ft2_set_mm_coords($self->{id}, @{$opts{coords}})
-    or return Imager->_set_error(Imager->_error_as_msg);
-
-  return 1;
-}
+@ISA = qw(Imager::Font::FT2);
+
+$VERSION = "1.020";
+
 
 1;
 
index 6c440ce..6bc58a7 100644 (file)
--- a/paste.im
+++ b/paste.im
@@ -339,6 +339,8 @@ background color.
 This is intended for output to image formats that don't support alpha
 channels.
 
+=cut
+
 =item i_gsampf_bg(im, l, r, y, samples, out_channels, background)
 
 =category Drawing
index 511cf7a..a426b58 100644 (file)
--- a/polygon.c
+++ b/polygon.c
@@ -2,6 +2,7 @@
 #include "draw.h"
 #include "log.h"
 #include "imrender.h"
+#include "imageri.h"
 
 #define IMTRUNC(x) ((int)((x)*16))
 
diff --git a/quant.c b/quant.c
index 13096cc..ca4e34e 100644 (file)
--- a/quant.c
+++ b/quant.c
@@ -3,6 +3,7 @@
    8-bit (or bigger indexed) png files at some point
 */
 #include "imager.h"
+#include "imageri.h"
 
 static void makemap_addi(i_quantize *, i_img **imgs, int count);
 static void makemap_mediancut(i_quantize *, i_img **imgs, int count);
index c7fe613..fa6578e 100644 (file)
--- a/regmach.c
+++ b/regmach.c
@@ -1,5 +1,6 @@
 #include "regmach.h"
 #include <float.h>
+#include "imageri.h"
 
 /*#define DEBUG*/
 #ifdef DEBUG
index 44fef99..0812914 100644 (file)
--- a/render.im
+++ b/render.im
@@ -5,7 +5,7 @@ Render utilities
 
 #define RENDER_MAGIC 0x765AE
 
-typedef void (*render_color_f)(i_render *, int, int, int, unsigned char const *src, i_color const *color);
+typedef void (*render_color_f)(i_render *, i_img_dim, i_img_dim, i_img_dim, unsigned char const *src, i_color const *color);
 
 #define i_has_alpha(channels) ((channels) == 2 || (channels) == 4)
 
@@ -13,8 +13,8 @@ typedef void (*render_color_f)(i_render *, int, int, int, unsigned char const *s
 
 #code
 
-static void IM_SUFFIX(render_color_alpha)(i_render *r, int x, int y, int width, unsigned char const *src, i_color const *color);
-static void IM_SUFFIX(render_color_13)(i_render *r, int x, int y, int width, unsigned char const *src, i_color const *color);
+static void IM_SUFFIX(render_color_alpha)(i_render *r, i_img_dim x, i_img_dim y, i_img_dim width, unsigned char const *src, i_color const *color);
+static void IM_SUFFIX(render_color_13)(i_render *r, i_img_dim x, i_img_dim y, i_img_dim width, unsigned char const *src, i_color const *color);
 
 static render_color_f IM_SUFFIX(render_color_tab)[] =
   {
@@ -25,18 +25,51 @@ static render_color_f IM_SUFFIX(render_color_tab)[] =
     IM_SUFFIX(render_color_alpha),
   };
 
-static void IM_SUFFIX(combine_line_noalpha)(IM_COLOR *out, IM_COLOR const *in, int channels, int count);
-static void IM_SUFFIX(combine_line_alpha)(IM_COLOR *out, IM_COLOR const *in, int channels, int count);
+static void IM_SUFFIX(combine_line_noalpha)(IM_COLOR *out, IM_COLOR const *in, int channels, i_img_dim count);
+static void IM_SUFFIX(combine_line_alpha)(IM_COLOR *out, IM_COLOR const *in, int channels, i_img_dim count);
 /* the copy variant copies the source alpha to the the output alpha channel */
-static void IM_SUFFIX(combine_line_alpha_na)(IM_COLOR *out, IM_COLOR const *in, int channels, int count);
+static void IM_SUFFIX(combine_line_alpha_na)(IM_COLOR *out, IM_COLOR const *in, int channels, i_img_dim count);
 
-static void IM_SUFFIX(combine_line)(IM_COLOR *out, IM_COLOR const *in, int channels, int count);
-static void IM_SUFFIX(combine_line_na)(IM_COLOR *out, IM_COLOR const *in, int channels, int count);
+static void IM_SUFFIX(combine_line)(IM_COLOR *out, IM_COLOR const *in, int channels, i_img_dim count);
+static void IM_SUFFIX(combine_line_na)(IM_COLOR *out, IM_COLOR const *in, int channels, i_img_dim count);
 
 #/code
 
+/* 
+=item i_render_new(im, width)
+=category Blit tools
+
+Allocate a new C<i_render> object and initialize it.
+
+=cut
+*/
+
+i_render *
+i_render_new(i_img *im, i_img_dim width) {
+  i_render *r = mymalloc(sizeof(i_render));
+
+  i_render_init(r, im, width);
+
+  return r;
+}
+
+/*
+=item i_render_delete(r)
+=category Blit tools
+
+Release an C<i_render> object.
+
+=cut
+*/
+
 void
-i_render_init(i_render *r, i_img *im, int width) {
+i_render_delete(i_render *r) {
+  i_render_done(r);
+  myfree(r);
+}
+
+void
+i_render_init(i_render *r, i_img *im, i_img_dim width) {
   r->magic = RENDER_MAGIC;
   r->im = im;
   r->line_width = width;
@@ -61,9 +94,9 @@ i_render_done(i_render *r) {
 }
 
 static void
-alloc_line(i_render *r, int width, int eight_bit) {
+alloc_line(i_render *r, i_img_dim width, i_img_dim eight_bit) {
   if (width > r->line_width) {
-    int new_width = r->line_width * 2;
+    i_img_dim new_width = r->line_width * 2;
     if (new_width < width)
       new_width = width;
 
@@ -111,9 +144,9 @@ alloc_line(i_render *r, int width, int eight_bit) {
 }
 
 static void
-alloc_fill_line(i_render *r, int width, int eight_bit) {
+alloc_fill_line(i_render *r, i_img_dim width, int eight_bit) {
   if (width > r->fill_width) {
-    int new_width = r->fill_width * 2;
+    i_img_dim new_width = r->fill_width * 2;
     if (new_width < width)
       new_width = width;
 
@@ -160,9 +193,21 @@ alloc_fill_line(i_render *r, int width, int eight_bit) {
   }
 }
 
+/*
+=item i_render_color(r, x, y, width, source, color)
+=category Blit tools
+
+Render the given color with the coverage specified by C<source[0]> to
+C<source[width-1]>.
+
+Renders in normal combine mode.
+
+=cut
+*/
+
 void
-i_render_color(i_render *r, int x, int y, int width, unsigned char const *src,
-               i_color const *color) {
+i_render_color(i_render *r, i_img_dim x, i_img_dim y, i_img_dim width,
+              unsigned char const *src, i_color const *color) {
   i_img *im = r->im;
   if (y < 0 || y >= im->ysize)
     return;
@@ -198,9 +243,19 @@ i_render_color(i_render *r, int x, int y, int width, unsigned char const *src,
 #/code
 }
 
+/*
+=item i_render_fill(r, x, y, width, source, fill)
+=category Blit tools
+
+Render the given fill with the coverage in C<source[0]> through
+C<source[width-1]>.
+
+=cut
+*/
+
 void
-i_render_fill(i_render *r, int x, int y, int width, unsigned char const *src,
-             i_fill_t *fill) {
+i_render_fill(i_render *r, i_img_dim x, i_img_dim y, i_img_dim width,
+             unsigned char const *src, i_fill_t *fill) {
   i_img *im = r->im;
   int fill_channels = im->channels;
   
@@ -245,7 +300,7 @@ i_render_fill(i_render *r, int x, int y, int width, unsigned char const *src,
     if (src) {
       unsigned char const *srcc = src;
       IM_COLOR *fillc = r->IM_SUFFIX(fill_line);
-      int work_width = width;
+      i_img_dim work_width = width;
       while (work_width) {
        if (*srcc == 0) {
          fillc->channel[fill_channels-1] = 0;
@@ -264,7 +319,7 @@ i_render_fill(i_render *r, int x, int y, int width, unsigned char const *src,
   }
   else {
     if (src) {
-      int work_width = width;
+      i_img_dim work_width = width;
       IM_COLOR *srcc = r->IM_SUFFIX(fill_line);
       IM_COLOR *destc = r->IM_SUFFIX(line);
       int ch;
@@ -299,8 +354,8 @@ i_render_fill(i_render *r, int x, int y, int width, unsigned char const *src,
 }
 
 static void
-dump_src(const char *note, unsigned char const *src, int width) {
-  int i;
+dump_src(const char *note, unsigned char const *src, i_img_dim width) {
+  i_img_dim i;
   printf("%s - %p/%d\n", note, src, width);
   for (i = 0; i < width; ++i) {
     printf("%02x ", src[i]);
@@ -310,9 +365,28 @@ dump_src(const char *note, unsigned char const *src, int width) {
 
 #code
 
+/*
+=item i_render_line(r, x, y, width, source, fill)
+=category Blit tools
+
+Render the given fill with the coverage in C<source[0]> through
+C<source[width-1]>.
+
+=cut
+
+=item i_render_linef(r, x, y, width, source, fill)
+=category Blit tools
+
+Render the given fill with the coverage in C<source[0]> through
+C<source[width-1]>.
+
+=cut
+*/
+
 void
-IM_RENDER_LINE(i_render *r, int x, int y, int width, const IM_SAMPLE_T *src,
-             IM_COLOR *line, IM_FILL_COMBINE_F combine) {
+IM_RENDER_LINE(i_render *r, i_img_dim x, i_img_dim y, i_img_dim width,
+              const IM_SAMPLE_T *src, IM_COLOR *line,
+              IM_FILL_COMBINE_F combine) {
   i_img *im = r->im;
   int src_chans = im->channels;
 
@@ -339,7 +413,7 @@ IM_RENDER_LINE(i_render *r, int x, int y, int width, const IM_SAMPLE_T *src,
 
   if (combine) {
     if (src) {
-      int work_width = width;
+      i_img_dim work_width = width;
       IM_COLOR *linep = line;
       const IM_SAMPLE_T *srcp = src;
       int alpha_chan = src_chans - 1;
@@ -364,7 +438,7 @@ IM_RENDER_LINE(i_render *r, int x, int y, int width, const IM_SAMPLE_T *src,
   }
   else {
     if (src) {
-      int work_width = width;
+      i_img_dim work_width = width;
       IM_COLOR *srcc = line;
       IM_COLOR *destc = r->IM_SUFFIX(line);
 
@@ -398,12 +472,13 @@ IM_RENDER_LINE(i_render *r, int x, int y, int width, const IM_SAMPLE_T *src,
 
 static
 void
-IM_SUFFIX(render_color_13)(i_render *r, int x, int y, int width, 
-                unsigned char const *src, i_color const *color) {
+IM_SUFFIX(render_color_13)(i_render *r, i_img_dim x, i_img_dim y,
+                          i_img_dim width, unsigned char const *src,
+                          i_color const *color) {
   i_img *im = r->im;
   IM_COLOR *linep = r->IM_SUFFIX(line);
   int ch, channels = im->channels;
-  int fetch_offset;
+  i_img_dim fetch_offset;
 #undef STORE_COLOR
 #ifdef IM_EIGHT_BIT
 #define STORE_COLOR (*color)
@@ -445,12 +520,13 @@ IM_SUFFIX(render_color_13)(i_render *r, int x, int y, int width,
 
 static
 void
-IM_SUFFIX(render_color_alpha)(i_render *r, int x, int y, int width, 
-                unsigned char const *src, i_color const *color) {
+IM_SUFFIX(render_color_alpha)(i_render *r, i_img_dim x, i_img_dim y,
+                             i_img_dim width, unsigned char const *src,
+                             i_color const *color) {
   IM_COLOR *linep = r->IM_SUFFIX(line);
   int ch;
   int alpha_channel = r->im->channels - 1;
-  int fetch_offset;
+  i_img_dim fetch_offset;
 #undef STORE_COLOR
 #ifdef IM_EIGHT_BIT
 #define STORE_COLOR (*color)
@@ -505,7 +581,7 @@ IM_SUFFIX(render_color_alpha)(i_render *r, int x, int y, int width,
 
 static void
 IM_SUFFIX(combine_line_alpha)(IM_COLOR *out, IM_COLOR const *in, 
-                             int channels, int count) {
+                             int channels, i_img_dim count) {
   int ch;
   int alpha_channel = channels - 1;
   
@@ -542,7 +618,7 @@ IM_SUFFIX(combine_line_alpha)(IM_COLOR *out, IM_COLOR const *in,
 
 static void
 IM_SUFFIX(combine_line_noalpha)
-     (IM_COLOR *out, IM_COLOR const *in, int channels, int count) {
+     (IM_COLOR *out, IM_COLOR const *in, int channels, i_img_dim count) {
   int ch;
 
   while (count) {
@@ -577,7 +653,7 @@ IM_SUFFIX(combine_line_noalpha)
 
 static void
 IM_SUFFIX(combine_line_alpha_na)(IM_COLOR *out, IM_COLOR const *in, 
-                                  int channels, int count) {
+                                  int channels, i_img_dim count) {
   int ch;
   int alpha_channel = channels - 1;
   
@@ -605,7 +681,7 @@ IM_SUFFIX(combine_line_alpha_na)(IM_COLOR *out, IM_COLOR const *in,
 }
 
 static void
-IM_SUFFIX(combine_line)(IM_COLOR *out, IM_COLOR const *in, int channels, int count) {
+IM_SUFFIX(combine_line)(IM_COLOR *out, IM_COLOR const *in, int channels, i_img_dim count) {
   if (channels == 2 || channels == 4)
     IM_SUFFIX(combine_line_alpha)(out, in, channels, count);
   else
@@ -613,25 +689,25 @@ IM_SUFFIX(combine_line)(IM_COLOR *out, IM_COLOR const *in, int channels, int cou
 }
 
 static void
-IM_SUFFIX(combine_line_na)(IM_COLOR *out, IM_COLOR const *in, int channels, int count) {
+IM_SUFFIX(combine_line_na)(IM_COLOR *out, IM_COLOR const *in, int channels, i_img_dim count) {
   if (channels == 2 || channels == 4)
     IM_SUFFIX(combine_line_alpha_na)(out, in, channels, count);
   else
     IM_SUFFIX(combine_line_noalpha)(out, in, channels, count);
 }
 
-static void IM_SUFFIX(combine_alphablend)(IM_COLOR *, IM_COLOR *, int, int);
-static void IM_SUFFIX(combine_mult)(IM_COLOR *, IM_COLOR *, int, int);
-static void IM_SUFFIX(combine_dissolve)(IM_COLOR *, IM_COLOR *, int, int);
-static void IM_SUFFIX(combine_add)(IM_COLOR *, IM_COLOR *, int, int);
-static void IM_SUFFIX(combine_subtract)(IM_COLOR *, IM_COLOR *, int, int);
-static void IM_SUFFIX(combine_diff)(IM_COLOR *, IM_COLOR *, int, int);
-static void IM_SUFFIX(combine_darken)(IM_COLOR *, IM_COLOR *, int, int);
-static void IM_SUFFIX(combine_lighten)(IM_COLOR *, IM_COLOR *, int, int);
-static void IM_SUFFIX(combine_hue)(IM_COLOR *, IM_COLOR *, int, int);
-static void IM_SUFFIX(combine_sat)(IM_COLOR *, IM_COLOR *, int, int);
-static void IM_SUFFIX(combine_value)(IM_COLOR *, IM_COLOR *, int, int);
-static void IM_SUFFIX(combine_color)(IM_COLOR *, IM_COLOR *, int, int);
+static void IM_SUFFIX(combine_alphablend)(IM_COLOR *, IM_COLOR *, int, i_img_dim);
+static void IM_SUFFIX(combine_mult)(IM_COLOR *, IM_COLOR *, int, i_img_dim);
+static void IM_SUFFIX(combine_dissolve)(IM_COLOR *, IM_COLOR *, int, i_img_dim);
+static void IM_SUFFIX(combine_add)(IM_COLOR *, IM_COLOR *, int, i_img_dim);
+static void IM_SUFFIX(combine_subtract)(IM_COLOR *, IM_COLOR *, int, i_img_dim);
+static void IM_SUFFIX(combine_diff)(IM_COLOR *, IM_COLOR *, int, i_img_dim);
+static void IM_SUFFIX(combine_darken)(IM_COLOR *, IM_COLOR *, int, i_img_dim);
+static void IM_SUFFIX(combine_lighten)(IM_COLOR *, IM_COLOR *, int, i_img_dim);
+static void IM_SUFFIX(combine_hue)(IM_COLOR *, IM_COLOR *, int, i_img_dim);
+static void IM_SUFFIX(combine_sat)(IM_COLOR *, IM_COLOR *, int, i_img_dim);
+static void IM_SUFFIX(combine_value)(IM_COLOR *, IM_COLOR *, int, i_img_dim);
+static void IM_SUFFIX(combine_color)(IM_COLOR *, IM_COLOR *, int, i_img_dim);
 
 static const IM_FILL_COMBINE_F IM_SUFFIX(combines)[] =
 {
@@ -688,7 +764,7 @@ void i_get_combine(int combine, i_fill_combine_f *color_func,
 
 
 static void 
-IM_SUFFIX(combine_alphablend)(IM_COLOR *out, IM_COLOR *in, int channels, int count) {
+IM_SUFFIX(combine_alphablend)(IM_COLOR *out, IM_COLOR *in, int channels, i_img_dim count) {
   IM_SUFFIX(combine_line)(out, in, channels, count);
 }
 
@@ -702,11 +778,11 @@ When Da=1
 Dc' = Sc.Sa.Dc + Dc.(1 - Sa)
  */
 static void
-IM_SUFFIX(combine_mult)(IM_COLOR *out, IM_COLOR *in, int channels, int count) {
+IM_SUFFIX(combine_mult)(IM_COLOR *out, IM_COLOR *in, int channels, i_img_dim count) {
   int ch;
   IM_COLOR *inp = in;
   IM_COLOR *outp = out;
-  int work_count = count;
+  i_img_dim work_count = count;
   int color_channels = i_color_channels(channels);
 
   if (i_has_alpha(channels)) {
@@ -751,7 +827,7 @@ IM_SUFFIX(combine_mult)(IM_COLOR *out, IM_COLOR *in, int channels, int count) {
 }
 
 static void 
-IM_SUFFIX(combine_dissolve)(IM_COLOR *out, IM_COLOR *in, int channels, int count) {
+IM_SUFFIX(combine_dissolve)(IM_COLOR *out, IM_COLOR *in, int channels, i_img_dim count) {
   int color_channels = i_color_channels(channels);
   int ch;
 
@@ -788,10 +864,10 @@ Da'  = Sa.Da + Da.Sa + Sa.(1 - Da) + Da.(1 - Sa)
 */
 
 static void
-IM_SUFFIX(combine_add)(IM_COLOR *out, IM_COLOR *in, int channels, int count) {
+IM_SUFFIX(combine_add)(IM_COLOR *out, IM_COLOR *in, int channels, i_img_dim count) {
   int ch;
   int color_channels = i_color_channels(channels);
-  int work_count = count;
+  i_img_dim work_count = count;
   IM_COLOR *inp = in;
   IM_COLOR *outp = out;
 
@@ -843,11 +919,11 @@ IM_SUFFIX(combine_add)(IM_COLOR *out, IM_COLOR *in, int channels, int count) {
    channel to apply that to the target.
  */
 static void
-IM_SUFFIX(combine_subtract)(IM_COLOR *out, IM_COLOR *in, int channels, int count) {
+IM_SUFFIX(combine_subtract)(IM_COLOR *out, IM_COLOR *in, int channels, i_img_dim count) {
   int ch;
   IM_COLOR const *inp = in;
   IM_COLOR *outp = out;
-  int work_count = count;
+  i_img_dim work_count = count;
   int color_channels = i_color_channels(channels);
 
   if (i_has_alpha(channels)) {
@@ -901,11 +977,11 @@ Dca' = abs(Dca.Sa - Sca.Da) + Sca.(1 - Da) + Dca.(1 - Sa)
 Da'  = Sa + Da - Sa.Da 
 */
 static void
-IM_SUFFIX(combine_diff)(IM_COLOR *out, IM_COLOR *in, int channels, int count) {
+IM_SUFFIX(combine_diff)(IM_COLOR *out, IM_COLOR *in, int channels, i_img_dim count) {
   int ch;
   IM_COLOR const *inp = in;
   IM_COLOR *outp = out;
-  int work_count = count;
+  i_img_dim work_count = count;
   int color_channels = i_color_channels(channels);
 
   if (i_has_alpha(channels)) {
@@ -969,11 +1045,11 @@ IM_SUFFIX(combine_diff)(IM_COLOR *out, IM_COLOR *in, int channels, int count) {
  */
 static void 
 IM_SUFFIX(combine_darken)(IM_COLOR *out, IM_COLOR *in, int channels, 
-                         int count) {
+                         i_img_dim count) {
   int ch;
   IM_COLOR const *inp = in;
   IM_COLOR *outp = out;
-  int work_count = count;
+  i_img_dim work_count = count;
   int color_channels = i_color_channels(channels);
 
   if (i_has_alpha(channels)) {
@@ -1024,11 +1100,11 @@ IM_SUFFIX(combine_darken)(IM_COLOR *out, IM_COLOR *in, int channels,
 }
 
 static void 
-IM_SUFFIX(combine_lighten)(IM_COLOR *out, IM_COLOR *in, int channels, int count) {
+IM_SUFFIX(combine_lighten)(IM_COLOR *out, IM_COLOR *in, int channels, i_img_dim count) {
   int ch;
   IM_COLOR const *inp = in;
   IM_COLOR *outp = out;
-  int work_count = count;
+  i_img_dim work_count = count;
   int color_channels = i_color_channels(channels);
 
   if (i_has_alpha(channels)) {
@@ -1087,11 +1163,11 @@ IM_SUFFIX(combine_lighten)(IM_COLOR *out, IM_COLOR *in, int channels, int count)
 #endif
 
 static void 
-IM_SUFFIX(combine_hue)(IM_COLOR *out, IM_COLOR *in, int channels, int count) {
+IM_SUFFIX(combine_hue)(IM_COLOR *out, IM_COLOR *in, int channels, i_img_dim count) {
   if (channels > 2) {
     IM_COLOR *inp = in;
     IM_COLOR const *outp = out;
-    int work_count = count;
+    i_img_dim work_count = count;
 
     if (i_has_alpha(channels)) {
       while (work_count--) {
@@ -1148,11 +1224,11 @@ IM_SUFFIX(combine_hue)(IM_COLOR *out, IM_COLOR *in, int channels, int count) {
 }
 
 static void
-IM_SUFFIX(combine_sat)(IM_COLOR *out, IM_COLOR *in, int channels, int count) {
+IM_SUFFIX(combine_sat)(IM_COLOR *out, IM_COLOR *in, int channels, i_img_dim count) {
   if (channels > 2) {
     IM_COLOR *inp = in;
     IM_COLOR const *outp = out;
-    int work_count = count;
+    i_img_dim work_count = count;
 
     while (work_count--) {
       IM_COLOR c = *inp;
@@ -1171,11 +1247,11 @@ IM_SUFFIX(combine_sat)(IM_COLOR *out, IM_COLOR *in, int channels, int count) {
 }
 
 static void 
-IM_SUFFIX(combine_value)(IM_COLOR *out, IM_COLOR *in, int channels, int count) {
+IM_SUFFIX(combine_value)(IM_COLOR *out, IM_COLOR *in, int channels, i_img_dim count) {
   if (channels > 2) {
     IM_COLOR *inp = in;
     IM_COLOR const *outp = out;
-    int work_count = count;
+    i_img_dim work_count = count;
 
     while (work_count--) {
       IM_COLOR c = *inp;
@@ -1196,11 +1272,11 @@ IM_SUFFIX(combine_value)(IM_COLOR *out, IM_COLOR *in, int channels, int count) {
 }
 
 static void 
-IM_SUFFIX(combine_color)(IM_COLOR *out, IM_COLOR *in, int channels, int count) {
+IM_SUFFIX(combine_color)(IM_COLOR *out, IM_COLOR *in, int channels, i_img_dim count) {
   if (channels > 2) {
     IM_COLOR *inp = in;
     IM_COLOR const *outp = out;
-    int work_count = count;
+    i_img_dim work_count = count;
 
     while (work_count--) {
       IM_COLOR c = *inp;
index 2eb79a2..3aa2470 100644 (file)
--- a/rendert.h
+++ b/rendert.h
@@ -1,17 +1,19 @@
 #ifndef IMAGER_RENDERT_H
 #define IMAGER_RENDERT_H
 
-typedef struct {
+#include "imdatatypes.h"
+
+struct i_render_tag {
   int magic;
   i_img *im;
 
-  int line_width;
+  i_img_dim line_width;
   i_color *line_8;
   i_fcolor *line_double;
 
-  int fill_width;
+  i_img_dim fill_width;
   i_color *fill_line_8;
   i_fcolor *fill_line_double;
-} i_render;
+};
 
 #endif
diff --git a/t/t38ft2font.t b/t/t38ft2font.t
deleted file mode 100644 (file)
index 85f8ed6..0000000
+++ /dev/null
@@ -1,592 +0,0 @@
-#!perl -w
-use strict;
-use Test::More tests => 189;
-use Cwd qw(getcwd abs_path);
-++$|;
-# Before `make install' is performed this script should be runnable with
-# `make test'. After `make install' it should work as `perl test.pl'
-
-######################### We start with some black magic to print on failure.
-
-# Change 1..1 below to 1..last_test_to_print .
-# (It may become useful if the test is moved to ./t subdirectory.)
-
-BEGIN { use_ok(Imager => ':all') }
-
-use Imager::Test qw(diff_text_with_nul is_color3);
-
-init_log("testout/t38ft2font.log",2);
-
-my $deffont = "fontfiles/dodge.ttf";
-
-my @base_color = (64, 255, 64);
-
-SKIP:
-{
-  i_has_format("ft2") or skip("no freetype2 library found", 188);
-
-  print "# has ft2\n";
-  
-  my $fontname=$ENV{'TTFONTTEST'} || $deffont;
-
-  -f $fontname or skip("cannot find fontfile $fontname", 188);
-
-
-  my $bgcolor=i_color_new(255,0,0,0);
-  my $overlay=Imager::ImgRaw::new(200,70,3);
-  
-  my $ttraw=Imager::Font::FreeType2::i_ft2_new($fontname, 0);
-  
-  $ttraw or print Imager::_error_as_msg(),"\n";
-  ok($ttraw, "loaded raw font");
-
-  my @bbox=Imager::Font::FreeType2::i_ft2_bbox($ttraw, 50.0, 0, 'XMCLH', 0);
-  print "#bbox @bbox\n";
-  
-  is(@bbox, 8, "i_ft2_bbox() returns 8 values");
-
-  ok(Imager::Font::FreeType2::i_ft2_cp($ttraw,$overlay,5,50,1,50.0,50, 'XMCLH',1,1, 0, 0), "drawn to channel");
-  i_line($overlay,0,50,100,50,$bgcolor,1);
-
-  open(FH,">testout/t38ft2font.ppm") || die "cannot open testout/t38ft2font.ppm\n";
-  binmode(FH);
-  my $IO = Imager::io_new_fd(fileno(FH));
-  ok(i_writeppm_wiol($overlay, $IO), "saved image");
-  close(FH);
-
-  $bgcolor=i_color_set($bgcolor,200,200,200,0);
-  my $backgr=Imager::ImgRaw::new(500,300,3);
-  
-  #     i_tt_set_aa(2);
-  ok(Imager::Font::FreeType2::i_ft2_text($ttraw,$backgr,100,150,NC(255, 64, 64),200.0,50, 'MAW',1,1,0, 0), "drew MAW");
-  Imager::Font::FreeType2::i_ft2_settransform($ttraw, [0.9659, 0.2588, 0, -0.2588, 0.9659, 0 ]);
-  ok(Imager::Font::FreeType2::i_ft2_text($ttraw,$backgr,100,150,NC(0, 128, 0),200.0,50, 'MAW',0,1, 0, 0), "drew rotated MAW");
-  i_line($backgr, 0,150, 499, 150, NC(0, 0, 255),1);
-
-  open(FH,">testout/t38ft2font2.ppm") || die "cannot open testout/t38ft2font.ppm\n";
-  binmode(FH);
-  $IO = Imager::io_new_fd(fileno(FH));
-  ok(i_writeppm_wiol($backgr,$IO), "saved second image");
-  close(FH);
-
-  my $oof = Imager::Font->new(file=>$fontname, type=>'ft2', 'index'=>0);
-
-  ok($oof, "loaded OO font");
-
-  my $im = Imager->new(xsize=>400, ysize=>250);
-  
-  ok($im->string(font=>$oof,
-                 text=>"Via OO",
-                 'x'=>20,
-                 'y'=>20,
-                 size=>60,
-                 color=>NC(255, 128, 255),
-                 aa => 1,
-                 align=>0), "drawn through OO interface");
-  ok($oof->transform(matrix=>[1, 0.1, 0, 0, 1, 0]),
-     "set matrix via OO interface");
-  ok($im->string(font=>$oof,
-                 text=>"Shear",
-                 'x'=>20,
-                 'y'=>40,
-                 size=>60,
-                 sizew=>50,
-                 channel=>1,
-                 aa=>1,
-                 align=>1), "drawn transformed through OO");
-  use Imager::Matrix2d ':handy';
-  ok($oof->transform(matrix=>m2d_rotate(degrees=>-30)),
-     "set transform from m2d module");
-  ok($im->string(font=>$oof,
-                 text=>"SPIN",
-                 'x'=>20,
-                 'y'=>50,
-                 size=>50,
-                 sizew=>40,
-                 color=>NC(255,255,0),
-                 aa => 1,
-                 align=>0, vlayout=>0), "drawn first rotated");
-
-  ok($im->string(font=>$oof,
-                 text=>"SPIN",
-                 'x'=>20,
-                 'y'=>50,
-                 size=>50,
-                 sizew=>40,
-            channel=>2,
-                 aa => 1,
-                 align=>0, vlayout=>0), "drawn second rotated");
-  
-  $oof->transform(matrix=>m2d_identity());
-  $oof->hinting(hinting=>1);
-
-  # UTF8 testing
-  # the test font (dodge.ttf) only supports one character above 0xFF that
-  # I can see, 0x2010 HYPHEN (which renders the same as 0x002D HYPHEN MINUS)
-  # an attempt at utf8 support
-  # first attempt to use native perl UTF8
- SKIP:
-  {
-    skip("no native UTF8 support in this version of perl", 1) 
-      unless $] >= 5.006;
-    my $text;
-    # we need to do this in eval to prevent compile time errors in older
-    # versions
-    eval q{$text = "A\x{2010}A"}; # A, HYPHEN, A in our test font
-    #$text = "A".chr(0x2010)."A"; # this one works too
-    unless (ok($im->string(font=>$oof,
-                           text=>$text,
-                           'x'=>20,
-                           'y'=>200,
-                           size=>50,
-                           color=>NC(0,255,0),
-                           aa=>1), "drawn UTF natively")) {
-      print "# ",$im->errstr,"\n";
-    }
-  }
-
-  # an attempt using emulation of UTF8
-  my $text = pack("C*", 0x41, 0xE2, 0x80, 0x90, 0x41);
-  #my $text = "A\xE2\x80\x90\x41\x{2010}";
-  #substr($text, -1, 0) = '';
-  unless (ok($im->string(font=>$oof,
-                         text=>$text,
-                         'x'=>20,
-                         'y'=>230,
-                         size=>50,
-                         color=>NC(255,128,0),
-                         aa=>1, 
-                         utf8=>1), "drawn UTF emulated")) {
-    print "# ",$im->errstr,"\n";
-  }
-
-  # just a bit of fun
-  # well it was - it demostrates what happens when you combine
-  # transformations and font hinting
-  for my $steps (0..39) {
-    $oof->transform(matrix=>m2d_rotate(degrees=>-$steps+5));
-    # demonstrates why we disable hinting on a doing a transform
-    # if the following line is enabled then the 0 degrees output sticks 
-    # out a bit
-    # $oof->hinting(hinting=>1);
-    $im->string(font=>$oof,
-                text=>"SPIN",
-                'x'=>160,
-                'y'=>70,
-                size=>65,
-                color=>NC(255, $steps * 5, 200-$steps * 5),
-                aa => 1,
-                align=>0, );
-  }
-
-  $im->write(file=>'testout/t38_oo.ppm')
-    or print "# could not save OO output: ",$im->errstr,"\n";
-  
-  my (@got) = $oof->has_chars(string=>"\x01H");
-  ok(@got == 2, "has_chars returned 2 items");
-  ok(!$got[0], "have no chr(1)");
-  ok($got[1], "have 'H'");
-  is($oof->has_chars(string=>"H\x01"), "\x01\x00",
-     "scalar has_chars()");
-
-  print "# OO bounding boxes\n";
-  @bbox = $oof->bounding_box(string=>"hello", size=>30);
-  my $bbox = $oof->bounding_box(string=>"hello", size=>30);
-
-  is(@bbox, 8, "list bbox returned 8 items");
-  ok($bbox->isa('Imager::Font::BBox'), "scalar bbox returned right class");
-  ok($bbox->start_offset == $bbox[0], "start_offset");
-  ok($bbox->end_offset == $bbox[2], "end_offset");
-  ok($bbox->global_ascent == $bbox[3], "global_ascent");
-  ok($bbox->global_descent == $bbox[1], "global_descent");
-  ok($bbox->ascent == $bbox[5], "ascent");
-  ok($bbox->descent == $bbox[4], "descent");
-  ok($bbox->advance_width == $bbox[6], "advance_width");
-
-  print "# aligned text output\n";
-  my $alimg = Imager->new(xsize=>300, ysize=>300);
-  $alimg->box(color=>'40FF40', filled=>1);
-
-  $oof->transform(matrix=>m2d_identity());
-  $oof->hinting(hinting=>1);
-  
-  align_test('left', 'top', 10, 10, $oof, $alimg);
-  align_test('start', 'top', 10, 40, $oof, $alimg);
-  align_test('center', 'top', 150, 70, $oof, $alimg);
-  align_test('end', 'top', 290, 100, $oof, $alimg);
-  align_test('right', 'top', 290, 130, $oof, $alimg);
-
-  align_test('center', 'top', 150, 160, $oof, $alimg);
-  align_test('center', 'center', 150, 190, $oof, $alimg);
-  align_test('center', 'bottom', 150, 220, $oof, $alimg);
-  align_test('center', 'baseline', 150, 250, $oof, $alimg);
-  
-  ok($alimg->write(file=>'testout/t38aligned.ppm'), 
-     "saving aligned output image");
-  
-  my $exfont = Imager::Font->new(file=>'fontfiles/ExistenceTest.ttf',
-                                 type=>'ft2');
-  SKIP:
-  {
-    ok($exfont, "loaded existence font") or
-      skip("couldn't load test font", 11);
-
-    # the test font is known to have a shorter advance width for that char
-    my @bbox = $exfont->bounding_box(string=>"/", size=>100);
-    is(@bbox, 8, "should be 8 entries");
-    isnt($bbox[6], $bbox[2], "different advance width");
-    my $bbox = $exfont->bounding_box(string=>"/", size=>100);
-    ok($bbox->pos_width != $bbox->advance_width, "OO check");
-
-    cmp_ok($bbox->right_bearing, '<', 0, "check right bearing");
-
-    cmp_ok($bbox->display_width, '>', $bbox->advance_width,
-           "check display width (roughly)");
-
-    # check with a char that fits inside the box
-    $bbox = $exfont->bounding_box(string=>"!", size=>100);
-    print "# pos width ", $bbox->pos_width, "\n";
-    is($bbox->pos_width, $bbox->advance_width, 
-       "check backwards compatibility");
-    cmp_ok($bbox->left_bearing, '>', 0, "left bearing positive");
-    cmp_ok($bbox->right_bearing, '>', 0, "right bearing positive");
-    cmp_ok($bbox->display_width, '<', $bbox->advance_width,
-           "display smaller than advance");
-
-    # name tests
-    # make sure the number of tests on each branch match
-    if (Imager::Font::FreeType2::i_ft2_can_face_name()) {
-      my $facename = Imager::Font::FreeType2::i_ft2_face_name($exfont->{id});
-      print "# face name '$facename'\n";
-      is($facename, 'ExistenceTest', "test face name");
-      $facename = $exfont->face_name;
-      is($facename, 'ExistenceTest', "test face name OO");
-    }
-    else {
-      # make sure we get the error we expect
-      my $facename = Imager::Font::FreeType2::i_ft2_face_name($exfont->{id});
-      my ($msg) = Imager::_error_as_msg();
-      ok(!defined($facename), "test face name not supported");
-      print "# $msg\n";
-      ok(scalar($msg =~ /or later required/), "test face name not supported");
-    }
-  }
-
-  SKIP:
-  {
-    Imager::Font::FreeType2->can_glyph_names
-        or skip("FT2 compiled without glyph names support", 9);
-        
-    # FT2 considers POST tables in TTF fonts unreliable, so use
-    # a type 1 font, see below for TTF test 
-    my $exfont = Imager::Font->new(file=>'fontfiles/ExistenceTest.pfb',
-                               type=>'ft2');
-  SKIP:
-    {
-      ok($exfont, "load Type 1 via FT2")
-        or skip("couldn't load type 1 with FT2", 8);
-      my @glyph_names = 
-        Imager::Font::FreeType2::i_ft2_glyph_name($exfont->{id}, "!J/");
-      #use Data::Dumper;
-      #print Dumper \@glyph_names;
-      is($glyph_names[0], 'exclam', "check exclam name");
-      ok(!defined($glyph_names[1]), "check for no J name");
-      is($glyph_names[2], 'slash', "check slash name");
-
-      # oo interfaces
-      @glyph_names = $exfont->glyph_names(string=>"!J/");
-      is($glyph_names[0], 'exclam', "check exclam name OO");
-      ok(!defined($glyph_names[1]), "check for no J name OO");
-      is($glyph_names[2], 'slash', "check slash name OO");
-
-      # make sure a missing string parameter is handled correctly
-      eval {
-        $exfont->glyph_names();
-      };
-      is($@, "", "correct error handling");
-      cmp_ok(Imager->errstr, '=~', qr/no string parameter/, "error message");
-    }
-  
-    # freetype 2 considers truetype glyph name tables unreliable
-    # due to some specific fonts, supplying reliable_only=>0 bypasses
-    # that check and lets us get the glyph names even for truetype fonts
-    # so we can test this stuff <sigh>
-    # we can't use ExistenceTest.ttf since that's generated with 
-    # AppleStandardEncoding since the same .sfd needs to generate
-    # a .pfb file, NameTest.ttf uses a Unicode encoding
-    
-    # we were using an unsigned char to store a unicode character
-    # https://rt.cpan.org/Ticket/Display.html?id=7949
-    $exfont = Imager::Font->new(file=>'fontfiles/NameTest.ttf',
-                                type=>'ft2');
-  SKIP:
-    {
-      ok($exfont, "load TTF via FT2")
-        or skip("could not load TTF with FT2", 1);
-      my $text = pack("C*", 0xE2, 0x80, 0x90); # "\x{2010}" as utf-8
-      my @names = $exfont->glyph_names(string=>$text,
-                                       utf8=>1, reliable_only=>0);
-      is($names[0], "hyphentwo", "check utf8 glyph name");
-    }
-  }
-
-  # check that error codes are translated correctly
-  my $errfont = Imager::Font->new(file=>"t/t38ft2font.t", type=>"ft2");
-  is($errfont, undef, "new font vs non font");
-  cmp_ok(Imager->errstr, '=~', qr/unknown file format/, "check error message");
-
-  # Multiple Master tests
-  # we check a non-MM font errors correctly
-  print "# check that the methods act correctly for a non-MM font\n";
-  ok(!$exfont->is_mm, "exfont not MM");
-  ok((() = $exfont->mm_axes) == 0, "exfont has no MM axes");
-  cmp_ok(Imager->errstr, '=~', qr/no multiple masters/, 
-         "and returns correct error when we ask");
-  ok(!$exfont->set_mm_coords(coords=>[0, 0]), "fail setting axis on exfont");
-  cmp_ok(Imager->errstr, '=~', qr/no multiple masters/, 
-         "and returns correct error when we ask");
-
-  # try a MM font now - test font only has A defined
-  print "# Try a multiple master font\n";
-  my $mmfont = Imager::Font->new(file=>"fontfiles/MMOne.pfb", type=>"ft2", 
-                                 color=>"white", aa=>1, size=>60);
-  ok($mmfont, "loaded MM font");
-  ok($mmfont->is_mm, "font is multiple master");
-  my @axes = $mmfont->mm_axes;
-  is(@axes, 2, "check we got both axes");
-  is($axes[0][0], "Weight", "name of first axis");
-  is($axes[0][1],  50, "min for first axis");
-  is($axes[0][2], 999, "max for first axis");
-  is($axes[1][0], "Slant", "name of second axis");
-  is($axes[1][1],   0, "min for second axis");
-  is($axes[1][2], 999, "max for second axis");
-  my $mmim = Imager->new(xsize=>200, ysize=>200);
-  $mmim->string(font=>$mmfont, x=>0, 'y'=>50, text=>"A");
-  ok($mmfont->set_mm_coords(coords=>[ 700, 0 ]), "set to bold, unsloped");
-  $mmim->string(font=>$mmfont, x=>0, 'y'=>100, text=>"A", color=>'blue');
-  my @weights = qw(50 260 525 760 999);
-  my @slants = qw(0 333 666 999);
-  for my $windex (0 .. $#weights) {
-    my $weight = $weights[$windex];
-    for my $sindex (0 .. $#slants) {
-      my $slant = $slants[$sindex];
-      $mmfont->set_mm_coords(coords=>[ $weight, $slant ]);
-      $mmim->string(font=>$mmfont, x=>30+32*$windex, 'y'=>50+45*$sindex,
-                    text=>"A");
-    }
-  }
-
-  ok($mmim->write(file=>"testout/t38mm.ppm"), "save MM output");
-
- SKIP:
-  { print "# alignment tests\n";
-    my $font = Imager::Font->new(file=>'fontfiles/ImUgly.ttf', type=>'ft2');
-    ok($font, "loaded deffont OO")
-      or skip("could not load font:".Imager->errstr, 4);
-    my $im = Imager->new(xsize=>140, ysize=>150);
-    my %common = 
-      (
-       font=>$font, 
-       size=>40, 
-       aa=>1,
-      );
-    $im->line(x1=>0, y1=>40, x2=>139, y2=>40, color=>'blue');
-    $im->line(x1=>0, y1=>90, x2=>139, y2=>90, color=>'blue');
-    $im->line(x1=>0, y1=>110, x2=>139, y2=>110, color=>'blue');
-    for my $args ([ x=>5,   text=>"A", color=>"white" ],
-                  [ x=>40,  text=>"y", color=>"white" ],
-                  [ x=>75,  text=>"A", channel=>1 ],
-                  [ x=>110, text=>"y", channel=>1 ]) {
-      ok($im->string(%common, @$args, 'y'=>40), "A no alignment");
-      ok($im->string(%common, @$args, 'y'=>90, align=>1), "A align=1");
-      ok($im->string(%common, @$args, 'y'=>110, align=>0), "A align=0");
-    }
-    ok($im->write(file=>'testout/t38align.ppm'), "save align image");
-  }
-
-
-  { # outputting a space in non-AA could either crash 
-    # or fail (ft 2.2+)
-    my $font = Imager::Font->new(file=>'fontfiles/ImUgly.ttf', type=>'ft2');
-    my $im = Imager->new(xsize => 100, ysize => 100);
-    ok($im->string(x => 10, y => 10, string => "test space", aa => 0,
-                  color => '#FFF', size => 8, font => $font),
-       "draw space non-antialiased (color)");
-    ok($im->string(x => 10, y => 50, string => "test space", aa => 0,
-                  channel => 0, size => 8, font => $font),
-       "draw space non-antialiased (channel)");
-  }
-
-  { # cannot output "0"
-    # https://rt.cpan.org/Ticket/Display.html?id=21770
-    my $font = Imager::Font->new(file=>'fontfiles/ImUgly.ttf', type=>'ft2');
-    ok($font, "loaded imugly");
-    my $imbase = Imager->new(xsize => 100, ysize => 100);
-    my $im = $imbase->copy;
-    ok($im->string(x => 10, y => 50, string => "0", aa => 0,
-                  color => '#FFF', size => 20, font => $font),
-       "draw '0'");
-    ok(Imager::i_img_diff($im->{IMG}, $imbase->{IMG}),
-       "make sure we actually drew it");
-    $im = $imbase->copy;
-    ok($im->string(x => 10, y => 50, string => 0.0, aa => 0,
-                  color => '#FFF', size => 20, font => $font),
-       "draw 0.0");
-    ok(Imager::i_img_diff($im->{IMG}, $imbase->{IMG}),
-       "make sure we actually drew it");
-  }
-  { # string output cut off at NUL ('\0')
-    # https://rt.cpan.org/Ticket/Display.html?id=21770 cont'd
-    my $font = Imager::Font->new(file=>'fontfiles/ImUgly.ttf', type=>'ft2');
-    ok($font, "loaded imugly");
-
-    diff_text_with_nul("a\\0b vs a", "a\0b", "a", 
-                      font => $font, color => '#FFFFFF');
-    diff_text_with_nul("a\\0b vs a", "a\0b", "a", 
-                      font => $font, channel => 1);
-
-    # UTF8 encoded \x{2010}
-    my $dash = pack("C*", 0xE2, 0x80, 0x90);
-    diff_text_with_nul("utf8 dash\0dash vs dash", "$dash\0$dash", $dash,
-                      font => $font, color => '#FFFFFF', utf8 => 1);
-    diff_text_with_nul("utf8 dash\0dash vs dash", "$dash\0$dash", $dash,
-                      font => $font, channel => 1, utf8 => 1);
-  }
-
-  { # RT 11972
-    # when rendering to a transparent image the coverage should be
-    # expressed in terms of the alpha channel rather than the color
-    my $font = Imager::Font->new(file=>'fontfiles/ImUgly.ttf', type=>'ft2');
-    my $im = Imager->new(xsize => 40, ysize => 20, channels => 4);
-    ok($im->string(string => "AB", size => 20, aa => 1, color => '#F00',
-                  x => 0, y => 15, font => $font),
-       "draw to transparent image");
-    my $im_noalpha = $im->convert(preset => 'noalpha');
-    my $im_pal = $im->to_paletted(make_colors => 'mediancut');
-    my @colors = $im_pal->getcolors;
-    is(@colors, 2, "should be only 2 colors");
-    @colors = sort { ($a->rgba)[0] <=> ($b->rgba)[0] } @colors;
-    is_color3($colors[0], 0, 0, 0, "check we got black");
-    is_color3($colors[1], 255, 0, 0, "and red");
-  }
-
-  { # RT 27546
-    my $im = Imager->new(xsize => 100, ysize => 100, channels => 4);
-    $im->box(filled => 1, color => '#ff0000FF');
-    my $font = Imager::Font->new(file=>'fontfiles/ImUgly.ttf', type=>'ft2');
-    ok($im->string(x => 0, 'y' => 40, text => 'test', 
-                  size => 11, sizew => 11, font => $font, aa => 1),
-       'draw on translucent image')
-  }
-
-  { # RT 60199
-    # not ft2 specific, but Imager
-    my $im = Imager->new(xsize => 100, ysize => 100);
-    my $font = Imager::Font->new(file=>'fontfiles/ImUgly.ttf', type=>'ft2');
-    my $imcopy = $im->copy;
-    ok($im, "make test image");
-    ok($font, "make test font");
-    ok($im->align_string(valign => "center", halign => "center",
-                        x => 50, y => 50, string => "0", color => "#FFF",
-                        font => $font),
-       "draw 0 aligned");
-    ok(Imager::i_img_diff($im->{IMG}, $imcopy->{IMG}),
-       "make sure we drew the '0'");
-  }
-
- SKIP:
-  { # RT 60509
-    # checks that a c:foo or c:\foo path is handled correctly on win32
-    my $type = "ft2";
-    $^O eq "MSWin32" || $^O eq "cygwin"
-      or skip("only for win32", 2);
-    my $dir = getcwd
-      or skip("Cannot get cwd", 2);
-    if ($^O eq "cygwin") {
-      $dir = Cygwin::posix_to_win_path($dir);
-    }
-    my $abs_path = abs_path($deffont);
-    my $font = Imager::Font->new(file => $abs_path, type => $type);
-    ok($font, "found font by absolute path")
-      or print "# path $abs_path\n";
-    undef $font;
-
-    $^O eq "cygwin"
-      and skip("cygwin doesn't support drive relative DOSsish paths", 1);
-    my ($drive) = $dir =~ /^([a-z]:)/i
-      or skip("cwd has no drive letter", 2);
-    my $drive_path = $drive . $deffont;
-    $font = Imager::Font->new(file => $drive_path, type => $type);
-    ok($font, "found font by drive relative path")
-      or print "# path $drive_path\n";
-  }
-
-}
-
-sub align_test {
-  my ($h, $v, $x, $y, $f, $img) = @_;
-
-  my @pos = $f->align(halign=>$h, valign=>$v, 'x'=>$x, 'y'=>$y,
-                      image=>$img, size=>15, color=>'FFFFFF',
-                      string=>"x$h ${v}y", channel=>1, aa=>1);
-  @pos = $img->align_string(halign=>$h, valign=>$v, 'x'=>$x, 'y'=>$y,
-                      font=>$f, size=>15, color=>'FF99FF',
-                      string=>"x$h ${v}y", aa=>1);
-  if (ok(@pos == 4, "$h $v aligned output")) {
-    # checking corners
-    my $cx = int(($pos[0] + $pos[2]) / 2);
-    my $cy = int(($pos[1] + $pos[3]) / 2);
-    
-    print "# @pos cx $cx cy $cy\n";
-    okmatchcolor($img, $cx, $pos[1]-1, @base_color, "outer top edge");
-    okmatchcolor($img, $cx, $pos[3], @base_color, "outer bottom edge");
-    okmatchcolor($img, $pos[0]-1, $cy, @base_color, "outer left edge");
-    okmatchcolor($img, $pos[2], $cy, @base_color, "outer right edge");
-    
-    okmismatchcolor($img, $cx, $pos[1], @base_color, "inner top edge");
-    okmismatchcolor($img, $cx, $pos[3]-1, @base_color, "inner bottom edge");
-    okmismatchcolor($img, $pos[0], $cy, @base_color, "inner left edge");
-#    okmismatchcolor($img, $pos[2]-1, $cy, @base_color, "inner right edge");
-# XXX: This gets triggered by a freetype2 bug I think 
-#    $ rpm -qa | grep freetype
-#    freetype-2.1.3-6
-#
-# (addi: 4/1/2004).
-
-    cross($img, $x, $y, 'FF0000');
-    cross($img, $cx, $pos[1]-1, '0000FF');
-    cross($img, $cx, $pos[3], '0000FF');
-    cross($img, $pos[0]-1, $cy, '0000FF');
-    cross($img, $pos[2], $cy, '0000FF');
-  }
-  else {
-    SKIP: { skip("couldn't draw text", 7) };
-  }
-}
-
-sub okmatchcolor {
-  my ($img, $x, $y, $r, $g, $b, $about) = @_;
-
-  my $c = $img->getpixel('x'=>$x, 'y'=>$y);
-  my ($fr, $fg, $fb) = $c->rgba;
-  ok($fr == $r && $fg == $g && $fb == $b,
-      "want ($r,$g,$b) found ($fr,$fg,$fb)\@($x,$y) $about");
-}
-
-sub okmismatchcolor {
-  my ($img, $x, $y, $r, $g, $b, $about) = @_;
-
-  my $c = $img->getpixel('x'=>$x, 'y'=>$y);
-  my ($fr, $fg, $fb) = $c->rgba;
-  ok($fr != $r || $fg != $g || $fb != $b,
-      "don't want ($r,$g,$b) found ($fr,$fg,$fb)\@($x,$y) $about");
-}
-
-sub cross {
-  my ($img, $x, $y, $color) = @_;
-
-  $img->setpixel('x'=>[$x, $x, $x, $x, $x, $x-2, $x-1, $x+1, $x+2], 
-                 'y'=>[$y-2, $y-1, $y, $y+1, $y+2, $y, $y, $y, $y], 
-                 color => $color);
-  
-}
index 9ff84e0..cf7f141 100644 (file)
@@ -44,6 +44,8 @@ RGBA
 postfix
 infix
 unary
+Uncategorized
+Blit
 /;
 
 local %Pod::Wordlist::Wordlist = %Pod::Wordlist::Wordlist;
diff --git a/typemap b/typemap
index 28159ad..74d5ae7 100644 (file)
--- a/typemap
+++ b/typemap
@@ -4,7 +4,6 @@ Imager::Color::Float    T_PTROBJ
 Imager::ImgRaw          T_IMAGER_IMAGE
 Imager::Font::TT       T_PTROBJ
 Imager::IO              T_PTROBJ
-Imager::Font::FT2       T_PTROBJ
 Imager::FillHandle      T_PTROBJ
 Imager::Internal::Hlines T_PTROBJ
 const char *           T_PV