bounding_box() for t1 driver fonts was treating spaces as empty space
authorTony Cook <tony@develop=help.com>
Thu, 20 Jul 2006 13:42:04 +0000 (13:42 +0000)
committerTony Cook <tony@develop=help.com>
Thu, 20 Jul 2006 13:42:04 +0000 (13:42 +0000)
when calculating the bounds, which they are, but this is inconsistent
with other drivers.  This was especially a problem for strings
containing only spaces where the left bound would end up far to the
right of the right bound, and similarly for the ascent and descent.

calculating the bounding box for an empty string invoked special
behaviour in t1lib, making it unreliable.

Fixes: http://rt.cpan.org/Ticket/Display.html?id=20555

MANIFEST
font.c
fontfiles/ExistenceTest.afm
fontfiles/ExistenceTest.pfb
fontfiles/ExistenceTest.sfd
fontfiles/SpaceTest.afm [new file with mode: 0644]
fontfiles/SpaceTest.pfb [new file with mode: 0644]
fontfiles/SpaceTest.sfd [new file with mode: 0644]
t/t30t1font.t

index 6cfee79..1b2c7ae 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -92,6 +92,8 @@ 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/SpaceTest.afm
+fontfiles/SpaceTest.pfb                test bounding box with spaces in t30t1font.t
 fontfiles/dcr10.afm
 fontfiles/dcr10.pfb
 fontfiles/dodge.ttf
diff --git a/font.c b/font.c
index e228fba..6f72710 100644 (file)
--- a/font.c
+++ b/font.c
@@ -298,6 +298,17 @@ i_t1_cp(i_img *im,int xb,int yb,int channel,int fontnum,float points,char* str,i
   return 1;
 }
 
+static void
+t1_fix_bbox(BBox *bbox, const char *str, int len, int advance, 
+           int space_position) {
+  /* never called with len == 0 */
+  if (str[0] == space_position && bbox->llx > 0)
+    bbox->llx = 0;
+  if (str[len-1] == space_position && bbox->urx < advance)
+    bbox->urx = advance;
+  if (bbox->lly > bbox->ury)
+    bbox->lly = bbox->ury = 0; 
+}
 
 /*
 =item i_t1_bbox(handle, fontnum, points, str, len, cords)
@@ -320,20 +331,32 @@ i_t1_bbox(int fontnum,float points,const char *str,int len,int cords[6], int utf
   BBox gbbox;
   int mod_flags = t1_get_flags(flags);
   int advance;
+  int space_position = T1_GetEncodingIndex(fontnum, "space");
   
   mm_log((1,"i_t1_bbox(fontnum %d,points %.2f,str '%.*s', len %d)\n",fontnum,points,len,str,len));
   T1_LoadFont(fontnum);  /* FIXME: Here a return code is ignored - haw haw haw */ 
