line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Font::TTF::Glyph; |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
=head1 NAME |
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
Font::TTF::Glyph - Holds a information for a single glyph |
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
=head1 DESCRIPTION |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
This is a single glyph description as held in a TT font. On creation only its |
10
|
|
|
|
|
|
|
header is read. Thus you can get the bounding box of each glyph without having |
11
|
|
|
|
|
|
|
to read all the other information. |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
=head1 INSTANCE VARIABLES |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
In addition to the named variables in a glyph header (C etc.), there are |
16
|
|
|
|
|
|
|
also all capital instance variables for holding working information, mostly |
17
|
|
|
|
|
|
|
from the location table. |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
=head2 Variables for all glyphs: |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
The standard attributes each glyph has are: |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
=over 4 |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
=item numberOfContours |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
For simple glyphs this will be the count of contours. For compound glyphs this will be -1. |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
=item xMin |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
=item yMin |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
=item xMax |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
=item yMax |
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
These identify the bounding box of the glyph. |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
=back |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
There are also other, derived, instance variables for each glyph which are read |
42
|
|
|
|
|
|
|
when the whole glyph is read (via C): |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
=over 4 |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
=item instLen |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
Number of bytes in the hinting instructions (Warning this variable is deprecated, |
49
|
|
|
|
|
|
|
use C{'hints'})> instead). |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
=item hints |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
The string containing the hinting code for the glyph |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
=back |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
=head2 Variables for simple glyphs (numberOfContours E= 0): |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
=over 4 |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
=item endPoints |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
An array of endpoints for each contour in the glyph. There are |
64
|
|
|
|
|
|
|
C contours in a glyph. The number of points in a glyph is |
65
|
|
|
|
|
|
|
equal to the highest endpoint of a contour. |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
=item numPoints |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
This is a generated value which contains the total number of points for this simple glyph. |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
=back |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
There are also a number of arrays indexed by point number: |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
=over 4 |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
=item flags |
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
The flags associated with reading this point. The flags for a point are |
80
|
|
|
|
|
|
|
recalculated for a point when it is Cd. Thus the flags are not very |
81
|
|
|
|
|
|
|
useful. The only important bit is bit 0 which indicates whether the point is |
82
|
|
|
|
|
|
|
an 'on' curve point, or an 'off' curve point. |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
=item x |
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
The absolute x co-ordinate of the point. |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
=item y |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
The absolute y co-ordinate of the point |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
=back |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
=head2 Variables for compound glyphs (numberOfContours == -1): |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
=over 4 |
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
=item metric |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
This holds the component number (not its glyph number) of the component from |
101
|
|
|
|
|
|
|
which the metrics for this glyph should be taken. |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
=item comps |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
This is an array of hashes for each component. Each hash has a number of |
106
|
|
|
|
|
|
|
elements: |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
=over 4 |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
=item glyph |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
The glyph number of the glyph which comprises this component of the composite. |
113
|
|
|
|
|
|
|
NOTE: In some badly generated fonts, C may contain a numerical value |
114
|
|
|
|
|
|
|
but that glyph might not actually exist in the font file. This could |
115
|
|
|
|
|
|
|
occur in any glyph, but is particularly likely for glyphs that have |
116
|
|
|
|
|
|
|
no strokes, such as SPACE, U+00A0 NO-BREAK SPACE, or |
117
|
|
|
|
|
|
|
U+200B ZERO WIDTH SPACE. |
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
=item args |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
An array of two arguments which may be an x, y co-ordinate or two attachment |
122
|
|
|
|
|
|
|
points (one on the base glyph the other on the component). See flags for details. |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
=item flag |
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
The flag for this component |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
=item scale |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
A 4 number array for component scaling. This allows stretching, rotating, etc. |
131
|
|
|
|
|
|
|
Note that scaling applies to placement co-ordinates (rather than attachment points) |
132
|
|
|
|
|
|
|
before locating rather than after. |
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
=back |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
=item numPoints |
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
This is a generated value which contains the number of components read in for this |
139
|
|
|
|
|
|
|
compound glyph. |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
=back |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
=head2 Private instance variables: |
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
=over 4 |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
=item INFILE (P) |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
The input file form which to read any information |
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
=item LOC (P) |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
Location relative to the start of the glyf table in the read file |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
=item BASE (P) |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
The location of the glyf table in the read file |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
=item LEN (P) |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
This is the number of bytes required by the glyph. It should be kept up to date |
162
|
|
|
|
|
|
|
by calling the C method whenever any of the glyph content changes. |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
=item OUTLOC (P) |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
Location relative to the start of the glyf table. This variable is only active |
167
|
|
|
|
|
|
|
whilst the output process is going on. It is used to inform the location table |
168
|
|
|
|
|
|
|
where the glyph is located, since the glyf table is output before the loca |
169
|
|
|
|
|
|
|
table due to alphabetical ordering. |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
=item OUTLEN (P) |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
This indicates the length of the glyph data when it is output. This more |
174
|
|
|
|
|
|
|
accurately reflects the internal memory form than the C variable which |
175
|
|
|
|
|
|
|
only reflects the read file length. The C variable is only set after |
176
|
|
|
|
|
|
|
calling C or C. |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
=back |
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
=head2 Editing |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
If you want to edit a glyph in some way, then you should read_dat the glyph, then |
183
|
|
|
|
|
|
|
make your changes and then update the glyph or set the $g->{' isDirty'} variable. |
184
|
|
|
|
|
|
|
The application must ensure that the following instance variables are |
185
|
|
|
|
|
|
|
correct, from which update will calculate the rest, including the bounding box |
186
|
|
|
|
|
|
|
information. |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
numPoints |
189
|
|
|
|
|
|
|
numberOfContours |
190
|
|
|
|
|
|
|
endPoints |
191
|
|
|
|
|
|
|
x, y, flags (only flags bit 0) |
192
|
|
|
|
|
|
|
instLen |
193
|
|
|
|
|
|
|
hints |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
For components, the numPoints, x, y, endPoints & flags are not required but |
196
|
|
|
|
|
|
|
the following information is required for each component. |
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
flag (bits 2, 10, 11, 12) |
199
|
|
|
|
|
|
|
glyph |
200
|
|
|
|
|
|
|
args |
201
|
|
|
|
|
|
|
scale |
202
|
|
|
|
|
|
|
metric (glyph instance variable) |
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
=head1 METHODS |
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
=cut |
208
|
|
|
|
|
|
|
|
209
|
1
|
|
|
1
|
|
4
|
use strict; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
32
|
|
210
|
1
|
|
|
1
|
|
4
|
use vars qw(%fields @field_info); |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
39
|
|
211
|
1
|
|
|
1
|
|
5
|
use Font::TTF::Utils; |
|
1
|
|
|
|
|
0
|
|
|
1
|
|
|
|
|
75
|
|
212
|
1
|
|
|
1
|
|
5
|
use Font::TTF::Table; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
2907
|
|
213
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
@field_info = ( |
215
|
|
|
|
|
|
|
'numberOfContours' => 's', |
216
|
|
|
|
|
|
|
'xMin' => 's', |
217
|
|
|
|
|
|
|
'yMin' => 's', |
218
|
|
|
|
|
|
|
'xMax' => 's', |
219
|
|
|
|
|
|
|
'yMax' => 's'); |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
sub init |
222
|
|
|
|
|
|
|
{ |
223
|
1
|
|
|
1
|
0
|
1
|
my ($k, $v, $c, $i); |
224
|
1
|
|
|
|
|
5
|
for ($i = 0; $i < $#field_info; $i += 2) |
225
|
|
|
|
|
|
|
{ |
226
|
5
|
|
|
|
|
11
|
($k, $v, $c) = TTF_Init_Fields($field_info[$i], $c, $field_info[$i + 1]); |
227
|
5
|
50
|
33
|
|
|
17
|
next unless defined $k && $k ne ""; |
228
|
5
|
|
|
|
|
14
|
$fields{$k} = $v; |
229
|
|
|
|
|
|
|
} |
230
|
|
|
|
|
|
|
} |
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
=head1 Font::TTF::Glyph->new(%parms) |
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
Creates a new glyph setting various instance variables |
236
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
=cut |
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
sub new |
240
|
|
|
|
|
|
|
{ |
241
|
188
|
|
|
188
|
0
|
578
|
my ($class, %parms) = @_; |
242
|
188
|
|
|
|
|
202
|
my ($self) = {}; |
243
|
188
|
|
|
|
|
145
|
my ($p); |
244
|
|
|
|
|
|
|
|
245
|
188
|
|
|
|
|
267
|
bless $self, $class; |
246
|
188
|
|
|
|
|
338
|
foreach $p (keys %parms) |
247
|
1316
|
|
|
|
|
1854
|
{ $self->{" $p"} = $parms{$p}; } |
248
|
188
|
100
|
|
|
|
427
|
init unless defined $fields{'xMin'}; |
249
|
188
|
|
|
|
|
594
|
$self; |
250
|
|
|
|
|
|
|
} |
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
=head2 $g->read |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
Reads the header component of the glyph (numberOfContours and bounding box) and also the |
256
|
|
|
|
|
|
|
glyph content, but into a data field rather than breaking it down into |
257
|
|
|
|
|
|
|
its constituent structures. Use read_dat for this. |
258
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
=cut |
260
|
|
|
|
|
|
|
|
261
|
|
|
|
|
|
|
sub read |
262
|
|
|
|
|
|
|
{ |
263
|
188
|
|
|
188
|
1
|
209
|
my ($self) = @_; |
264
|
188
|
|
|
|
|
301
|
my ($fh) = $self->{' INFILE'}; |
265
|
188
|
|
|
|
|
224
|
my ($dat); |
266
|
|
|
|
|
|
|
|
267
|
188
|
50
|
33
|
|
|
490
|
return $self if (defined $self->{' read'} && $self->{' read'} > 0); |
268
|
188
|
|
|
|
|
709
|
$self->{' read'} = 1; |
269
|
188
|
|
|
|
|
891
|
$fh->seek($self->{' LOC'} + $self->{' BASE'}, 0); |
270
|
188
|
|
|
|
|
3070
|
$fh->read($self->{' DAT'}, $self->{' LEN'}); |
271
|
188
|
|
|
|
|
4357
|
TTF_Read_Fields($self, $self->{' DAT'}, \%fields); |
272
|
188
|
|
|
|
|
306
|
$self; |
273
|
|
|
|
|
|
|
} |
274
|
|
|
|
|
|
|
|
275
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
=head2 $g->read_dat |
277
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
Reads the contents of the glyph (components and curves, etc.) from the memory |
279
|
|
|
|
|
|
|
store C into structures within the object. |
280
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
=cut |
282
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
sub read_dat |
284
|
|
|
|
|
|
|
{ |
285
|
188
|
|
|
188
|
1
|
856
|
my ($self) = @_; |
286
|
188
|
|
|
|
|
326
|
my ($dat, $num, $max, $i, $flag, $len, $val, $val1, $fp); |
287
|
|
|
|
|
|
|
|
288
|
188
|
50
|
33
|
|
|
602
|
return $self if (defined $self->{' read'} && $self->{' read'} > 1); |
289
|
188
|
50
|
|
|
|
569
|
$self->read unless $self->{' read'}; |
290
|
188
|
|
|
|
|
332
|
$dat = $self->{' DAT'}; |
291
|
188
|
|
|
|
|
222
|
$fp = 10; |
292
|
188
|
|
|
|
|
266
|
$num = $self->{'numberOfContours'}; |
293
|
188
|
100
|
|
|
|
340
|
if ($num > 0) |
|
|
50
|
|
|
|
|
|
294
|
|
|
|
|
|
|
{ |
295
|
184
|
|
|
|
|
822
|
$self->{'endPoints'} = [unpack("n*", substr($dat, $fp, $num << 1))]; |
296
|
184
|
|
|
|
|
294
|
$fp += $num << 1; |
297
|
184
|
|
|
|
|
195
|
$max = 0; |
298
|
184
|
|
|
|
|
196
|
foreach (@{$self->{'endPoints'}}) |
|
184
|
|
|
|
|
553
|
|
299
|
260
|
50
|
|
|
|
722
|
{ $max = $_ if $_ > $max; } |
300
|
|
|
|
|
|
|
# print STDERR join(",", unpack('C*', $self->{" DAT"})); |
301
|
|
|
|
|
|
|
# printf STDERR ("(%d,%d in %d=%d @ %d)", scalar @{$self->{'endPoints'}}, $max, length($dat), $self->{' LEN'}, $fp); |
302
|
184
|
50
|
|
|
|
241
|
$max++ if (@{$self->{'endPoints'}}); |
|
184
|
|
|
|
|
491
|
|
303
|
184
|
|
|
|
|
703
|
$self->{'numPoints'} = $max; |
304
|
184
|
|
|
|
|
505
|
$self->{'instLen'} = unpack("n", substr($dat, $fp)); |
305
|
184
|
|
|
|
|
633
|
$self->{'hints'} = substr($dat, $fp + 2, $self->{'instLen'}); |
306
|
184
|
|
|
|
|
306
|
$fp += 2 + $self->{'instLen'}; |
307
|
|
|
|
|
|
|
# read the flags array |
308
|
184
|
|
|
|
|
456
|
for ($i = 0; $i < $max; $i++) |
309
|
|
|
|
|
|
|
{ |
310
|
5498
|
|
|
|
|
8691
|
$flag = unpack("C", substr($dat, $fp++)); |
311
|
5498
|
|
|
|
|
9021
|
$self->{'flags'}[$i] = $flag; |
312
|
5498
|
100
|
|
|
|
13902
|
if ($flag & 8) |
313
|
|
|
|
|
|
|
{ |
314
|
1474
|
|
|
|
|
2220
|
$len = unpack("C", substr($dat, $fp++)); |
315
|
1474
|
|
|
|
|
3196
|
while ($len-- > 0) |
316
|
|
|
|
|
|
|
{ |
317
|
2976
|
|
|
|
|
2384
|
$i++; |
318
|
2976
|
|
|
|
|
8051
|
$self->{'flags'}[$i] = $flag; |
319
|
|
|
|
|
|
|
} |
320
|
|
|
|
|
|
|
} |
321
|
|
|
|
|
|
|
} |
322
|
|
|
|
|
|
|
#read the x array |
323
|
184
|
|
|
|
|
400
|
for ($i = 0; $i < $max; $i++) |
324
|
|
|
|
|
|
|
{ |
325
|
8474
|
|
|
|
|
10155
|
$flag = $self->{'flags'}[$i]; |
326
|
8474
|
100
|
|
|
|
12050
|
if ($flag & 2) |
|
|
100
|
|
|
|
|
|
327
|
|
|
|
|
|
|
{ |
328
|
6630
|
|
|
|
|
11148
|
$val = unpack("C", substr($dat, $fp++)); |
329
|
6630
|
100
|
|
|
|
12442
|
$val = -$val unless ($flag & 16); |
330
|
|
|
|
|
|
|
} elsif ($flag & 16) |
331
|
1310
|
|
|
|
|
1270
|
{ $val = 0; } |
332
|
|
|
|
|
|
|
else |
333
|
|
|
|
|
|
|
{ |
334
|
534
|
|
|
|
|
2124
|
$val = TTF_Unpack("s", substr($dat, $fp)); |
335
|
534
|
|
|
|
|
1109
|
$fp += 2; |
336
|
|
|
|
|
|
|
} |
337
|
8474
|
100
|
|
|
|
35280
|
$self->{'x'}[$i] = $i == 0 ? $val : $self->{'x'}[$i - 1] + $val; |
338
|
|
|
|
|
|
|
} |
339
|
|
|
|
|
|
|
#read the y array |
340
|
184
|
|
|
|
|
429
|
for ($i = 0; $i < $max; $i++) |
341
|
|
|
|
|
|
|
{ |
342
|
8474
|
|
|
|
|
9417
|
$flag = $self->{'flags'}[$i]; |
343
|
8474
|
100
|
|
|
|
16180
|
if ($flag & 4) |
|
|
100
|
|
|
|
|
|
344
|
|
|
|
|
|
|
{ |
345
|
6774
|
|
|
|
|
10742
|
$val = unpack("C", substr($dat, $fp++)); |
346
|
6774
|
100
|
|
|
|
12764
|
$val = -$val unless ($flag & 32); |
347
|
|
|
|
|
|
|
} elsif ($flag & 32) |
348
|
1074
|
|
|
|
|
1046
|
{ $val = 0; } |
349
|
|
|
|
|
|
|
else |
350
|
|
|
|
|
|
|
{ |
351
|
626
|
|
|
|
|
2382
|
$val = TTF_Unpack("s", substr($dat, $fp)); |
352
|
626
|
|
|
|
|
1296
|
$fp += 2; |
353
|
|
|
|
|
|
|
} |
354
|
8474
|
100
|
|
|
|
27967
|
$self->{'y'}[$i] = $i == 0 ? $val : $self->{'y'}[$i - 1] + $val; |
355
|
|
|
|
|
|
|
} |
356
|
|
|
|
|
|
|
} |
357
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
# compound glyph |
359
|
|
|
|
|
|
|
elsif ($num < 0) |
360
|
|
|
|
|
|
|
{ |
361
|
4
|
|
|
|
|
6
|
$flag = 1 << 5; # cheat to get the loop going |
362
|
4
|
|
|
|
|
16
|
for ($i = 0; $flag & 32; $i++) |
363
|
|
|
|
|
|
|
{ |
364
|
8
|
|
|
|
|
38
|
($flag, $self->{'comps'}[$i]{'glyph'}) = unpack("n2", substr($dat, $fp)); |
365
|
8
|
|
|
|
|
12
|
$fp += 4; |
366
|
8
|
|
|
|
|
16
|
$self->{'comps'}[$i]{'flag'} = $flag; |
367
|
8
|
100
|
|
|
|
26
|
if ($flag & 1) # ARGS1_AND_2_ARE_WORDS |
368
|
|
|
|
|
|
|
{ |
369
|
4
|
|
|
|
|
18
|
$self->{'comps'}[$i]{'args'} = [TTF_Unpack("s2", substr($dat, $fp))]; |
370
|
4
|
|
|
|
|
10
|
$fp += 4; |
371
|
|
|
|
|
|
|
} else |
372
|
|
|
|
|
|
|
{ |
373
|
4
|
|
|
|
|
18
|
$self->{'comps'}[$i]{'args'} = [unpack("c2", substr($dat, $fp))]; |
374
|
4
|
|
|
|
|
6
|
$fp += 2; |
375
|
|
|
|
|
|
|
} |
376
|
|
|
|
|
|
|
|
377
|
8
|
50
|
|
|
|
33
|
if ($flag & 8) |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
378
|
|
|
|
|
|
|
{ |
379
|
0
|
|
|
|
|
0
|
$val = TTF_Unpack("F", substr($dat, $fp)); |
380
|
0
|
|
|
|
|
0
|
$fp += 2; |
381
|
0
|
|
|
|
|
0
|
$self->{'comps'}[$i]{'scale'} = [$val, 0, 0, $val]; |
382
|
|
|
|
|
|
|
} elsif ($flag & 64) |
383
|
|
|
|
|
|
|
{ |
384
|
0
|
|
|
|
|
0
|
($val, $val1) = TTF_Unpack("F2", substr($dat, $fp)); |
385
|
0
|
|
|
|
|
0
|
$fp += 4; |
386
|
0
|
|
|
|
|
0
|
$self->{'comps'}[$i]{'scale'} = [$val, 0, 0, $val1]; |
387
|
|
|
|
|
|
|
} elsif ($flag & 128) |
388
|
|
|
|
|
|
|
{ |
389
|
0
|
|
|
|
|
0
|
$self->{'comps'}[$i]{'scale'} = [TTF_Unpack("F4", substr($dat, $fp))]; |
390
|
0
|
|
|
|
|
0
|
$fp += 8; |
391
|
|
|
|
|
|
|
} |
392
|
8
|
50
|
|
|
|
27
|
$self->{'metric'} = $i if ($flag & 512); |
393
|
|
|
|
|
|
|
} |
394
|
4
|
|
|
|
|
16
|
$self->{'numPoints'} = $i; |
395
|
4
|
50
|
|
|
|
12
|
if ($flag & 256) # HAVE_INSTRUCTIONS |
396
|
|
|
|
|
|
|
{ |
397
|
0
|
|
|
|
|
0
|
$self->{'instLen'} = unpack("n", substr($dat, $fp)); |
398
|
0
|
|
|
|
|
0
|
$self->{'hints'} = substr($dat, $fp + 2, $self->{'instLen'}); |
399
|
0
|
|
|
|
|
0
|
$fp += 2 + $self->{'instLen'}; |
400
|
|
|
|
|
|
|
} |
401
|
|
|
|
|
|
|
} |
402
|
188
|
50
|
|
|
|
451
|
return undef if ($fp > length($dat)); |
403
|
188
|
|
|
|
|
319
|
$self->{' read'} = 2; |
404
|
188
|
|
|
|
|
882
|
$self; |
405
|
|
|
|
|
|
|
} |
406
|
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
|
408
|
|
|
|
|
|
|
=head2 $g->out($fh) |
409
|
|
|
|
|
|
|
|
410
|
|
|
|
|
|
|
Writes the glyph data to outfile |
411
|
|
|
|
|
|
|
|
412
|
|
|
|
|
|
|
=cut |
413
|
|
|
|
|
|
|
|
414
|
|
|
|
|
|
|
sub out |
415
|
|
|
|
|
|
|
{ |
416
|
188
|
|
|
188
|
1
|
179
|
my ($self, $fh) = @_; |
417
|
|
|
|
|
|
|
|
418
|
188
|
50
|
|
|
|
430
|
$self->read unless $self->{' read'}; |
419
|
188
|
50
|
|
|
|
326
|
$self->update if $self->{' isDirty'}; |
420
|
188
|
|
|
|
|
414
|
$fh->print($self->{' DAT'}); |
421
|
188
|
|
|
|
|
1368
|
$self->{' OUTLEN'} = length($self->{' DAT'}); |
422
|
188
|
|
|
|
|
289
|
$self; |
423
|
|
|
|
|
|
|
} |
424
|
|
|
|
|
|
|
|
425
|
|
|
|
|
|
|
|
426
|
|
|
|
|
|
|
=head2 $g->out_xml($context, $depth) |
427
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
Outputs an XML description of the glyph |
429
|
|
|
|
|
|
|
|
430
|
|
|
|
|
|
|
=cut |
431
|
|
|
|
|
|
|
|
432
|
|
|
|
|
|
|
sub out_xml |
433
|
|
|
|
|
|
|
{ |
434
|
0
|
|
|
0
|
1
|
0
|
my ($self, $context, $depth) = @_; |
435
|
0
|
|
|
|
|
0
|
my ($addr) = ($self =~ m/\((.+)\)$/o); |
436
|
0
|
|
|
|
|
0
|
my ($k, $ndepth); |
437
|
|
|
|
|
|
|
|
438
|
0
|
0
|
|
|
|
0
|
if ($context->{'addresses'}{$addr}) |
439
|
|
|
|
|
|
|
{ |
440
|
0
|
|
|
|
|
0
|
$context->{'fh'}->printf("%s\n", $depth, $context->{'gid'}, $context->{'addresses'}{$addr}); |
441
|
0
|
|
|
|
|
0
|
return $self; |
442
|
|
|
|
|
|
|
} |
443
|
|
|
|
|
|
|
else |
444
|
|
|
|
|
|
|
{ |
445
|
0
|
|
|
|
|
0
|
$context->{'fh'}->printf("%s\n", $depth, $context->{'gid'}); |
446
|
|
|
|
|
|
|
} |
447
|
|
|
|
|
|
|
|
448
|
0
|
|
|
|
|
0
|
$ndepth = $depth . $context->{'indent'}; |
449
|
0
|
|
|
|
|
0
|
$self->read_dat; |
450
|
0
|
|
|
|
|
0
|
foreach $k (sort grep {$_ !~ m/^\s/o} keys %{$self}) |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
451
|
|
|
|
|
|
|
{ |
452
|
0
|
|
|
|
|
0
|
$self->XML_element($context, $ndepth, $k, $self->{$k}); |
453
|
|
|
|
|
|
|
} |
454
|
0
|
|
|
|
|
0
|
$context->{'fh'}->print("$depth\n"); |
455
|
0
|
|
|
|
|
0
|
delete $context->{'done_points'}; |
456
|
0
|
|
|
|
|
0
|
$self; |
457
|
|
|
|
|
|
|
} |
458
|
|
|
|
|
|
|
|
459
|
|
|
|
|
|
|
|
460
|
|
|
|
|
|
|
sub XML_element |
461
|
|
|
|
|
|
|
{ |
462
|
0
|
|
|
0
|
0
|
0
|
my ($self, $context, $depth, $key, $val) = @_; |
463
|
0
|
|
|
|
|
0
|
my ($fh) = $context->{'fh'}; |
464
|
0
|
|
|
|
|
0
|
my ($dind) = $depth . $context->{'indent'}; |
465
|
0
|
|
|
|
|
0
|
my ($i); |
466
|
|
|
|
|
|
|
|
467
|
0
|
0
|
0
|
|
|
0
|
if ($self->{'numberOfContours'} >= 0 && ($key eq 'x' || $key eq 'y' || $key eq 'flags')) |
|
|
0
|
0
|
|
|
|
|
468
|
|
|
|
|
|
|
{ |
469
|
0
|
0
|
|
|
|
0
|
return $self if ($context->{'done_points'}); |
470
|
0
|
|
|
|
|
0
|
$context->{'done_points'} = 1; |
471
|
|
|
|
|
|
|
|
472
|
0
|
|
|
|
|
0
|
$fh->print("$depth\n"); |
473
|
0
|
|
|
|
|
0
|
for ($i = 0; $i <= $#{$self->{'flags'}}; $i++) |
|
0
|
|
|
|
|
0
|
|
474
|
0
|
|
|
|
|
0
|
{ $fh->printf("%s\n", $dind, |
475
|
|
|
|
|
|
|
$self->{'x'}[$i], $self->{'y'}[$i], $self->{'flags'}[$i]); } |
476
|
0
|
|
|
|
|
0
|
$fh->print("$depth\n"); |
477
|
|
|
|
|
|
|
} |
478
|
|
|
|
|
|
|
elsif ($key eq 'hints') |
479
|
|
|
|
|
|
|
{ |
480
|
0
|
|
|
|
|
0
|
my ($dat); |
481
|
0
|
|
|
|
|
0
|
$fh->print("$depth\n"); |
482
|
|
|
|
|
|
|
# Font::TTF::Utils::XML_hexdump($context, $depth . $context->{'indent'}, $self->{'hints'}); |
483
|
0
|
|
0
|
|
|
0
|
$dat = Font::TTF::Utils::XML_binhint($self->{'hints'}) || ""; |
484
|
0
|
|
|
|
|
0
|
$dat =~ s/\n(?!$)/\n$depth$context->{'indent'}/mg; |
485
|
0
|
|
|
|
|
0
|
$fh->print("$depth$context->{'indent'}$dat"); |
486
|
0
|
|
|
|
|
0
|
$fh->print("$depth\n"); |
487
|
|
|
|
|
|
|
} |
488
|
|
|
|
|
|
|
else |
489
|
0
|
|
|
|
|
0
|
{ return Font::TTF::Table::XML_element(@_); } |
490
|
|
|
|
|
|
|
|
491
|
0
|
|
|
|
|
0
|
$self; |
492
|
|
|
|
|
|
|
} |
493
|
|
|
|
|
|
|
|
494
|
|
|
|
|
|
|
=head2 $g->dirty($val) |
495
|
|
|
|
|
|
|
|
496
|
|
|
|
|
|
|
This sets the dirty flag to the given value or 1 if no given value. It returns the |
497
|
|
|
|
|
|
|
value of the flag |
498
|
|
|
|
|
|
|
|
499
|
|
|
|
|
|
|
=cut |
500
|
|
|
|
|
|
|
|
501
|
|
|
|
|
|
|
sub dirty |
502
|
|
|
|
|
|
|
{ |
503
|
0
|
|
|
0
|
1
|
0
|
my ($self, $val) = @_; |
504
|
0
|
|
|
|
|
0
|
my ($res) = $self->{' isDirty'}; |
505
|
|
|
|
|
|
|
|
506
|
0
|
0
|
|
|
|
0
|
$self->{' isDirty'} = defined $val ? $val : 1; |
507
|
0
|
|
|
|
|
0
|
$res; |
508
|
|
|
|
|
|
|
} |
509
|
|
|
|
|
|
|
|
510
|
|
|
|
|
|
|
=head2 $g->update |
511
|
|
|
|
|
|
|
|
512
|
|
|
|
|
|
|
Generates a C<$self->{'DAT'}> from the internal structures, if the data has |
513
|
|
|
|
|
|
|
been read into structures in the first place. If you are building a glyph |
514
|
|
|
|
|
|
|
from scratch you will need to set the instance variable C<' isDirty'>. |
515
|
|
|
|
|
|
|
|
516
|
|
|
|
|
|
|
=cut |
517
|
|
|
|
|
|
|
|
518
|
|
|
|
|
|
|
sub update |
519
|
|
|
|
|
|
|
{ |
520
|
188
|
|
|
188
|
1
|
188
|
my ($self) = @_; |
521
|
188
|
|
|
|
|
218
|
my ($dat, $loc, $len, $flag, $x, $y, $i, $comp, $num, @rflags, $repeat); |
522
|
|
|
|
|
|
|
|
523
|
188
|
50
|
|
|
|
555
|
return $self unless ($self->{' isDirty'}); |
524
|
0
|
|
|
|
|
|
$self->read_dat->update_bbox; |
525
|
0
|
|
|
|
|
|
$self->{' DAT'} = TTF_Out_Fields($self, \%fields, 10); |
526
|
0
|
|
|
|
|
|
$num = $self->{'numberOfContours'}; |
527
|
0
|
0
|
|
|
|
|
if ($num > 0) |
|
|
0
|
|
|
|
|
|
528
|
|
|
|
|
|
|
{ |
529
|
0
|
|
|
|
|
|
$self->{' DAT'} .= pack("n*", @{$self->{'endPoints'}}); |
|
0
|
|
|
|
|
|
|
530
|
0
|
|
|
|
|
|
$len = $self->{'instLen'}; |
531
|
0
|
|
|
|
|
|
$self->{' DAT'} .= pack("n", $len); |
532
|
0
|
0
|
|
|
|
|
$self->{' DAT'} .= pack("a" . $len, substr($self->{'hints'}, 0, $len)) if ($len > 0); |
533
|
0
|
|
|
|
|
|
$repeat = 0; |
534
|
0
|
|
|
|
|
|
for ($i = 0; $i < $self->{'numPoints'}; $i++) |
535
|
|
|
|
|
|
|
{ |
536
|
0
|
|
|
|
|
|
$flag = $self->{'flags'}[$i] & 1; |
537
|
0
|
0
|
|
|
|
|
if ($i == 0) |
538
|
|
|
|
|
|
|
{ |
539
|
0
|
|
|
|
|
|
$x = $self->{'x'}[$i]; |
540
|
0
|
|
|
|
|
|
$y = $self->{'y'}[$i]; |
541
|
|
|
|
|
|
|
} else |
542
|
|
|
|
|
|
|
{ |
543
|
0
|
|
|
|
|
|
$x = $self->{'x'}[$i] - $self->{'x'}[$i - 1]; |
544
|
0
|
|
|
|
|
|
$y = $self->{'y'}[$i] - $self->{'y'}[$i - 1]; |
545
|
|
|
|
|
|
|
} |
546
|
0
|
0
|
|
|
|
|
$flag |= 16 if ($x == 0); |
547
|
0
|
0
|
|
|
|
|
$flag |= 32 if ($y == 0); |
548
|
0
|
0
|
0
|
|
|
|
if (($flag & 16) == 0 && $x < 256 && $x > -256) |
|
|
|
0
|
|
|
|
|
549
|
|
|
|
|
|
|
{ |
550
|
0
|
|
|
|
|
|
$flag |= 2; |
551
|
0
|
0
|
|
|
|
|
$flag |= 16 if ($x >= 0); |
552
|
|
|
|
|
|
|
} |
553
|
0
|
0
|
0
|
|
|
|
if (($flag & 32) == 0 && $y < 256 && $y > -256) |
|
|
|
0
|
|
|
|
|
554
|
|
|
|
|
|
|
{ |
555
|
0
|
|
|
|
|
|
$flag |= 4; |
556
|
0
|
0
|
|
|
|
|
$flag |= 32 if ($y >= 0); |
557
|
|
|
|
|
|
|
} |
558
|
0
|
0
|
0
|
|
|
|
if ($i > 0 && $rflags[-1] == $flag && $repeat < 255) |
|
|
|
0
|
|
|
|
|
559
|
|
|
|
|
|
|
{ |
560
|
0
|
|
|
|
|
|
$repeat++; |
561
|
|
|
|
|
|
|
} else |
562
|
|
|
|
|
|
|
{ |
563
|
0
|
0
|
|
|
|
|
if ($repeat) |
564
|
|
|
|
|
|
|
{ |
565
|
0
|
|
|
|
|
|
$rflags[-1] |= 8; |
566
|
0
|
|
|
|
|
|
push @rflags, $repeat; |
567
|
|
|
|
|
|
|
} |
568
|
0
|
|
|
|
|
|
push @rflags, $flag; |
569
|
0
|
|
|
|
|
|
$repeat = 0; |
570
|
|
|
|
|
|
|
} |
571
|
0
|
|
|
|
|
|
$self->{'flags'}[$i] = $flag; |
572
|
|
|
|
|
|
|
} |
573
|
|
|
|
|
|
|
# Add final repeat if needed, then pack up the flag bytes: |
574
|
0
|
0
|
|
|
|
|
if ($repeat) |
575
|
|
|
|
|
|
|
{ |
576
|
0
|
|
|
|
|
|
$rflags[-1] |= 8; |
577
|
0
|
|
|
|
|
|
push @rflags, $repeat; |
578
|
|
|
|
|
|
|
} |
579
|
0
|
|
|
|
|
|
$self->{' DAT'} .= pack("C*", @rflags); |
580
|
0
|
|
|
|
|
|
for ($i = 0; $i < $self->{'numPoints'}; $i++) |
581
|
|
|
|
|
|
|
{ |
582
|
0
|
|
|
|
|
|
$flag = $self->{'flags'}[$i]; |
583
|
0
|
0
|
|
|
|
|
$x = $self->{'x'}[$i] - (($i == 0) ? 0 : $self->{'x'}[$i - 1]); |
584
|
0
|
0
|
|
|
|
|
if (($flag & 18) == 0) |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
585
|
0
|
|
|
|
|
|
{ $self->{' DAT'} .= TTF_Pack("s", $x); } |
586
|
|
|
|
|
|
|
elsif (($flag & 18) == 18) |
587
|
0
|
|
|
|
|
|
{ $self->{' DAT'} .= pack("C", $x); } |
588
|
|
|
|
|
|
|
elsif (($flag & 18) == 2) |
589
|
0
|
|
|
|
|
|
{ $self->{' DAT'} .= pack("C", -$x); } |
590
|
|
|
|
|
|
|
} |
591
|
0
|
|
|
|
|
|
for ($i = 0; $i < $self->{'numPoints'}; $i++) |
592
|
|
|
|
|
|
|
{ |
593
|
0
|
|
|
|
|
|
$flag = $self->{'flags'}[$i]; |
594
|
0
|
0
|
|
|
|
|
$y = $self->{'y'}[$i] - (($i == 0) ? 0 : $self->{'y'}[$i - 1]); |
595
|
0
|
0
|
|
|
|
|
if (($flag & 36) == 0) |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
596
|
0
|
|
|
|
|
|
{ $self->{' DAT'} .= TTF_Pack("s", $y); } |
597
|
|
|
|
|
|
|
elsif (($flag & 36) == 36) |
598
|
0
|
|
|
|
|
|
{ $self->{' DAT'} .= pack("C", $y); } |
599
|
|
|
|
|
|
|
elsif (($flag & 36) == 4) |
600
|
0
|
|
|
|
|
|
{ $self->{' DAT'} .= pack("C", -$y); } |
601
|
|
|
|
|
|
|
} |
602
|
|
|
|
|
|
|
} |
603
|
|
|
|
|
|
|
|
604
|
|
|
|
|
|
|
elsif ($num < 0) |
605
|
|
|
|
|
|
|
{ |
606
|
0
|
|
|
|
|
|
for ($i = 0; $i <= $#{$self->{'comps'}}; $i++) |
|
0
|
|
|
|
|
|
|
607
|
|
|
|
|
|
|
{ |
608
|
0
|
|
|
|
|
|
$comp = $self->{'comps'}[$i]; |
609
|
0
|
|
|
|
|
|
$flag = $comp->{'flag'} & 7158; # bits 2,10,11,12 |
610
|
0
|
0
|
0
|
|
|
|
$flag |= 1 unless ($comp->{'args'}[0] > -129 && $comp->{'args'}[0] < 128 |
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
611
|
|
|
|
|
|
|
&& $comp->{'args'}[1] > -129 && $comp->{'args'}[1] < 128); |
612
|
0
|
0
|
|
|
|
|
if (defined $comp->{'scale'}) |
613
|
|
|
|
|
|
|
{ |
614
|
0
|
0
|
0
|
|
|
|
if ($comp->{'scale'}[1] == 0 && $comp->{'scale'}[2] == 0) |
615
|
|
|
|
|
|
|
{ |
616
|
0
|
0
|
|
|
|
|
if ($comp->{'scale'}[0] == $comp->{'scale'}[3]) |
617
|
0
|
0
|
0
|
|
|
|
{ $flag |= 8 unless ($comp->{'scale'}[0] == 0 |
618
|
|
|
|
|
|
|
|| $comp->{'scale'}[0] == 1); } |
619
|
|
|
|
|
|
|
else |
620
|
0
|
|
|
|
|
|
{ $flag |= 64; } |
621
|
|
|
|
|
|
|
} else |
622
|
0
|
|
|
|
|
|
{ $flag |= 128; } |
623
|
|
|
|
|
|
|
} |
624
|
|
|
|
|
|
|
|
625
|
0
|
0
|
0
|
|
|
|
$flag |= 512 if (defined $self->{'metric'} && $self->{'metric'} == $i); |
626
|
0
|
0
|
|
|
|
|
if ($i == $#{$self->{'comps'}}) |
|
0
|
|
|
|
|
|
|
627
|
0
|
0
|
0
|
|
|
|
{ $flag |= 256 if (defined $self->{'instLen'} && $self->{'instLen'} > 0); } |
628
|
|
|
|
|
|
|
else |
629
|
0
|
|
|
|
|
|
{ $flag |= 32; } |
630
|
|
|
|
|
|
|
|
631
|
0
|
|
|
|
|
|
$self->{' DAT'} .= pack("n", $flag); |
632
|
0
|
|
|
|
|
|
$self->{' DAT'} .= pack("n", $comp->{'glyph'}); |
633
|
0
|
|
|
|
|
|
$comp->{'flag'} = $flag; |
634
|
|
|
|
|
|
|
|
635
|
0
|
0
|
|
|
|
|
if ($flag & 1) |
636
|
0
|
|
|
|
|
|
{ $self->{' DAT'} .= TTF_Pack("s2", @{$comp->{'args'}}); } |
|
0
|
|
|
|
|
|
|
637
|
|
|
|
|
|
|
else |
638
|
0
|
|
|
|
|
|
{ $self->{' DAT'} .= pack("CC", @{$comp->{'args'}}); } |
|
0
|
|
|
|
|
|
|
639
|
|
|
|
|
|
|
|
640
|
0
|
0
|
|
|
|
|
if ($flag & 8) |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
641
|
0
|
|
|
|
|
|
{ $self->{' DAT'} .= TTF_Pack("F", $comp->{'scale'}[0]); } |
642
|
|
|
|
|
|
|
elsif ($flag & 64) |
643
|
0
|
|
|
|
|
|
{ $self->{' DAT'} .= TTF_Pack("F2", $comp->{'scale'}[0], $comp->{'scale'}[3]); } |
644
|
|
|
|
|
|
|
elsif ($flag & 128) |
645
|
0
|
|
|
|
|
|
{ $self->{' DAT'} .= TTF_Pack("F4", @{$comp->{'scale'}}); } |
|
0
|
|
|
|
|
|
|
646
|
|
|
|
|
|
|
} |
647
|
0
|
0
|
0
|
|
|
|
if (defined $self->{'instLen'} && $self->{'instLen'} > 0) |
648
|
|
|
|
|
|
|
{ |
649
|
0
|
|
|
|
|
|
$len = $self->{'instLen'}; |
650
|
0
|
|
|
|
|
|
$self->{' DAT'} .= pack("n", $len); |
651
|
0
|
|
|
|
|
|
$self->{' DAT'} .= pack("a" . $len, substr($self->{'hints'}, 0, $len)); |
652
|
|
|
|
|
|
|
} |
653
|
|
|
|
|
|
|
} |
654
|
0
|
|
|
|
|
|
my ($olen) = length($self->{' DAT'}); |
655
|
0
|
0
|
|
|
|
|
$self->{' DAT'} .= ("\000") x (4 - ($olen & 3)) if ($olen & 3); |
656
|
0
|
|
|
|
|
|
$self->{' OUTLEN'} = length($self->{' DAT'}); |
657
|
0
|
|
|
|
|
|
$self->{' read'} = 2; # changed from 1 to 2 so we don't read_dat() again |
658
|
|
|
|
|
|
|
# we leave numPoints and instLen since maxp stats use this |
659
|
0
|
|
|
|
|
|
$self; |
660
|
|
|
|
|
|
|
} |
661
|
|
|
|
|
|
|
|
662
|
|
|
|
|
|
|
|
663
|
|
|
|
|
|
|
=head2 $g->update_bbox |
664
|
|
|
|
|
|
|
|
665
|
|
|
|
|
|
|
Updates the bounding box for this glyph according to the points in the glyph |
666
|
|
|
|
|
|
|
|
667
|
|
|
|
|
|
|
=cut |
668
|
|
|
|
|
|
|
|
669
|
|
|
|
|
|
|
sub update_bbox |
670
|
|
|
|
|
|
|
{ |
671
|
0
|
|
|
0
|
1
|
|
my ($self) = @_; |
672
|
0
|
|
|
|
|
|
my ($num, $maxx, $minx, $maxy, $miny, $i, $comp, $x, $y, $compg); |
673
|
|
|
|
|
|
|
|
674
|
0
|
0
|
0
|
|
|
|
return $self unless (defined $self->{' read'} && $self->{' read'} > 1); # only if read_dat done |
675
|
0
|
|
|
|
|
|
$miny = $minx = 65537; $maxx = $maxy = -65537; |
|
0
|
|
|
|
|
|
|
676
|
0
|
|
|
|
|
|
$num = $self->{'numberOfContours'}; |
677
|
0
|
0
|
|
|
|
|
if ($num > 0) |
|
|
0
|
|
|
|
|
|
678
|
|
|
|
|
|
|
{ |
679
|
0
|
|
|
|
|
|
for ($i = 0; $i < $self->{'numPoints'}; $i++) |
680
|
|
|
|
|
|
|
{ |
681
|
0
|
|
|
|
|
|
($x, $y) = ($self->{'x'}[$i], $self->{'y'}[$i]); |
682
|
|
|
|
|
|
|
|
683
|
0
|
0
|
|
|
|
|
$maxx = $x if ($x > $maxx); |
684
|
0
|
0
|
|
|
|
|
$minx = $x if ($x < $minx); |
685
|
0
|
0
|
|
|
|
|
$maxy = $y if ($y > $maxy); |
686
|
0
|
0
|
|
|
|
|
$miny = $y if ($y < $miny); |
687
|
|
|
|
|
|
|
} |
688
|
|
|
|
|
|
|
} |
689
|
|
|
|
|
|
|
|
690
|
|
|
|
|
|
|
elsif ($num < 0) |
691
|
|
|
|
|
|
|
{ |
692
|
0
|
|
|
|
|
|
foreach $comp (@{$self->{'comps'}}) |
|
0
|
|
|
|
|
|
|
693
|
|
|
|
|
|
|
{ |
694
|
0
|
|
|
|
|
|
my ($gnx, $gny, $gxx, $gxy); |
695
|
0
|
|
|
|
|
|
my ($sxx, $sxy, $syx, $syy); |
696
|
|
|
|
|
|
|
|
697
|
0
|
|
|
|
|
|
my $otherg = $self->{' PARENT'}{'loca'}{'glyphs'}[$comp->{'glyph'}]; |
698
|
|
|
|
|
|
|
# work around bad fonts: see documentation for 'comps' above |
699
|
0
|
0
|
|
|
|
|
next unless (defined $otherg); |
700
|
0
|
|
|
|
|
|
$compg = $otherg->read->update_bbox; |
701
|
0
|
|
|
|
|
|
($gnx, $gny, $gxx, $gxy) = @{$compg}{'xMin', 'yMin', 'xMax', 'yMax'}; |
|
0
|
|
|
|
|
|
|
702
|
0
|
0
|
0
|
|
|
|
if (defined $comp->{'scale'}) |
|
|
0
|
|
|
|
|
|
703
|
|
|
|
|
|
|
{ |
704
|
0
|
|
|
|
|
|
($sxx, $sxy, $syx, $syy) = @{$comp->{'scale'}}; |
|
0
|
|
|
|
|
|
|
705
|
0
|
|
|
|
|
|
($gnx, $gny, $gxx, $gxy) = ($gnx*$sxx+$gny*$syx + $comp->{'args'}[0], |
706
|
|
|
|
|
|
|
$gnx*$sxy+$gny*$syy + $comp->{'args'}[1], |
707
|
|
|
|
|
|
|
$gxx*$sxx+$gxy*$syx + $comp->{'args'}[0], |
708
|
|
|
|
|
|
|
$gxx*$sxy+$gxy*$syy + $comp->{'args'}[1]); |
709
|
|
|
|
|
|
|
} elsif ($comp->{'args'}[0] || $comp->{'args'}[1]) |
710
|
|
|
|
|
|
|
{ |
711
|
0
|
|
|
|
|
|
$gnx += $comp->{'args'}[0]; |
712
|
0
|
|
|
|
|
|
$gny += $comp->{'args'}[1]; |
713
|
0
|
|
|
|
|
|
$gxx += $comp->{'args'}[0]; |
714
|
0
|
|
|
|
|
|
$gxy += $comp->{'args'}[1]; |
715
|
|
|
|
|
|
|
} |
716
|
0
|
0
|
|
|
|
|
($gnx, $gxx) = ($gxx, $gnx) if $gnx > $gxx; |
717
|
0
|
0
|
|
|
|
|
($gny, $gxy) = ($gxy, $gny) if $gny > $gxy; |
718
|
0
|
0
|
|
|
|
|
$maxx = $gxx if $gxx > $maxx; |
719
|
0
|
0
|
|
|
|
|
$minx = $gnx if $gnx < $minx; |
720
|
0
|
0
|
|
|
|
|
$maxy = $gxy if $gxy > $maxy; |
721
|
0
|
0
|
|
|
|
|
$miny = $gny if $gny < $miny; |
722
|
|
|
|
|
|
|
} |
723
|
|
|
|
|
|
|
} |
724
|
0
|
|
|
|
|
|
$self->{'xMax'} = $maxx; |
725
|
0
|
|
|
|
|
|
$self->{'xMin'} = $minx; |
726
|
0
|
|
|
|
|
|
$self->{'yMax'} = $maxy; |
727
|
0
|
|
|
|
|
|
$self->{'yMin'} = $miny; |
728
|
0
|
|
|
|
|
|
$self; |
729
|
|
|
|
|
|
|
} |
730
|
|
|
|
|
|
|
|
731
|
|
|
|
|
|
|
|
732
|
|
|
|
|
|
|
=head2 $g->maxInfo |
733
|
|
|
|
|
|
|
|
734
|
|
|
|
|
|
|
Returns lots of information about a glyph so that the C table can update |
735
|
|
|
|
|
|
|
itself. Returns array containing contributions of this glyph to maxPoints, maxContours, |
736
|
|
|
|
|
|
|
maxCompositePoints, maxCompositeContours, maxSizeOfInstructions, maxComponentElements, |
737
|
|
|
|
|
|
|
and maxComponentDepth. |
738
|
|
|
|
|
|
|
|
739
|
|
|
|
|
|
|
=cut |
740
|
|
|
|
|
|
|
|
741
|
|
|
|
|
|
|
sub maxInfo |
742
|
|
|
|
|
|
|
{ |
743
|
0
|
|
|
0
|
1
|
|
my ($self) = @_; |
744
|
0
|
|
|
|
|
|
my (@res, $i, @n); |
745
|
|
|
|
|
|
|
|
746
|
0
|
|
|
|
|
|
$self->read_dat; # make sure we've read some data |
747
|
0
|
0
|
|
|
|
|
$res[4] = length($self->{'hints'}) if defined $self->{'hints'}; |
748
|
0
|
|
|
|
|
|
$res[6] = 1; |
749
|
0
|
0
|
|
|
|
|
if ($self->{'numberOfContours'} > 0) |
|
|
0
|
|
|
|
|
|
750
|
|
|
|
|
|
|
{ |
751
|
0
|
|
|
|
|
|
$res[0] = $self->{'numPoints'}; |
752
|
0
|
|
|
|
|
|
$res[1] = $self->{'numberOfContours'}; |
753
|
|
|
|
|
|
|
} elsif ($self->{'numberOfContours'} < 0) |
754
|
|
|
|
|
|
|
{ |
755
|
0
|
|
|
|
|
|
for ($i = 0; $i <= $#{$self->{'comps'}}; $i++) |
|
0
|
|
|
|
|
|
|
756
|
|
|
|
|
|
|
{ |
757
|
0
|
|
|
|
|
|
my $otherg = |
758
|
|
|
|
|
|
|
$self->{' PARENT'}{'loca'}{'glyphs'} |
759
|
|
|
|
|
|
|
[$self->{'comps'}[$i]{'glyph'}]; |
760
|
|
|
|
|
|
|
|
761
|
|
|
|
|
|
|
# work around bad fonts: see documentation for 'comps' above |
762
|
0
|
0
|
|
|
|
|
next unless (defined $otherg ); |
763
|
|
|
|
|
|
|
|
764
|
0
|
|
|
|
|
|
@n = $otherg->maxInfo; |
765
|
|
|
|
|
|
|
|
766
|
0
|
0
|
|
|
|
|
$res[2] += $n[2] == 0 ? $n[0] : $n[2]; |
767
|
0
|
0
|
|
|
|
|
$res[3] += $n[3] == 0 ? $n[1] : $n[3]; |
768
|
0
|
|
|
|
|
|
$res[5]++; |
769
|
0
|
0
|
|
|
|
|
$res[6] = $n[6] + 1 if ($n[6] >= $res[6]); |
770
|
|
|
|
|
|
|
} |
771
|
|
|
|
|
|
|
} |
772
|
0
|
|
|
|
|
|
@res; |
773
|
|
|
|
|
|
|
} |
774
|
|
|
|
|
|
|
|
775
|
|
|
|
|
|
|
=head2 $g->empty |
776
|
|
|
|
|
|
|
|
777
|
|
|
|
|
|
|
Empties the glyph of all information to the level of not having been read. |
778
|
|
|
|
|
|
|
Useful for saving memory in apps with many glyphs being read |
779
|
|
|
|
|
|
|
|
780
|
|
|
|
|
|
|
=cut |
781
|
|
|
|
|
|
|
|
782
|
|
|
|
|
|
|
sub empty |
783
|
|
|
|
|
|
|
{ |
784
|
0
|
|
|
0
|
1
|
|
my ($self) = @_; |
785
|
0
|
|
|
|
|
|
my (%keep) = map {(" $_" => 1)} ('LOC', 'OUTLOC', 'PARENT', 'INFILE', 'BASE', |
|
0
|
|
|
|
|
|
|
786
|
|
|
|
|
|
|
'OUTLEN', 'LEN'); |
787
|
0
|
0
|
|
|
|
|
map {delete $self->{$_} unless $keep{$_}} keys %$self; |
|
0
|
|
|
|
|
|
|
788
|
|
|
|
|
|
|
|
789
|
0
|
|
|
|
|
|
$self; |
790
|
|
|
|
|
|
|
} |
791
|
|
|
|
|
|
|
|
792
|
|
|
|
|
|
|
|
793
|
|
|
|
|
|
|
=head2 $g->get_points |
794
|
|
|
|
|
|
|
|
795
|
|
|
|
|
|
|
This method creates point information for a compound glyph. The information is |
796
|
|
|
|
|
|
|
stored in the same place as if the glyph was not a compound, but since |
797
|
|
|
|
|
|
|
numberOfContours is negative, the glyph is still marked as being a compound |
798
|
|
|
|
|
|
|
|
799
|
|
|
|
|
|
|
=cut |
800
|
|
|
|
|
|
|
|
801
|
|
|
|
|
|
|
sub get_points |
802
|
|
|
|
|
|
|
{ |
803
|
0
|
|
|
0
|
1
|
|
my ($self) = @_; |
804
|
0
|
|
|
|
|
|
my ($comp, $compg, $nump, $e, $i); |
805
|
|
|
|
|
|
|
|
806
|
0
|
|
|
|
|
|
$self->read_dat; |
807
|
0
|
0
|
|
|
|
|
return undef unless ($self->{'numberOfContours'} < 0); |
808
|
|
|
|
|
|
|
|
809
|
0
|
|
|
|
|
|
foreach $comp (@{$self->{'comps'}}) |
|
0
|
|
|
|
|
|
|
810
|
|
|
|
|
|
|
{ |
811
|
0
|
|
|
|
|
|
$compg = $self->{' PARENT'}{'loca'}{'glyphs'}[$comp->{'glyph'}]; |
812
|
|
|
|
|
|
|
# work around bad fonts: see documentation for 'comps' above |
813
|
0
|
0
|
|
|
|
|
next unless (defined $compg ); |
814
|
0
|
|
|
|
|
|
$compg->get_points; |
815
|
|
|
|
|
|
|
|
816
|
0
|
|
|
|
|
|
for ($i = 0; $i < $compg->{'numPoints'}; $i++) |
817
|
|
|
|
|
|
|
{ |
818
|
0
|
|
|
|
|
|
my ($x, $y) = ($compg->{'x'}[$i], $compg->{'y'}[$i]); |
819
|
0
|
0
|
|
|
|
|
if (defined $comp->{'scale'}) |
820
|
|
|
|
|
|
|
{ |
821
|
0
|
|
|
|
|
|
($x, $y) = ($x * $comp->{'scale'}[0] + $y * $comp->{'scale'}[2], |
822
|
|
|
|
|
|
|
$x * $comp->{'scale'}[1] + $y * $comp->{'scale'}[3]); |
823
|
|
|
|
|
|
|
} |
824
|
0
|
0
|
|
|
|
|
if (defined $comp->{'args'}) |
825
|
0
|
|
|
|
|
|
{ ($x, $y) = ($x + $comp->{'args'}[0], $y + $comp->{'args'}[1]); } |
826
|
0
|
|
|
|
|
|
push (@{$self->{'x'}}, $x); |
|
0
|
|
|
|
|
|
|
827
|
0
|
|
|
|
|
|
push (@{$self->{'y'}}, $y); |
|
0
|
|
|
|
|
|
|
828
|
0
|
|
|
|
|
|
push (@{$self->{'flags'}}, $compg->{'flags'}[$i]); |
|
0
|
|
|
|
|
|
|
829
|
|
|
|
|
|
|
} |
830
|
0
|
|
|
|
|
|
foreach $e (@{$compg->{'endPoints'}}) |
|
0
|
|
|
|
|
|
|
831
|
0
|
|
|
|
|
|
{ push (@{$self->{'endPoints'}}, $e + $nump); } |
|
0
|
|
|
|
|
|
|
832
|
0
|
|
|
|
|
|
$nump += $compg->{'numPoints'}; |
833
|
|
|
|
|
|
|
} |
834
|
0
|
|
|
|
|
|
$self->{'numPoints'} = $nump; |
835
|
0
|
|
|
|
|
|
$self; |
836
|
|
|
|
|
|
|
} |
837
|
|
|
|
|
|
|
|
838
|
|
|
|
|
|
|
|
839
|
|
|
|
|
|
|
=head2 $g->get_refs |
840
|
|
|
|
|
|
|
|
841
|
|
|
|
|
|
|
Returns an array of all the glyph ids that are used to make up this glyph. That |
842
|
|
|
|
|
|
|
is all the compounds and their references and so on. If this glyph is not a |
843
|
|
|
|
|
|
|
compound, then returns an empty array. |
844
|
|
|
|
|
|
|
|
845
|
|
|
|
|
|
|
Please note the warning about bad fonts that reference nonexistant glyphs |
846
|
|
|
|
|
|
|
under INSTANCE VARIABLES above. This function will not attempt to |
847
|
|
|
|
|
|
|
filter out nonexistant glyph numbers. |
848
|
|
|
|
|
|
|
|
849
|
|
|
|
|
|
|
=cut |
850
|
|
|
|
|
|
|
|
851
|
|
|
|
|
|
|
sub get_refs |
852
|
|
|
|
|
|
|
{ |
853
|
0
|
|
|
0
|
1
|
|
my ($self) = @_; |
854
|
0
|
|
|
|
|
|
my (@res, $g); |
855
|
|
|
|
|
|
|
|
856
|
0
|
|
|
|
|
|
$self->read_dat; |
857
|
0
|
0
|
|
|
|
|
return unless ($self->{'numberOfContours'} < 0); |
858
|
0
|
|
|
|
|
|
foreach $g (@{$self->{'comps'}}) |
|
0
|
|
|
|
|
|
|
859
|
|
|
|
|
|
|
{ |
860
|
0
|
|
|
|
|
|
push (@res, $g->{'glyph'}); |
861
|
0
|
|
|
|
|
|
my $otherg = $self->{' PARENT'}{'loca'}{'glyphs'}[$g->{'glyph'}]; |
862
|
|
|
|
|
|
|
# work around bad fonts: see documentation for 'comps' above |
863
|
0
|
0
|
|
|
|
|
next unless (defined $otherg); |
864
|
0
|
|
|
|
|
|
my @list = $otherg->get_refs; |
865
|
0
|
|
|
|
|
|
push(@res, @list); |
866
|
|
|
|
|
|
|
} |
867
|
0
|
|
|
|
|
|
return @res; |
868
|
|
|
|
|
|
|
} |
869
|
|
|
|
|
|
|
|
870
|
|
|
|
|
|
|
1; |
871
|
|
|
|
|
|
|
|
872
|
|
|
|
|
|
|
=head1 BUGS |
873
|
|
|
|
|
|
|
|
874
|
|
|
|
|
|
|
=over 4 |
875
|
|
|
|
|
|
|
|
876
|
|
|
|
|
|
|
=item * |
877
|
|
|
|
|
|
|
|
878
|
|
|
|
|
|
|
The instance variables used here are somewhat clunky and inconsistent with |
879
|
|
|
|
|
|
|
the other tables. |
880
|
|
|
|
|
|
|
|
881
|
|
|
|
|
|
|
=item * |
882
|
|
|
|
|
|
|
|
883
|
|
|
|
|
|
|
C doesn't re-calculate the bounding box or C. |
884
|
|
|
|
|
|
|
|
885
|
|
|
|
|
|
|
=back |
886
|
|
|
|
|
|
|
|
887
|
|
|
|
|
|
|
=head1 AUTHOR |
888
|
|
|
|
|
|
|
|
889
|
|
|
|
|
|
|
Martin Hosken L. |
890
|
|
|
|
|
|
|
|
891
|
|
|
|
|
|
|
|
892
|
|
|
|
|
|
|
=head1 LICENSING |
893
|
|
|
|
|
|
|
|
894
|
|
|
|
|
|
|
Copyright (c) 1998-2014, SIL International (http://www.sil.org) |
895
|
|
|
|
|
|
|
|
896
|
|
|
|
|
|
|
This module is released under the terms of the Artistic License 2.0. |
897
|
|
|
|
|
|
|
For details, see the full text of the license in the file LICENSE. |
898
|
|
|
|
|
|
|
|
899
|
|
|
|
|
|
|
|
900
|
|
|
|
|
|
|
|
901
|
|
|
|
|
|
|
=cut |
902
|
|
|
|
|
|
|
|