- the changes to scale() had some problems with integer vs floating point
calculations (only caught in tests under perl 5.8.5 <sigh>)
+- the FT2 glyph_names() method didn't do correct error handling
+ when the string parameter wasn't supplied
+- i_ft2_glyph_name() accepted only an unsigned char as the
+ character code to get the name for, which meant it
+ didn't work for unicode characters \x{100} or above
+- the XS for i_ft2_glyph_name() had a similar problem
+- added NameTest.ttf to be used in checking unicode glyph
+ names
+- added reliable_only optional parameter to the glyph_names()
+ method so you can ignore theresult of FT_Has_PS_Glyph_Names()
+- partly resolves https://rt.cpan.org/Ticket/Display.html?id=7949
+- handle errors given by i_ft2_glyph_name() a bit more
+ correctly
+- the FT1 glyph_names() method didn't do correct error handling
+ when the string parameter wasn't supplied
+- some memory allocated when creating a callback IO object (io_new_cb)
+ wasn't being released (detected with valgrind)
+- the testtools.pl match[nx]() functions escapes the test string on
+ test failure a bit better
=================================================================
For latest versions check the Imager-devel pages:
- http://imager.perl.org/~addi/perl/Imager/
+ http://imager.perl.org/
=================================================================
SvREFCNT_dec(cbd->readcb);
SvREFCNT_dec(cbd->seekcb);
SvREFCNT_dec(cbd->closecb);
+ myfree(cbd);
}
struct value_name {
i_ft2_can_face_name()
void
-i_ft2_glyph_name(handle, text_sv, utf8 = 0)
+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;
text = SvPV(text_sv, work_len);
len = work_len;
while (len) {
- unsigned char ch;
+ unsigned long ch;
if (utf8) {
ch = i_utf8_advance(&text, &len);
if (ch == ~0UL) {
--len;
}
EXTEND(SP, 1);
- if (outsize = i_ft2_glyph_name(handle, ch, name, sizeof(name))) {
+ if (outsize = i_ft2_glyph_name(handle, ch, name, sizeof(name),
+ reliable_only)) {
PUSHs(sv_2mortal(newSVpv(name, 0)));
}
else {
fontfiles/ExistenceTest.pfb to change these files, edited and
fontfiles/ExistenceTest.ttf generated using pfaedit
fontfiles/ImUgly.ttf
+fontfiles/NameTest.ttf test glyph_names() - see t38ft2font.t
fontfiles/dcr10.afm
fontfiles/dcr10.pfb
fontfiles/dodge.ttf
--- /dev/null
+SplineFontDB: 1.0
+FontName: NameTest
+FullName: NameTest
+FamilyName: NameTest
+Weight: Medium
+Copyright: Created by Tony Cook - test font for the glyph_names() method
+Comments: 2004-10-13: Created.
+Version: 001.000
+ItalicAngle: 0
+UnderlinePosition: -100
+UnderlineWidth: 50
+Ascent: 800
+Descent: 200
+XUID: [1021 123 2012976297 155577]
+FSType: 0
+OS2WinAscent: 0
+OS2WinAOffset: 1
+OS2WinDescent: 0
+OS2WinDOffset: 1
+HheadAscent: 0
+HheadAOffset: 0
+HheadDescent: 0
+HheadDOffset: 0
+ScriptLang: 1
+ 1 latn 1 dflt
+TtfTable: cvt 4
+!$MDh
+EndTtf
+Encoding: Custom
+UnicodeInterp: none
+DisplaySize: -24
+AntiAlias: 1
+FitToEm: 1
+WinInfo: 0 21 12
+BeginChars: 65536 2
+StartChar: exclam
+Encoding: 33 33 65535
+Width: 295
+Flags: W
+HStem: 30 60<141 143>
+Fore
+111 60 m 0
+ 111 76.5596 124.44 90 141 90 c 0
+ 157.56 90 171 76.5596 171 60 c 0
+ 171 43.4404 157.56 30 141 30 c 0
+ 124.44 30 111 43.4404 111 60 c 0
+165 171 m 2
+ 165 157.2 153.8 146 140 146 c 0
+ 126.2 146 115 157.2 115 171 c 0
+ 115 228.6 115 728.006 115 747 c 0
+ 115 760.8 126.2 772 140 772 c 0
+ 153.8 772 165 760.8 165 747 c 2
+ 165 171 l 2
+EndSplineSet
+EndChar
+StartChar: hyphentwo
+Encoding: 8208 8208 65535
+Width: 487
+Flags: W
+HStem: 308 50<114 378>
+Fore
+372 358 m 2
+ 385.8 358 397 346.8 397 333 c 0
+ 397 319.2 385.8 308 372 308 c 0
+ 346.2 308 122.395 308 114 308 c 0
+ 100.2 308 89 319.2 89 333 c 0
+ 89 346.8 100.2 358 114 358 c 2
+ 372 358 l 2
+EndSplineSet
+EndChar
+EndChars
+EndSplineFont
#endif
int
-i_ft2_glyph_name(FT2_Fonthandle *handle, unsigned char ch, char *name_buf,
- size_t name_buf_size) {
+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';
return 0;
#else
+ FT_UInt index;
+
i_clear_error();
- if (FT_Has_PS_Glyph_Names(handle->face)) {
- FT_UInt index = FT_Get_Char_Index(handle->face, ch);
+ 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;
+ }
- 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;
- }
- if (*name_buf) {
- return strlen(name_buf) + 1;
- }
- else {
- 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;
+ }
+ if (*name_buf) {
+ return strlen(name_buf) + 1;
}
else {
- i_push_error(0, "no glyph for that character");
- *name_buf = 0;
return 0;
}
}
else {
- i_push_error(0, "no glyph names in font");
- *name_buf = '\0';
+ i_push_error(0, "no glyph for that character");
+ *name_buf = 0;
return 0;
}
#endif
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 char ch,
- char *name_buf, size_t name_buf_size);
+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);
Returns the internal name of the face. Not all font types support
this method yet.
-=item glyph_names(string=>$string [, utf8=>$utf8 ] );
+=item glyph_names(string=>$string [, utf8=>$utf8 ][, reliable_only=>0 ] );
Returns a list of glyph names for each of the characters in the
string. If the character has no name then C<undef> is returned for
will not return any names. Freetype 1 can return standard names even
if there are no glyph names in the font.
+Freetype 2 has an API function that returns true only if the font has
+"reliable glyph names", unfortunately this always returns false for
+TTF fonts. This can avoid the check of this API by supplying
+C<reliable_only> as 0. The consequences of using this on an unknown
+font may be unpredictable, since the Freetype documentation doesn't
+say how those name tables are unreliable, or how FT2 handles them.
+
Both Freetype 1.x and 2.x allow support for glyph names to not be
included.
my $string = $input{string};
defined $string
- or return Imager->_seterror("no string parameter passed to glyph_names");
- my $utf8 = _first($input{utf8} || 0);
+ 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);
- i_ft2_glyph_name($self->{id}, $string, $utf8);
+ 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;
}
1;
my $string = $input{string};
defined $string
- or return Imager->_seterror("no string parameter passed to glyph_names");
+ or return Imager->_set_error("no string parameter passed to glyph_names");
my $utf8 = _first($input{utf8} || 0);
Imager::i_tt_glyph_name($self->{id}, $string, $utf8);
# Change 1..1 below to 1..last_test_to_print .
# (It may become useful if the test is moved to ./t subdirectory.)
-BEGIN { $| = 1; print "1..116\n"; }
+BEGIN { $| = 1; print "1..120\n"; }
END {print "not ok 1\n" unless $loaded;}
use Imager qw(:all);
}
if (Imager::Font::FreeType2->can_glyph_names) {
- # pfaedit doesn't seem to save glyph names into TTF files
+ # 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');
if (okx($exfont, "load Type 1 via FT2")) {
Imager::Font::FreeType2::i_ft2_glyph_name($exfont->{id}, "!J/");
#use Data::Dumper;
#print Dumper \@glyph_names;
- okx($glyph_names[0] eq 'exclam', "check exclam name");
+ isx($glyph_names[0], 'exclam', "check exclam name");
okx(!defined($glyph_names[1]), "check for no J name");
- okx($glyph_names[2] eq 'slash', "check slash name");
+ isx($glyph_names[2], 'slash', "check slash name");
# oo interfaces
@glyph_names = $exfont->glyph_names(string=>"!J/");
- okx($glyph_names[0] eq 'exclam', "check exclam name OO");
+ isx($glyph_names[0], 'exclam', "check exclam name OO");
okx(!defined($glyph_names[1]), "check for no J name OO");
- okx($glyph_names[2] eq 'slash', "check slash name OO");
+ isx($glyph_names[2], 'slash', "check slash name OO");
+
+ # make sure a missing string parameter is handled correctly
+ eval {
+ $exfont->glyph_names();
+ };
+ isx($@, "", "correct error handling");
+ matchx(Imager->errstr, qr/no string parameter/, "error message");
}
else {
- skipx(6, "couldn't load type 1 with FT2");
+ skipx(8, "couldn't load type 1 with FT2");
+ }
+
+ # 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');
+ if (okx($exfont, "load TTF via FT2")) {
+ my $text = pack("C*", 0xE2, 0x80, 0x90); # "\x{2010}" as utf-8
+ my @names = $exfont->glyph_names(string=>$text,
+ utf8=>1, reliable_only=>0);
+ isx($names[0], "hyphentwo", "check utf8 glyph name");
+ }
+ else {
+ skipx(1, "could not load TTF with FT2");
}
}
else {
- skipx(7, "FT2 compiled without glyph names support");
+ skipx(9, "FT2 compiled without glyph names support");
}
sub align_test {
sub matchn($$$$) {
my ($num, $str, $re, $comment) = @_;
- my $match = $str =~ $re;
+ my $match = defined($str) && $str =~ $re;
okn($num, $match, $comment);
unless ($match) {
- $str =~ s/\\/\\\\/g;
- $str =~ s/[^\x20-\x7E]/"\\x".sprintf("%02X", ord($1))/ge;
- print "# The string '$str'\n";
- print "# did not match '$re'\n";
+ print "# The value: ",_sv_str($str),"\n";
+ print "# did not match: qr/$re/\n";
}
return $match;
}