-  if (utf8) {
-    int worklen;
-    char *work = t1_from_utf8(str, len, &worklen);
-    bbox = T1_GetStringBBox(fontnum,work,worklen,0,mod_flags);
-    myfree(work);
+
+  if (len == 0) {
+    /* len == 0 has special meaning to T1lib, but it means there's
+       nothing to draw, so return that */
+    bbox.llx = bbox.lly = bbox.urx = bbox.ury = 0;
+    advance = 0;
   }
   else {
-    bbox = T1_GetStringBBox(fontnum,(char *)str,len,0,mod_flags);
+    advance = T1_GetStringWidth(fontnum, (char *)str, len, 0, mod_flags);
+    if (utf8) {
+      int worklen;
+      char *work = t1_from_utf8(str, len, &worklen);
+      bbox = T1_GetStringBBox(fontnum,work,worklen,0,mod_flags);
+      t1_fix_bbox(&bbox, work, worklen, advance, space_position);
+      myfree(work);
+    }
+    else {
+      bbox = T1_GetStringBBox(fontnum,(char *)str,len,0,mod_flags);
+      t1_fix_bbox(&bbox, str, len, advance, space_position);
+    }
   }
   gbbox = T1_GetFontBBox(fontnum);
-  advance = T1_GetStringWidth(fontnum, (char *)str, len, 0, mod_flags);
   
   mm_log((1,"bbox: (%d,%d,%d,%d)\n",
          (int)(bbox.llx*points/1000),
index 7dd627c..5200705 100644 (file)
@@ -1,6 +1,6 @@
 StartFontMetrics 2.0
 Comment Generated by pfaedit
-Comment Creation Date: Sat Dec 28 17:06:43 2002
+Comment Creation Date: Thu Jul 20 21:57:23 2006
 FontName ExistenceTest
 FullName ExistenceTest
 FamilyName ExistenceTest
@@ -13,7 +13,8 @@ UnderlineThickness 50
 Version 001.000
 EncodingScheme AdobeStandardEncoding
 FontBBox -60 -55 819 775
-StartCharMetrics 2
+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
index 46a9874..88863ad 100644 (file)
Binary files a/fontfiles/ExistenceTest.pfb and b/fontfiles/ExistenceTest.pfb differ
index 012568a..c76b93f 100644 (file)
@@ -11,6 +11,7 @@ UnderlinePosition: -100
 UnderlineWidth: 50
 Ascent: 800
 Descent: 200
+NeedsXUIDChange: 1
 FSType: 12
 PfmFamily: 17
 TTFWeight: 500
@@ -18,17 +19,42 @@ TTFWidth: 5
 Panose: 2 0 6 3 0 0 0 0 0 0
 LineGap: 90
 VLineGap: 0
-
-Encoding: adobestandard
-DisplaySize: -24
+OS2WinAscent: 0
+OS2WinAOffset: 1
+OS2WinDescent: 0
+OS2WinDOffset: 1
+HheadAscent: 0
+HheadAOffset: 1
+HheadDescent: 0
+HheadDOffset: 1
+Encoding: AdobeStandard
+UnicodeInterp: none
+DisplaySize: -48
 AntiAlias: 1
-BeginChars: 256 95
-StartChar: space
-Encoding: 32 32
-Width: 1000
+FitToEm: 1
+WinInfo: 0 16 4
+BeginChars: 256 5
+StartChar: uniFFFD
+Encoding: 0 65533 65535
+Width: 487
+Flags: HW
+HStem: 87 45<117 414> 342 54<72 363>
+VStem: 72 45<87 342> 363 51<132 396>
+Fore
+117 342 m 1
+ 117 132 l 1
+ 363 132 l 1
+ 363 342 l 1
+ 117 342 l 1
+72 396 m 1
+ 414 396 l 1
+ 414 87 l 1
+ 72 87 l 1
+ 72 396 l 1
+EndSplineSet
 EndChar
 StartChar: exclam
-Encoding: 33 33
+Encoding: 33 33 1
 Width: 310
 Flags: W
 HStem: 0 126<99 163> 180 558<99 147>
@@ -55,56 +81,8 @@ Fore
 EndSplineSet
 MinimumDistance: x2,-1 
 EndChar
-StartChar: quotedbl
-Encoding: 34 34
-Width: 1000
-EndChar
-StartChar: numbersign
-Encoding: 35 35
-Width: 1000
-EndChar
-StartChar: dollar
-Encoding: 36 36
-Width: 1000
-EndChar
-StartChar: percent
-Encoding: 37 37
-Width: 1000
-EndChar
-StartChar: ampersand
-Encoding: 38 38
-Width: 1000
-EndChar
-StartChar: parenleft
-Encoding: 40 40
-Width: 1000
-EndChar
-StartChar: parenright
-Encoding: 41 41
-Width: 1000
-EndChar
-StartChar: asterisk
-Encoding: 42 42
-Width: 1000
-EndChar
-StartChar: plus
-Encoding: 43 43
-Width: 1000
-EndChar
-StartChar: comma
-Encoding: 44 44
-Width: 1000
-EndChar
-StartChar: hyphen
-Encoding: 45 45
-Width: 1000
-EndChar
-StartChar: period
-Encoding: 46 46
-Width: 1000
-EndChar
 StartChar: slash
-Encoding: 47 47
+Encoding: 47 47 14
 Width: 761
 Flags: W
 DStem: 783.882 774.221 818.118 737.779 -59.1182 -17.7793 -24.8818 -54.2207
@@ -116,324 +94,12 @@ Fore
  -59.1182 -17.7793 l 1
 EndSplineSet
 EndChar
-StartChar: zero
-Encoding: 48 48
-Width: 1000
-EndChar
-StartChar: one
-Encoding: 49 49
-Width: 1000
-EndChar
-StartChar: two
-Encoding: 50 50
-Width: 1000
-EndChar
-StartChar: three
-Encoding: 51 51
-Width: 1000
-EndChar
-StartChar: four
-Encoding: 52 52
-Width: 1000
-EndChar
-StartChar: five
-Encoding: 53 53
-Width: 1000
-EndChar
-StartChar: six
-Encoding: 54 54
-Width: 1000
-EndChar
-StartChar: seven
-Encoding: 55 55
-Width: 1000
-EndChar
-StartChar: eight
-Encoding: 56 56
-Width: 1000
-EndChar
-StartChar: nine
-Encoding: 57 57
-Width: 1000
-EndChar
-StartChar: colon
-Encoding: 58 58
-Width: 1000
-EndChar
-StartChar: semicolon
-Encoding: 59 59
-Width: 1000
-EndChar
-StartChar: less
-Encoding: 60 60
-Width: 1000
-EndChar
-StartChar: equal
-Encoding: 61 61
-Width: 1000
-EndChar
-StartChar: greater
-Encoding: 62 62
-Width: 1000
-EndChar
-StartChar: question
-Encoding: 63 63
-Width: 1000
-EndChar
-StartChar: at
-Encoding: 64 64
-Width: 1000
-EndChar
-StartChar: A
-Encoding: 65 65
-Width: 1000
-EndChar
-StartChar: B
-Encoding: 66 66
-Width: 1000
-EndChar
-StartChar: C
-Encoding: 67 67
-Width: 1000
-EndChar
-StartChar: D
-Encoding: 68 68
-Width: 1000
-EndChar
-StartChar: E
-Encoding: 69 69
-Width: 1000
-EndChar
-StartChar: F
-Encoding: 70 70
-Width: 1000
-EndChar
-StartChar: G
-Encoding: 71 71
-Width: 1000
-EndChar
-StartChar: H
-Encoding: 72 72
-Width: 1000
-EndChar
-StartChar: I
-Encoding: 73 73
-Width: 1000
-EndChar
-StartChar: J
-Encoding: 74 74
-Width: 1000
-EndChar
-StartChar: K
-Encoding: 75 75
-Width: 1000
-EndChar
-StartChar: L
-Encoding: 76 76
-Width: 1000
-EndChar
-StartChar: M
-Encoding: 77 77
-Width: 1000
-EndChar
-StartChar: N
-Encoding: 78 78
-Width: 1000
-EndChar
-StartChar: O
-Encoding: 79 79
-Width: 1000
-EndChar
-StartChar: P
-Encoding: 80 80
-Width: 1000
-EndChar
-StartChar: Q
-Encoding: 81 81
-Width: 1000
-EndChar
-StartChar: R
-Encoding: 82 82
-Width: 1000
-EndChar
-StartChar: S
-Encoding: 83 83
-Width: 1000
-EndChar
-StartChar: T
-Encoding: 84 84
-Width: 1000
-EndChar
-StartChar: U
-Encoding: 85 85
-Width: 1000
-EndChar
-StartChar: V
-Encoding: 86 86
-Width: 1000
-EndChar
-StartChar: W
-Encoding: 87 87
-Width: 1000
-EndChar
-StartChar: X
-Encoding: 88 88
-Width: 1000
-EndChar
-StartChar: Y
-Encoding: 89 89
-Width: 1000
-EndChar
-StartChar: Z
-Encoding: 90 90
-Width: 1000
-EndChar
-StartChar: bracketleft
-Encoding: 91 91
-Width: 1000
-EndChar
-StartChar: backslash
-Encoding: 92 92
-Width: 1000
-EndChar
-StartChar: bracketright
-Encoding: 93 93
-Width: 1000
-EndChar
-StartChar: asciicircum
-Encoding: 94 94
-Width: 1000
-EndChar
-StartChar: underscore
-Encoding: 95 95
-Width: 1000
-EndChar
-StartChar: a
-Encoding: 97 97
-Width: 1000
-EndChar
-StartChar: b
-Encoding: 98 98
-Width: 1000
-EndChar
-StartChar: c
-Encoding: 99 99
-Width: 1000
-EndChar
-StartChar: d
-Encoding: 100 100
-Width: 1000
-EndChar
-StartChar: e
-Encoding: 101 101
-Width: 1000
-EndChar
-StartChar: f
-Encoding: 102 102
-Width: 1000
-EndChar
-StartChar: g
-Encoding: 103 103
-Width: 1000
-EndChar
-StartChar: h
-Encoding: 104 104
-Width: 1000
-EndChar
-StartChar: i
-Encoding: 105 105
-Width: 1000
-EndChar
-StartChar: j
-Encoding: 106 106
-Width: 1000
-EndChar
-StartChar: k
-Encoding: 107 107
-Width: 1000
-EndChar
-StartChar: l
-Encoding: 108 108
-Width: 1000
-EndChar
-StartChar: m
-Encoding: 109 109
-Width: 1000
-EndChar
-StartChar: n
-Encoding: 110 110
-Width: 1000
-EndChar
-StartChar: o
-Encoding: 111 111
-Width: 1000
-EndChar
-StartChar: p
-Encoding: 112 112
-Width: 1000
-EndChar
-StartChar: q
-Encoding: 113 113
-Width: 1000
-EndChar
-StartChar: r
-Encoding: 114 114
-Width: 1000
-EndChar
-StartChar: s
-Encoding: 115 115
-Width: 1000
-EndChar
-StartChar: t
-Encoding: 116 116
-Width: 1000
-EndChar
-StartChar: u
-Encoding: 117 117
-Width: 1000
-EndChar
-StartChar: v
-Encoding: 118 118
-Width: 1000
-EndChar
-StartChar: w
-Encoding: 119 119
-Width: 1000
-EndChar
-StartChar: x
-Encoding: 120 120
-Width: 1000
-EndChar
-StartChar: y
-Encoding: 121 121
-Width: 1000
-EndChar
-StartChar: z
-Encoding: 122 122
-Width: 1000
-EndChar
-StartChar: braceleft
-Encoding: 123 123
-Width: 1000
-EndChar
-StartChar: bar
-Encoding: 124 124
-Width: 1000
-EndChar
-StartChar: braceright
-Encoding: 125 125
-Width: 1000
-EndChar
-StartChar: asciitilde
-Encoding: 126 126
-Width: 1000
-EndChar
 StartChar: quotesingle
-Encoding: 169 39
+Encoding: 169 39 93
 Width: 1000
 EndChar
 StartChar: grave
-Encoding: 193 96
+Encoding: 193 96 94
 Width: 1000
 EndChar
 EndChars
diff --git a/fontfiles/SpaceTest.afm b/fontfiles/SpaceTest.afm
new file mode 100644 (file)
index 0000000..bdac656
--- /dev/null
@@ -0,0 +1,21 @@
+StartFontMetrics 2.0
+Comment Generated by pfaedit
+Comment Creation Date: Thu Jul 20 21:51:08 2006
+FontName SpaceTest
+FullName SpaceTest
+FamilyName SpaceTest
+Weight Medium
+Notice (Created by Tony Cook,,, with FontForge 1.0 (http://fontforge.sf.net))
+ItalicAngle 0
+IsFixedPitch false
+UnderlinePosition -100
+UnderlineThickness 50
+Version 001.000
+EncodingScheme AdobeStandardEncoding
+FontBBox 72 -24 414 684
+StartCharMetrics 3
+C 0 ; WX 487 ; N uniFFFD ; B 72 87 414 396 ;
+C 32 ; WX 500 ; N space ; B 0 0 0 0 ;
+C 33 ; WX 451 ; N exclam ; B 156 -24 312 684 ;
+EndCharMetrics
+EndFontMetrics
diff --git a/fontfiles/SpaceTest.pfb b/fontfiles/SpaceTest.pfb
new file mode 100644 (file)
index 0000000..38cdc89
Binary files /dev/null and b/fontfiles/SpaceTest.pfb differ
diff --git a/fontfiles/SpaceTest.sfd b/fontfiles/SpaceTest.sfd
new file mode 100644 (file)
index 0000000..abeea3a
--- /dev/null
@@ -0,0 +1,80 @@
+SplineFontDB: 1.0
+FontName: SpaceTest
+FullName: SpaceTest
+FamilyName: SpaceTest
+Weight: Medium
+Copyright: Created by Tony Cook,,, with FontForge 1.0 (http://fontforge.sf.net)
+Comments: 2006-7-20: Created.
+Version: 001.000
+ItalicAngle: 0
+UnderlinePosition: -100
+UnderlineWidth: 50
+Ascent: 800
+Descent: 200
+NeedsXUIDChange: 1
+XUID: [1021 918 1786090884 13370659]
+FSType: 8
+PfmFamily: 17
+TTFWeight: 500
+TTFWidth: 5
+Panose: 2 0 6 3 0 0 0 0 0 0
+LineGap: 90
+VLineGap: 0
+OS2WinAscent: 0
+OS2WinAOffset: 1
+OS2WinDescent: 0
+OS2WinDOffset: 1
+HheadAscent: 0
+HheadAOffset: 1
+HheadDescent: 0
+HheadDOffset: 1
+Encoding: AdobeStandard
+UnicodeInterp: none
+DisplaySize: -48
+AntiAlias: 1
+FitToEm: 1
+WinInfo: 0 16 4
+BeginChars: 256 3
+StartChar: uniFFFD
+Encoding: 0 65533 65535
+Width: 487
+Flags: HW
+Fore
+117 342 m 1
+ 117 132 l 1
+ 363 132 l 1
+ 363 342 l 1
+ 117 342 l 1
+72 396 m 1
+ 414 396 l 1
+ 414 87 l 1
+ 72 87 l 1
+ 72 396 l 1
+EndSplineSet
+EndChar
+StartChar: space
+Encoding: 32 32 65535
+Width: 500
+Flags: W
+EndChar
+StartChar: exclam
+Encoding: 33 33 65535
+Width: 451
+Flags: WO
+HStem: -24 156<221.497 237>
+VStem: 183 102<177 684>
+Fore
+156 54 m 0
+ 156 97.056 190.944 132 234 132 c 0
+ 277.056 132 312 97.056 312 54 c 0
+ 312 10.944 277.056 -24 234 -24 c 0
+ 190.944 -24 156 10.944 156 54 c 0
+183 684 m 1
+ 285 684 l 1
+ 285 177 l 1
+ 183 177 l 1
+ 183 684 l 1
+EndSplineSet
+EndChar
+EndChars
+EndSplineFont
index 9d8a010..4331e64 100644 (file)
@@ -8,7 +8,7 @@
 # (It may become useful if the test is moved to ./t subdirectory.)
 use strict;
 use lib 't';
-use Test::More tests => 64;
+use Test::More tests => 76;
 BEGIN { use_ok(Imager => ':all') }
 
 #$Imager::DEBUG=1;
@@ -23,13 +23,13 @@ my $fontname_afm=$ENV{'T1FONTTESTAFM'}||'./fontfiles/dcr10.afm';
 SKIP:
 {
   if (!(i_has_format("t1")) ) {
-    skip("t1lib unavailable or disabled", 63);
+    skip("t1lib unavailable or disabled", 75);
   }
   elsif (! -f $fontname_pfb) {
-    skip("cannot find fontfile for type 1 test $fontname_pfb", 63);
+    skip("cannot find fontfile for type 1 test $fontname_pfb", 75);
   }
   elsif (! -f $fontname_afm) {
-    skip("cannot find fontfile for type 1 test $fontname_afm", 63);
+    skip("cannot find fontfile for type 1 test $fontname_afm", 75);
   }
 
   print "# has t1\n";
@@ -252,6 +252,46 @@ SKIP:
     }
     ok($im->write(file=>'testout/t30align.ppm'), "save align image");
   }
+
+ SKIP:
+  {
+    # see http://rt.cpan.org/Ticket/Display.html?id=20555
+    print "# bounding box around spaces\n";
+    # SpaceTest contains 3 characters, space, ! and .undef
+    # only characters that define character zero seem to illustrate
+    # the problem we had with spaces
+    my $space_fontfile = "fontfiles/SpaceTest.pfb";
+    my $font = Imager::Font->new(file => $space_fontfile, type => 't1');
+    ok($font, "loaded $deffont")
+      or skip("failed to load $deffont" . Imager->errstr, 13);
+    my $bbox = $font->bounding_box(string => "", size => 36);
+    print "# empty string bbox: @$bbox\n";
+    is($bbox->start_offset, 0, "empty string start_offset");
+    is($bbox->end_offset, 0, "empty string end_offset");
+    is($bbox->advance_width, 0, "empty string advance_width");
+    is($bbox->ascent, 0, "empty string ascent");
+    is($bbox->descent, 0, "empty string descent");
+
+    # a single space
+    my $bbox_space = $font->bounding_box(string => " ", size => 36);
+    print "# space bbox: @$bbox_space\n";
+    is($bbox_space->start_offset, 0, "single space start_offset");
+    is($bbox_space->end_offset, $bbox_space->advance_width, 
+       "single space end_offset");
+    cmp_ok($bbox_space->ascent, '>=', $bbox_space->descent,
+          "single space ascent/descent");
+
+    my $bbox_bang = $font->bounding_box(string => "!", size => 36);
+    print "# '!' bbox: @$bbox_bang\n";
+
+    # space ! space
+    my $bbox_spbangsp = $font->bounding_box(string => " ! ", size => 36);
+    print "# ' ! ' bbox: @$bbox_spbangsp\n";
+    my $exp_advance = $bbox_bang->advance_width + 2 * $bbox_space->advance_width;
+    is($bbox_spbangsp->advance_width, $exp_advance, "sp ! sp advance_width");
+    is($bbox_spbangsp->start_offset, 0, "sp ! sp start_offset");
+    is($bbox_spbangsp->end_offset, $exp_advance, "sp ! sp end_offset");
+  }
 }
 
 #malloc_state();