handle failure to clone the log filehandle when cloning the Imager context
[imager.git] / FT2 / FT2.pm
CommitLineData
50c75381
TC
1package Imager::Font::FT2;
2use strict;
3use Imager;
98d6ae27 4use Scalar::Util ();
50c75381
TC
5use vars qw($VERSION @ISA);
6@ISA = qw(Imager::Font);
7
8BEGIN {
4eb9a521 9 $VERSION = "0.96";
50c75381 10
a5919365
TC
11 require XSLoader;
12 XSLoader::load('Imager::Font::FT2', $VERSION);
50c75381
TC
13}
14
15*_first = \&Imager::Font::_first;
16
17sub new {
18 my $class = shift;
61e5a61a 19 my %hsh=(color=>Imager::Color->new(255,0,0,255),
50c75381
TC
20 size=>15,
21 @_);
22
23 unless ($hsh{file}) {
24 $Imager::ERRSTR = "No font file specified";
25 return;
26 }
27 unless (-e $hsh{file}) {
28 $Imager::ERRSTR = "Font file $hsh{file} not found";
29 return;
30 }
31 unless ($Imager::formats{ft2}) {
32 $Imager::ERRSTR = "Freetype2 not supported in this build";
33 return;
34 }
35 my $id = i_ft2_new($hsh{file}, $hsh{'index'} || 0);
36 unless ($id) { # the low-level code may miss some error handling
37 $Imager::ERRSTR = Imager::_error_as_msg();
38 return;
39 }
40 return bless {
41 id => $id,
42 aa => $hsh{aa} || 0,
43 file => $hsh{file},
44 type => 't1',
45 size => $hsh{size},
46 color => $hsh{color},
47 utf8 => $hsh{utf8},
48 vlayout => $hsh{vlayout},
49 }, $class;
50}
51
52sub _draw {
53 my $self = shift;
98d6ae27
TC
54
55 $self->_valid
56 or return;
57
50c75381
TC
58 my %input = @_;
59 if (exists $input{channel}) {
60 i_ft2_cp($self->{id}, $input{image}{IMG}, $input{'x'}, $input{'y'},
61 $input{channel}, $input{size}, $input{sizew} || 0,
62 $input{string}, , $input{align}, $input{aa}, $input{vlayout},
63 $input{utf8});
64 } else {
65 i_ft2_text($self->{id}, $input{image}{IMG},
66 $input{'x'}, $input{'y'},
67 $input{color}, $input{size}, $input{sizew} || 0,
68 $input{string}, $input{align}, $input{aa}, $input{vlayout},
69 $input{utf8});
70 }
71}
72
73sub _bounding_box {
74 my $self = shift;
75 my %input = @_;
76
98d6ae27
TC
77 $self->_valid
78 or return;
79
d6f02a59
TC
80 my @result = i_ft2_bbox($self->{id}, $input{size}, $input{sizew},
81 $input{string}, $input{utf8});
82 unless (@result) {
83 Imager->_set_error(Imager->_error_as_msg);
84 return;
85 }
86
87 return @result;
50c75381
TC
88}
89
90sub dpi {
91 my $self = shift;
98d6ae27
TC
92
93 $self->_valid
94 or return;
95
50c75381
TC
96 my @old = i_ft2_getdpi($self->{id});
97 if (@_) {
98 my %hsh = @_;
99 my $result;
100 unless ($hsh{xdpi} && $hsh{ydpi}) {
101 if ($hsh{dpi}) {
102 $hsh{xdpi} = $hsh{ydpi} = $hsh{dpi};
103 }
104 else {
105 $Imager::ERRSTR = "dpi method requires xdpi and ydpi or just dpi";
106 return;
107 }
108 i_ft2_setdpi($self->{id}, $hsh{xdpi}, $hsh{ydpi}) or return;
109 }
110 }
111
112 return @old;
113}
114
115sub hinting {
116 my ($self, %opts) = @_;
117
98d6ae27
TC
118 $self->_valid
119 or return;
120
50c75381
TC
121 i_ft2_sethinting($self->{id}, $opts{hinting} || 0);
122}
123
124sub _transform {
125 my $self = shift;
126
98d6ae27
TC
127 $self->_valid
128 or return;
129
50c75381
TC
130 my %hsh = @_;
131 my $matrix = $hsh{matrix} or return undef;
132
133 return i_ft2_settransform($self->{id}, $matrix)
134}
135
136sub utf8 {
137 return 1;
138}
139
140# check if the font has the characters in the given string
141sub has_chars {
142 my ($self, %hsh) = @_;
143
98d6ae27
TC
144 $self->_valid
145 or return;
146
50c75381
TC
147 unless (defined $hsh{string} && length $hsh{string}) {
148 $Imager::ERRSTR = "No string supplied to \$font->has_chars()";
149 return;
150 }
d6f02a59
TC
151 if (wantarray) {
152 my @result = i_ft2_has_chars($self->{id}, $hsh{string},
153 _first($hsh{'utf8'}, $self->{utf8}, 0));
154 unless (@result) {
155 Imager->_set_error(Imager->_error_as_msg);
156 return;
157 }
158
159 return @result;
160 }
161 else {
162 my $result = i_ft2_has_chars($self->{id}, $hsh{string},
163 _first($hsh{'utf8'}, $self->{utf8}, 0));
164 unless (defined $result) {
165 Imager->_set_error(Imager->_error_as_msg);
166 return;
167 }
168 return $result;
169 }
50c75381
TC
170}
171
172sub face_name {
173 my ($self) = @_;
174
98d6ae27
TC
175 $self->_valid
176 or return;
177
50c75381
TC
178 i_ft2_face_name($self->{id});
179}
180
181sub can_glyph_names {
d6f02a59
TC
182 my ($self) = @_;
183
184 i_ft2_can_do_glyph_names()
185 or return;
186
187 if (ref $self) {
188 $self->_valid
189 or return;
190
191 i_ft2_face_has_glyph_names($self->{id})
192 or return;
193 }
194
195 return 1;
50c75381
TC
196}
197
198sub glyph_names {
199 my ($self, %input) = @_;
200
98d6ae27
TC
201 $self->_valid
202 or return;
203
50c75381
TC
204 my $string = $input{string};
205 defined $string
206 or return Imager->_set_error("no string parameter passed to glyph_names");
207 my $utf8 = _first($input{utf8}, 0);
208 my $reliable_only = _first($input{reliable_only}, 1);
209
210 my @names = i_ft2_glyph_name($self->{id}, $string, $utf8, $reliable_only);
211 @names or return Imager->_set_error(Imager->_error_as_msg);
212
213 return @names if wantarray;
214 return pop @names;
215}
216
217sub is_mm {
218 my ($self) = @_;
219
98d6ae27
TC
220 $self->_valid
221 or return;
222
50c75381
TC
223 i_ft2_is_multiple_master($self->{id});
224}
225
226sub mm_axes {
227 my ($self) = @_;
228
98d6ae27
TC
229 $self->_valid
230 or return;
231
50c75381
TC
232 my ($num_axis, $num_design, @axes) =
233 i_ft2_get_multiple_masters($self->{id})
234 or return Imager->_set_error(Imager->_error_as_msg);
235
236 return @axes;
237}
238
239sub set_mm_coords {
240 my ($self, %opts) = @_;
241
98d6ae27
TC
242 $self->_valid
243 or return;
244
50c75381
TC
245 $opts{coords}
246 or return Imager->_set_error("Missing coords parameter");
247 ref($opts{coords}) && $opts{coords} =~ /ARRAY\(0x[\da-f]+\)$/
248 or return Imager->_set_error("coords parameter must be an ARRAY ref");
249
250 i_ft2_set_mm_coords($self->{id}, @{$opts{coords}})
251 or return Imager->_set_error(Imager->_error_as_msg);
252
253 return 1;
254}
98d6ae27
TC
255
256# objects may be invalidated on thread creation (or Win32 fork emulation)
257sub _valid {
258 my $self = shift;
259
260 unless ($self->{id} && Scalar::Util::blessed($self->{id})) {
261 Imager->_set_error("font object was created in another thread");
262 return;
263 }
264
265 return 1;
266}
267
50c75381
TC
2681;
269
270__END__
271
272=head1 NAME
273
274Imager::Font::FT2 - font support using FreeType 2
275
276=head1 SYNOPSIS
277
278 use Imager;
279
280 my $img = Imager->new;
281 my $font = Imager::Font->new(file => "foo.ttf", type => "ft2");
282
283 $img->string(... font => $font);
284
285=head1 DESCRIPTION
286
287This provides font support on FreeType 2.
288
289=head1 CAVEATS
290
291Unfortunately, older versions of Imager would install
292C<Imager::Font::FreeType2> even if FreeType 2 wasn't available, and if
293no font was created would succeed in loading the module. This means
294that an existing C<FreeType2.pm> could cause a probe success for
295supported font files, so I've renamed it.
296
297=head1 AUTHOR
298
5b480b14 299Tony Cook <tonyc@cpan.org>
50c75381
TC
300
301=head1 SEE ALSO
302
303Imager, Imager::Font.
304
305=cut