line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Font::TTF::Utils; |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
=head1 NAME |
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
Font::TTF::Utils - Utility functions to save fingers |
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
=head1 DESCRIPTION |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
Lots of useful functions to save my fingers, especially for trivial tables |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
=head1 FUNCTIONS |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
The following functions are exported |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
=cut |
16
|
|
|
|
|
|
|
|
17
|
1
|
|
|
1
|
|
3
|
use strict; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
30
|
|
18
|
1
|
|
|
1
|
|
3
|
use vars qw(@ISA @EXPORT $VERSION @EXPORT_OK); |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
2844
|
|
19
|
|
|
|
|
|
|
require Exporter; |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
@ISA = qw(Exporter); |
22
|
|
|
|
|
|
|
@EXPORT = qw(TTF_Init_Fields TTF_Read_Fields TTF_Out_Fields TTF_Pack |
23
|
|
|
|
|
|
|
TTF_Unpack TTF_word_utf8 TTF_utf8_word TTF_bininfo); |
24
|
|
|
|
|
|
|
@EXPORT_OK = (@EXPORT, qw(XML_hexdump)); |
25
|
|
|
|
|
|
|
$VERSION = 0.0001; |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
=head2 ($val, $pos) = TTF_Init_Fields ($str, $pos) |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
Given a field description from the C section, creates an absolute entry |
30
|
|
|
|
|
|
|
in the fields associative array for the class |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
=cut |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
sub TTF_Init_Fields |
35
|
|
|
|
|
|
|
{ |
36
|
119
|
|
|
119
|
1
|
134
|
my ($str, $pos, $inval) = @_; |
37
|
119
|
|
|
|
|
82
|
my ($key, $val, $res, $len, $rel); |
38
|
|
|
|
|
|
|
|
39
|
119
|
|
|
|
|
133
|
$str =~ s/\r?\n$//o; |
40
|
119
|
50
|
|
|
|
132
|
if ($inval) |
41
|
119
|
|
|
|
|
116
|
{ ($key, $val) = ($str, $inval); } |
42
|
|
|
|
|
|
|
else |
43
|
0
|
|
|
|
|
0
|
{ ($key, $val) = split(',\s*', $str); } |
44
|
119
|
50
|
33
|
|
|
344
|
return (undef, undef, 0) unless (defined $key && $key ne ""); |
45
|
119
|
50
|
|
|
|
320
|
if ($val =~ m/^(\+?)(\d*)(\D+)(\d*)/oi) |
46
|
|
|
|
|
|
|
{ |
47
|
119
|
|
|
|
|
135
|
$rel = $1; |
48
|
119
|
100
|
|
|
|
248
|
if ($rel eq "+") |
|
|
50
|
|
|
|
|
|
49
|
1
|
|
|
|
|
3
|
{ $pos += $2; } |
50
|
|
|
|
|
|
|
elsif ($2 ne "") |
51
|
0
|
|
|
|
|
0
|
{ $pos = $2; } |
52
|
119
|
|
|
|
|
128
|
$val = $3; |
53
|
119
|
|
|
|
|
115
|
$len = $4; |
54
|
|
|
|
|
|
|
} |
55
|
119
|
50
|
|
|
|
149
|
$len = "" unless defined $len; |
56
|
119
|
100
|
66
|
|
|
345
|
$pos = 0 if !defined $pos || $pos eq ""; |
57
|
119
|
|
|
|
|
131
|
$res = "$pos:$val:$len"; |
58
|
119
|
100
|
100
|
|
|
734
|
if ($val eq "f" || $val eq 'v' || $val =~ m/^[l]/oi) |
|
|
100
|
100
|
|
|
|
|
|
|
|
66
|
|
|
|
|
59
|
27
|
100
|
|
|
|
49
|
{ $pos += 4 * ($len ne "" ? $len : 1); } |
60
|
|
|
|
|
|
|
elsif ($val eq "F" || $val =~ m/^[s]/oi) |
61
|
82
|
50
|
|
|
|
116
|
{ $pos += 2 * ($len ne "" ? $len : 1); } |
62
|
|
|
|
|
|
|
else |
63
|
10
|
50
|
|
|
|
15
|
{ $pos += 1 * ($len ne "" ? $len : 1); } |
64
|
|
|
|
|
|
|
|
65
|
119
|
|
|
|
|
334
|
($key, $res, $pos); |
66
|
|
|
|
|
|
|
} |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
=head2 TTF_Read_Fields($obj, $dat, $fields) |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
Given a block of data large enough to account for all the fields in a table, |
72
|
|
|
|
|
|
|
processes the data block to convert to the values in the objects instance |
73
|
|
|
|
|
|
|
variables by name based on the list in the C block which has been run |
74
|
|
|
|
|
|
|
through C |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
=cut |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
sub TTF_Read_Fields |
79
|
|
|
|
|
|
|
{ |
80
|
198
|
|
|
198
|
1
|
275
|
my ($self, $dat, $fields) = @_; |
81
|
198
|
|
|
|
|
150
|
my ($pos, $type, $res, $f, $arrlen, $arr, $frac); |
82
|
|
|
|
|
|
|
|
83
|
198
|
|
|
|
|
181
|
foreach $f (keys %{$fields}) |
|
198
|
|
|
|
|
591
|
|
84
|
|
|
|
|
|
|
{ |
85
|
1134
|
|
|
|
|
3455
|
($pos, $type, $arrlen) = split(':', $fields->{$f}); |
86
|
1134
|
50
|
|
|
|
2156
|
$pos = 0 if $pos eq ""; |
87
|
1134
|
100
|
|
|
|
1599
|
if ($arrlen ne "") |
88
|
4
|
|
|
|
|
13
|
{ $self->{$f} = [TTF_Unpack("$type$arrlen", substr($dat, $pos))]; } |
89
|
|
|
|
|
|
|
else |
90
|
1130
|
|
|
|
|
2636
|
{ $self->{$f} = TTF_Unpack("$type", substr($dat, $pos)); } |
91
|
|
|
|
|
|
|
} |
92
|
198
|
|
|
|
|
531
|
$self; |
93
|
|
|
|
|
|
|
} |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
=head2 TTF_Unpack($fmt, $dat) |
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
A TrueType types equivalent of Perls C function. Thus $fmt consists of |
99
|
|
|
|
|
|
|
type followed by an optional number of elements to read including *. The type |
100
|
|
|
|
|
|
|
may be one of: |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
c BYTE |
103
|
|
|
|
|
|
|
C CHAR |
104
|
|
|
|
|
|
|
f FIXED |
105
|
|
|
|
|
|
|
F F2DOT14 |
106
|
|
|
|
|
|
|
l LONG |
107
|
|
|
|
|
|
|
L ULONG |
108
|
|
|
|
|
|
|
s SHORT |
109
|
|
|
|
|
|
|
S USHORT |
110
|
|
|
|
|
|
|
v Version number (FIXED) |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
Note that C, C and C are not data types but units. |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
Returns array of scalar (first element) depending on context |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
=cut |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
sub TTF_Unpack |
119
|
|
|
|
|
|
|
{ |
120
|
2302
|
|
|
2302
|
1
|
4246
|
my ($fmt, $dat) = @_; |
121
|
2302
|
|
|
|
|
1808
|
my ($res, $frac, $i, $arrlen, $type, @res); |
122
|
|
|
|
|
|
|
|
123
|
2302
|
|
|
|
|
9592
|
while ($fmt =~ s/^([cflsv])(\d+|\*)?//oi) |
124
|
|
|
|
|
|
|
{ |
125
|
2302
|
|
|
|
|
3486
|
$type = $1; |
126
|
2302
|
|
|
|
|
2163
|
$arrlen = $2; |
127
|
2302
|
100
|
66
|
|
|
4656
|
$arrlen = 1 if !defined $arrlen || $arrlen eq ""; |
128
|
2302
|
100
|
|
|
|
3472
|
$arrlen = -1 if $arrlen eq "*"; |
129
|
|
|
|
|
|
|
|
130
|
2302
|
|
100
|
|
|
9815
|
for ($i = 0; ($arrlen == -1 && $dat ne "") || $i < $arrlen; $i++) |
|
|
|
100
|
|
|
|
|
131
|
|
|
|
|
|
|
{ |
132
|
2334
|
100
|
|
|
|
10089
|
if ($type eq "f") |
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
133
|
|
|
|
|
|
|
{ |
134
|
6
|
|
|
|
|
15
|
($res, $frac) = unpack("nn", $dat); |
135
|
6
|
|
|
|
|
12
|
substr($dat, 0, 4) = ""; |
136
|
6
|
50
|
|
|
|
16
|
$res -= 65536 if $res > 32767; |
137
|
6
|
|
|
|
|
14
|
$res += $frac / 65536.; |
138
|
|
|
|
|
|
|
} |
139
|
|
|
|
|
|
|
elsif ($type eq "v") |
140
|
|
|
|
|
|
|
{ |
141
|
6
|
|
|
|
|
19
|
($res, $frac) = unpack("nn", $dat); |
142
|
6
|
|
|
|
|
15
|
substr($dat, 0, 4) = ""; |
143
|
6
|
50
|
|
|
|
13
|
$res -= 65536 if $res > 32767; |
144
|
6
|
|
|
|
|
29
|
$res = sprintf("%d.%X", $res, $frac); |
145
|
|
|
|
|
|
|
} |
146
|
|
|
|
|
|
|
elsif ($type eq "F") |
147
|
|
|
|
|
|
|
{ |
148
|
0
|
|
|
|
|
0
|
$res = unpack("n", $dat); |
149
|
0
|
|
|
|
|
0
|
substr($dat, 0, 2) = ""; |
150
|
|
|
|
|
|
|
# $res -= 65536 if $res >= 32768; |
151
|
0
|
|
|
|
|
0
|
$frac = $res & 0x3fff; |
152
|
0
|
|
|
|
|
0
|
$res >>= 14; |
153
|
0
|
0
|
|
|
|
0
|
$res -= 4 if $res > 1; |
154
|
|
|
|
|
|
|
# $frac -= 16384 if $frac > 8191; |
155
|
0
|
|
|
|
|
0
|
$res += $frac / 16384.; |
156
|
|
|
|
|
|
|
} |
157
|
|
|
|
|
|
|
elsif ($type =~ m/^[l]/oi) |
158
|
|
|
|
|
|
|
{ |
159
|
36
|
|
|
|
|
58
|
$res = unpack("N", $dat); |
160
|
36
|
|
|
|
|
50
|
substr($dat, 0, 4) = ""; |
161
|
36
|
50
|
33
|
|
|
80
|
$res -= (1 << 32) if ($type eq "l" && $res >= 1 << 31); |
162
|
|
|
|
|
|
|
} |
163
|
|
|
|
|
|
|
elsif ($type =~ m/^[s]/oi) |
164
|
|
|
|
|
|
|
{ |
165
|
2266
|
|
|
|
|
3460
|
$res = unpack("n", $dat); |
166
|
2266
|
|
|
|
|
2721
|
substr($dat, 0, 2) = ""; |
167
|
2266
|
100
|
100
|
|
|
7338
|
$res -= 65536 if ($type eq "s" && $res >= 32768); |
168
|
|
|
|
|
|
|
} |
169
|
|
|
|
|
|
|
elsif ($type eq "c") |
170
|
|
|
|
|
|
|
{ |
171
|
0
|
|
|
|
|
0
|
$res = unpack("c", $dat); |
172
|
0
|
|
|
|
|
0
|
substr($dat, 0, 1) = ""; |
173
|
|
|
|
|
|
|
} |
174
|
|
|
|
|
|
|
else |
175
|
|
|
|
|
|
|
{ |
176
|
20
|
|
|
|
|
39
|
$res = unpack("C", $dat); |
177
|
20
|
|
|
|
|
33
|
substr($dat, 0, 1) = ""; |
178
|
|
|
|
|
|
|
} |
179
|
2334
|
|
|
|
|
11915
|
push (@res, $res); |
180
|
|
|
|
|
|
|
} |
181
|
|
|
|
|
|
|
} |
182
|
2302
|
100
|
|
|
|
7946
|
return wantarray ? @res : $res[0]; |
183
|
|
|
|
|
|
|
} |
184
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
=head2 $dat = TTF_Out_Fields($obj, $fields, $len) |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
Given the fields table from C writes out the instance variables from |
189
|
|
|
|
|
|
|
the object to the filehandle in TTF binary form. |
190
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
=cut |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
sub TTF_Out_Fields |
194
|
|
|
|
|
|
|
{ |
195
|
10
|
|
|
10
|
1
|
19
|
my ($obj, $fields, $len) = @_; |
196
|
10
|
|
|
|
|
38
|
my ($dat) = "\000" x $len; |
197
|
10
|
|
|
|
|
20
|
my ($f, $pos, $type, $res, $arr, $arrlen, $frac); |
198
|
|
|
|
|
|
|
|
199
|
10
|
|
|
|
|
15
|
foreach $f (keys %{$fields}) |
|
10
|
|
|
|
|
93
|
|
200
|
|
|
|
|
|
|
{ |
201
|
194
|
|
|
|
|
699
|
($pos, $type, $arrlen) = split(':', $fields->{$f}); |
202
|
194
|
100
|
|
|
|
365
|
if ($arrlen ne "") |
203
|
4
|
|
|
|
|
8
|
{ $res = TTF_Pack("$type$arrlen", @{$obj->{$f}}); } |
|
4
|
|
|
|
|
16
|
|
204
|
|
|
|
|
|
|
else |
205
|
190
|
|
|
|
|
454
|
{ $res = TTF_Pack("$type", $obj->{$f}); } |
206
|
194
|
|
|
|
|
514
|
substr($dat, $pos, length($res)) = $res; |
207
|
|
|
|
|
|
|
} |
208
|
10
|
|
|
|
|
76
|
$dat; |
209
|
|
|
|
|
|
|
} |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
=head2 $dat = TTF_Pack($fmt, @data) |
213
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
The TrueType equivalent to Perl's C function. See details of C |
215
|
|
|
|
|
|
|
for how to work the $fmt string. |
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
=cut |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
sub TTF_Pack |
220
|
|
|
|
|
|
|
{ |
221
|
196
|
|
|
196
|
1
|
313
|
my ($fmt, @obj) = @_; |
222
|
196
|
|
|
|
|
169
|
my ($type, $i, $arrlen, $dat, $res, $frac); |
223
|
|
|
|
|
|
|
|
224
|
196
|
|
|
|
|
183
|
$dat = ''; |
225
|
196
|
|
|
|
|
920
|
while ($fmt =~ s/^([flscv])(\d+|\*)?//oi) |
226
|
|
|
|
|
|
|
{ |
227
|
196
|
|
|
|
|
379
|
$type = $1; |
228
|
196
|
|
100
|
|
|
672
|
$arrlen = $2 || ""; |
229
|
196
|
50
|
|
|
|
362
|
$arrlen = $#obj + 1 if $arrlen eq "*"; |
230
|
196
|
100
|
|
|
|
326
|
$arrlen = 1 if $arrlen eq ""; |
231
|
|
|
|
|
|
|
|
232
|
196
|
|
|
|
|
366
|
for ($i = 0; $i < $arrlen; $i++) |
233
|
|
|
|
|
|
|
{ |
234
|
200
|
|
100
|
|
|
445
|
$res = shift(@obj) || 0; |
235
|
200
|
100
|
|
|
|
958
|
if ($type eq "f") |
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
236
|
|
|
|
|
|
|
{ |
237
|
6
|
|
|
|
|
25
|
$frac = int(($res - int($res)) * 65536); |
238
|
6
|
|
|
|
|
10
|
$res = (int($res) << 16) + $frac; |
239
|
6
|
|
|
|
|
26
|
$dat .= pack("N", $res); |
240
|
|
|
|
|
|
|
} |
241
|
|
|
|
|
|
|
elsif ($type eq "v") |
242
|
|
|
|
|
|
|
{ |
243
|
6
|
50
|
|
|
|
43
|
if ($res =~ s/\.(\d+)$//o) |
244
|
|
|
|
|
|
|
{ |
245
|
6
|
|
|
|
|
11
|
$frac = $1; |
246
|
6
|
|
|
|
|
21
|
$frac .= "0" x (4 - length($frac)); |
247
|
|
|
|
|
|
|
} |
248
|
|
|
|
|
|
|
else |
249
|
0
|
|
|
|
|
0
|
{ $frac = 0; } |
250
|
6
|
|
|
|
|
41
|
$dat .= pack('nn', $res, hex($frac)); |
251
|
|
|
|
|
|
|
} |
252
|
|
|
|
|
|
|
elsif ($type eq "F") |
253
|
|
|
|
|
|
|
{ |
254
|
0
|
|
|
|
|
0
|
$frac = int(($res - int($res)) * 16384); |
255
|
0
|
|
|
|
|
0
|
$res = (int($res) << 14) + $frac; |
256
|
0
|
|
|
|
|
0
|
$dat .= pack("n", $res); |
257
|
|
|
|
|
|
|
} |
258
|
|
|
|
|
|
|
elsif ($type =~ m/^[l]/oi) |
259
|
|
|
|
|
|
|
{ |
260
|
36
|
50
|
33
|
|
|
194
|
$res += 1 << 32 if ($type eq 'L' && $res < 0); |
261
|
36
|
|
|
|
|
140
|
$dat .= pack("N", $res); |
262
|
|
|
|
|
|
|
} |
263
|
|
|
|
|
|
|
elsif ($type =~ m/^[s]/oi) |
264
|
|
|
|
|
|
|
{ |
265
|
132
|
50
|
66
|
|
|
388
|
$res += 1 << 16 if ($type eq 'S' && $res < 0); |
266
|
132
|
|
|
|
|
526
|
$dat .= pack("n", $res); |
267
|
|
|
|
|
|
|
} |
268
|
|
|
|
|
|
|
elsif ($type eq "c") |
269
|
0
|
|
|
|
|
0
|
{ $dat .= pack("c", $res); } |
270
|
|
|
|
|
|
|
else |
271
|
20
|
|
|
|
|
79
|
{ $dat .= pack("C", $res); } |
272
|
|
|
|
|
|
|
} |
273
|
|
|
|
|
|
|
} |
274
|
196
|
|
|
|
|
428
|
$dat; |
275
|
|
|
|
|
|
|
} |
276
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
=head2 ($num, $range, $select, $shift) = TTF_bininfo($num) |
279
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
Calculates binary search information from a number of elements |
281
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
=cut |
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
sub TTF_bininfo |
285
|
|
|
|
|
|
|
{ |
286
|
6
|
|
|
6
|
1
|
12
|
my ($num, $block) = @_; |
287
|
6
|
|
|
|
|
9
|
my ($range, $select, $shift); |
288
|
|
|
|
|
|
|
|
289
|
6
|
|
|
|
|
10
|
$range = 1; |
290
|
6
|
|
|
|
|
25
|
for ($select = 0; $range <= $num; $select++) |
291
|
16
|
|
|
|
|
33
|
{ $range *= 2; } |
292
|
6
|
|
|
|
|
8
|
$select--; $range /= 2; |
|
6
|
|
|
|
|
13
|
|
293
|
6
|
|
|
|
|
9
|
$range *= $block; |
294
|
|
|
|
|
|
|
|
295
|
6
|
|
|
|
|
13
|
$shift = $num * $block - $range; |
296
|
6
|
|
|
|
|
31
|
($num, $range, $select, $shift); |
297
|
|
|
|
|
|
|
} |
298
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
=head2 TTF_word_utf8($str) |
301
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
Returns the UTF8 form of the 16 bit string, assumed to be in big endian order, |
303
|
|
|
|
|
|
|
including surrogate handling |
304
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
=cut |
306
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
sub TTF_word_utf8 |
308
|
|
|
|
|
|
|
{ |
309
|
122
|
|
|
122
|
1
|
129
|
my ($str) = @_; |
310
|
122
|
|
|
|
|
92
|
my ($res, $i); |
311
|
122
|
|
|
|
|
2190
|
my (@dat) = unpack("n*", $str); |
312
|
|
|
|
|
|
|
|
313
|
122
|
50
|
|
|
|
1593
|
return pack("U*", @dat) if ($] >= 5.006); |
314
|
0
|
|
|
|
|
0
|
for ($i = 0; $i <= $#dat; $i++) |
315
|
|
|
|
|
|
|
{ |
316
|
0
|
|
|
|
|
0
|
my ($dat) = $dat[$i]; |
317
|
0
|
0
|
0
|
|
|
0
|
if ($dat < 0x80) # Thanks to Gisle Aas for some of his old code |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
318
|
0
|
|
|
|
|
0
|
{ $res .= chr($dat); } |
319
|
|
|
|
|
|
|
elsif ($dat < 0x800) |
320
|
0
|
|
|
|
|
0
|
{ $res .= chr(0xC0 | ($dat >> 6)) . chr(0x80 | ($dat & 0x3F)); } |
321
|
|
|
|
|
|
|
elsif ($dat >= 0xD800 && $dat < 0xDC00) |
322
|
|
|
|
|
|
|
{ |
323
|
0
|
|
|
|
|
0
|
my ($dat1) = $dat[++$i]; |
324
|
0
|
|
|
|
|
0
|
my ($top) = (($dat & 0x3C0) >> 6) + 1; |
325
|
0
|
|
|
|
|
0
|
$res .= chr(0xF0 | ($top >> 2)) |
326
|
|
|
|
|
|
|
. chr(0x80 | (($top & 1) << 4) | (($dat & 0x3C) >> 2)) |
327
|
|
|
|
|
|
|
. chr(0x80 | (($dat & 0x3) << 4) | (($dat1 & 0x3C0) >> 6)) |
328
|
|
|
|
|
|
|
. chr(0x80 | ($dat1 & 0x3F)); |
329
|
|
|
|
|
|
|
} else |
330
|
0
|
|
|
|
|
0
|
{ $res .= chr(0xE0 | ($dat >> 12)) . chr(0x80 | (($dat >> 6) & 0x3F)) |
331
|
|
|
|
|
|
|
. chr(0x80 | ($dat & 0x3F)); } |
332
|
|
|
|
|
|
|
} |
333
|
0
|
|
|
|
|
0
|
$res; |
334
|
|
|
|
|
|
|
} |
335
|
|
|
|
|
|
|
|
336
|
|
|
|
|
|
|
|
337
|
|
|
|
|
|
|
=head2 TTF_utf8_word($str) |
338
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
Returns the 16-bit form in big endian order of the UTF 8 string, including |
340
|
|
|
|
|
|
|
surrogate handling to Unicode. |
341
|
|
|
|
|
|
|
|
342
|
|
|
|
|
|
|
=cut |
343
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
sub TTF_utf8_word |
345
|
|
|
|
|
|
|
{ |
346
|
122
|
|
|
122
|
1
|
172
|
my ($str) = @_; |
347
|
122
|
|
|
|
|
138
|
my ($res); |
348
|
|
|
|
|
|
|
|
349
|
122
|
50
|
|
|
|
4381
|
return pack("n*", unpack("U*", $str)) if ($^V ge v5.6.0); |
350
|
0
|
|
|
|
|
|
$str = "$str"; # copy $str |
351
|
0
|
|
|
|
|
|
while (length($str)) # Thanks to Gisle Aas for some of his old code |
352
|
|
|
|
|
|
|
{ |
353
|
0
|
|
|
|
|
|
$str =~ s/^[\x80-\xBF]+//o; |
354
|
0
|
0
|
|
|
|
|
if ($str =~ s/^([\x00-\x7F]+)//o) |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
355
|
0
|
|
|
|
|
|
{ $res .= pack("n*", unpack("C*", $1)); } |
356
|
|
|
|
|
|
|
elsif ($str =~ s/^([\xC0-\xDF])([\x80-\xBF])//o) |
357
|
0
|
|
|
|
|
|
{ $res .= pack("n", ((ord($1) & 0x1F) << 6) | (ord($2) & 0x3F)); } |
358
|
|
|
|
|
|
|
elsif ($str =~ s/^([\0xE0-\xEF])([\x80-\xBF])([\x80-\xBF])//o) |
359
|
0
|
|
|
|
|
|
{ $res .= pack("n", ((ord($1) & 0x0F) << 12) |
360
|
|
|
|
|
|
|
| ((ord($2) & 0x3F) << 6) |
361
|
|
|
|
|
|
|
| (ord($3) & 0x3F)); } |
362
|
|
|
|
|
|
|
elsif ($str =~ s/^([\xF0-\xF7])([\x80-\xBF])([\x80-\xBF])([\x80-\xBF])//o) |
363
|
|
|
|
|
|
|
{ |
364
|
0
|
|
|
|
|
|
my ($b1, $b2, $b3, $b4) = (ord($1), ord($2), ord($3), ord($4)); |
365
|
0
|
|
|
|
|
|
$res .= pack("n", ((($b1 & 0x07) << 8) | (($b2 & 0x3F) << 2) |
366
|
|
|
|
|
|
|
| (($b3 & 0x30) >> 4)) + 0xD600); # account for offset |
367
|
0
|
|
|
|
|
|
$res .= pack("n", ((($b3 & 0x0F) << 6) | ($b4 & 0x3F)) + 0xDC00); |
368
|
|
|
|
|
|
|
} |
369
|
|
|
|
|
|
|
elsif ($str =~ s/^[\xF8-\xFF][\x80-\xBF]*//o) |
370
|
|
|
|
|
|
|
{ } |
371
|
|
|
|
|
|
|
} |
372
|
0
|
|
|
|
|
|
$res; |
373
|
|
|
|
|
|
|
} |
374
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
=head2 XML_hexdump($context, $dat) |
377
|
|
|
|
|
|
|
|
378
|
|
|
|
|
|
|
Dumps out the given data as a sequence of blocks each 16 bytes wide |
379
|
|
|
|
|
|
|
|
380
|
|
|
|
|
|
|
=cut |
381
|
|
|
|
|
|
|
|
382
|
|
|
|
|
|
|
sub XML_hexdump |
383
|
|
|
|
|
|
|
{ |
384
|
0
|
|
|
0
|
1
|
|
my ($context, $depth, $dat) = @_; |
385
|
0
|
|
|
|
|
|
my ($fh) = $context->{'fh'}; |
386
|
0
|
|
|
|
|
|
my ($i, $len, $out); |
387
|
|
|
|
|
|
|
|
388
|
0
|
|
|
|
|
|
$len = length($dat); |
389
|
0
|
|
|
|
|
|
for ($i = 0; $i < $len; $i += 16) |
390
|
|
|
|
|
|
|
{ |
391
|
0
|
|
|
|
|
|
$out = join(' ', map {sprintf("%02X", ord($_))} (split('', substr($dat, $i, 16)))); |
|
0
|
|
|
|
|
|
|
392
|
0
|
|
|
|
|
|
$fh->printf("%s%s\n", $depth, $i, $out); |
393
|
|
|
|
|
|
|
} |
394
|
|
|
|
|
|
|
} |
395
|
|
|
|
|
|
|
|
396
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
=head2 XML_outhints |
398
|
|
|
|
|
|
|
|
399
|
|
|
|
|
|
|
Converts a binary string of hinting code into a textual representation |
400
|
|
|
|
|
|
|
|
401
|
|
|
|
|
|
|
=cut |
402
|
|
|
|
|
|
|
|
403
|
|
|
|
|
|
|
{ |
404
|
|
|
|
|
|
|
my (@hints) = ( |
405
|
|
|
|
|
|
|
['SVTCA[0]'], ['SVTCA[1]'], ['SPVTCA[0]'], ['SPVTCA[1]'], ['SFVTCA[0]'], ['SFVTCA[1]'], ['SPVTL[0]'], ['SPVTL[1]'], |
406
|
|
|
|
|
|
|
['SFVTL[0]'], ['SFVTL[1]'], ['SPVFS'], ['SFVFS'], ['GPV'], ['GFV'], ['SVFTPV'], ['ISECT'], |
407
|
|
|
|
|
|
|
# 10 |
408
|
|
|
|
|
|
|
['SRP0'], ['SRP1'], ['SRP2'], ['SZP0'], ['SZP1'], ['SZP2'], ['SZPS'], ['SLOOP'], |
409
|
|
|
|
|
|
|
['RTG'], ['RTHG'], ['SMD'], ['ELSE'], ['JMPR'], ['SCVTCI'], ['SSWCI'], ['SSW'], |
410
|
|
|
|
|
|
|
# 20 |
411
|
|
|
|
|
|
|
['DUP'], ['POP'], ['CLEAR'], ['SWAP'], ['DEPTH'], ['CINDEX'], ['MINDEX'], ['ALIGNPTS'], |
412
|
|
|
|
|
|
|
[], ['UTP'], ['LOOPCALL'], ['CALL'], ['FDEF'], ['ENDF'], ['MDAP[0]'], ['MDAP[1]'], |
413
|
|
|
|
|
|
|
# 30 |
414
|
|
|
|
|
|
|
['IUP[0]'], ['IUP[1]'], ['SHP[0]'], ['SHP[1]'], ['SHC[0]'], ['SHC[1]'], ['SHZ[0]'], ['SHZ[1]'], |
415
|
|
|
|
|
|
|
['SHPIX'], ['IP'], ['MSIRP[0]'], ['MSIRP[1]'], ['ALIGNRP'], ['RTDG'], ['MIAP[0]'], ['MIAP[1]'], |
416
|
|
|
|
|
|
|
# 40 |
417
|
|
|
|
|
|
|
['NPUSHB', -1, 1], ['NPUSHW', -1, 2], ['WS', 0, 0], ['RS', 0, 0], ['WCVTP', 0, 0], ['RCVT', 0, 0], ['GC[0]'], ['GC[1]'], |
418
|
|
|
|
|
|
|
['SCFS'], ['MD[0]'], ['MD[1]'], ['MPPEM'], ['MPS'], ['FLIPON'], ['FLIPOFF'], ['DEBUG'], |
419
|
|
|
|
|
|
|
# 50 |
420
|
|
|
|
|
|
|
['LT'], ['LTEQ'], ['GT'], ['GTEQ'], ['EQ'], ['NEQ'], ['ODD'], ['EVEN'], |
421
|
|
|
|
|
|
|
['IF'], ['EIF'], ['AND'], ['OR'], ['NOT'], ['DELTAP1'], ['SDB'], ['SDS'], |
422
|
|
|
|
|
|
|
# 60 |
423
|
|
|
|
|
|
|
['ADD'], ['SUB'], ['DIV'], ['MULT'], ['ABS'], ['NEG'], ['FLOOR'], ['CEILING'], |
424
|
|
|
|
|
|
|
['ROUND[0]'], ['ROUND[1]'], ['ROUND[2]'], ['ROUND[3]'], ['NROUND[0]'], ['NROUND[1]'], ['NROUND[2]'], ['NROUND[3]'], |
425
|
|
|
|
|
|
|
# 70 |
426
|
|
|
|
|
|
|
['WCVTF'], ['DELTAP2'], ['DELTAP3'], ['DELTAC1'], ['DELTAC2'], ['DELTAC3'], ['SROUND'], ['S45ROUND'], |
427
|
|
|
|
|
|
|
['JROT'], ['JROF'], ['ROFF'], [], ['RUTG'], ['RDTG'], ['SANGW'], [], |
428
|
|
|
|
|
|
|
# 80 |
429
|
|
|
|
|
|
|
['FLIPPT'], ['FLIPRGON'], ['FLIPRGOFF'], [], [], ['SCANCTRL'], ['SDPVTL[0]'], ['SDPVTL[1]'], |
430
|
|
|
|
|
|
|
['GETINFO'], ['IDEF'], ['ROLL'], ['MAX'], ['MIN'], ['SCANTYPE'], ['INSTCTRL'], [], |
431
|
|
|
|
|
|
|
# 90 |
432
|
|
|
|
|
|
|
[], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], |
433
|
|
|
|
|
|
|
# A0 |
434
|
|
|
|
|
|
|
[], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], |
435
|
|
|
|
|
|
|
# B0 |
436
|
|
|
|
|
|
|
['PUSHB1', 1, 1], ['PUSHB2', 2, 1], ['PUSHB3', 3, 1], ['PUSHB4', 4, 1], ['PUSHB5', 5, 1], ['PUSHB6', 6, 1], ['PUSHB7', 7, 1], ['PUSHB8', 8, 1], |
437
|
|
|
|
|
|
|
['PUSHW1', 1, 2], ['PUSHW2', 2, 2], ['PUSHW3', 3, 2], ['PUSHW4', 4, 2], ['PUSHW5', 5, 2], ['PUSHW6', 6, 2], ['PUSHW7', 7, 2], ['PUSHW8', 8, 2], |
438
|
|
|
|
|
|
|
# C0 |
439
|
|
|
|
|
|
|
['MDRP[0]'], ['MDRP[1]'], ['MDRP[2]'], ['MDRP[3]'], ['MDRP[4]'], ['MDRP[5]'], ['MDRP[6]'], ['MDRP[7]'], |
440
|
|
|
|
|
|
|
['MDRP[8]'], ['MDRP[9]'], ['MDRP[A]'], ['MDRP[B]'], ['MDRP[C]'], ['MDRP[D]'], ['MDRP[E]'], ['MDRP[F]'], |
441
|
|
|
|
|
|
|
# D0 |
442
|
|
|
|
|
|
|
['MDRP[10]'], ['MDRP[11]'], ['MDRP[12]'], ['MDRP[13]'], ['MDRP[14]'], ['MDRP[15]'], ['MDRP[16]'], ['MDRP[17]'], |
443
|
|
|
|
|
|
|
['MDRP[18]'], ['MDRP[19]'], ['MDRP[1A]'], ['MDRP[1B]'], ['MDRP[1C]'], ['MDRP[1D]'], ['MDRP[1E]'], ['MDRP[1F]'], |
444
|
|
|
|
|
|
|
# E0 |
445
|
|
|
|
|
|
|
['MIRP[0]'], ['MIRP[1]'], ['MIRP[2]'], ['MIRP[3]'], ['MIRP[4]'], ['MIRP[5]'], ['MIRP[6]'], ['MIRP[7]'], |
446
|
|
|
|
|
|
|
['MIRP[8]'], ['MIRP[9]'], ['MIRP[A]'], ['MIRP[B]'], ['MIRP[C]'], ['MIRP[D]'], ['MIRP[E]'], ['MIRP[F]'], |
447
|
|
|
|
|
|
|
# F0 |
448
|
|
|
|
|
|
|
['MIRP[10]'], ['MIRP[11]'], ['MIRP[12]'], ['MIRP[13]'], ['MIRP[14]'], ['MIRP[15]'], ['MIRP[16]'], ['MIRP[17]'], |
449
|
|
|
|
|
|
|
['MIRP[18]'], ['MIRP[19]'], ['MIRP[1A]'], ['MIRP[1B]'], ['MIRP[1C]'], ['MIRP[1D]'], ['MIRP[1E]'], ['MIRP[1F]']); |
450
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
my ($i); |
452
|
|
|
|
|
|
|
my (%hints) = map { $_->[0] => $i++ if (defined $_->[0]); } @hints; |
453
|
|
|
|
|
|
|
|
454
|
|
|
|
|
|
|
sub XML_binhint |
455
|
|
|
|
|
|
|
{ |
456
|
0
|
|
|
0
|
0
|
|
my ($dat) = @_; |
457
|
0
|
|
|
|
|
|
my ($len) = length($dat); |
458
|
0
|
|
|
|
|
|
my ($res, $i, $text, $size, $num); |
459
|
|
|
|
|
|
|
|
460
|
0
|
|
|
|
|
|
for ($i = 0; $i < $len; $i++) |
461
|
|
|
|
|
|
|
{ |
462
|
0
|
|
|
|
|
|
($text, $num, $size) = @{$hints[ord(substr($dat, $i, 1))]}; |
|
0
|
|
|
|
|
|
|
463
|
0
|
0
|
|
|
|
|
$num = 0 unless (defined $num); |
464
|
0
|
0
|
|
|
|
|
$text = sprintf("UNK[%02X]", ord(substr($dat, $i, 1))) unless defined $text; |
465
|
0
|
|
|
|
|
|
$res .= $text; |
466
|
0
|
0
|
|
|
|
|
if ($num != 0) |
467
|
|
|
|
|
|
|
{ |
468
|
0
|
0
|
|
|
|
|
if ($num < 0) |
469
|
|
|
|
|
|
|
{ |
470
|
0
|
|
|
|
|
|
$i++; |
471
|
0
|
0
|
|
|
|
|
my ($nnum) = unpack($num == -1 ? 'C' : 'n', substr($dat, $i, -$num)); |
472
|
0
|
|
|
|
|
|
$i += -$num - 1; |
473
|
0
|
|
|
|
|
|
$num = $nnum; |
474
|
|
|
|
|
|
|
} |
475
|
0
|
0
|
|
|
|
|
$res .= "\t" . join(' ', unpack($size == 1 ? 'C*' : 'n*', substr($dat, $i + 1, $num * $size))); |
476
|
0
|
|
|
|
|
|
$i += $num * $size; |
477
|
|
|
|
|
|
|
} |
478
|
0
|
|
|
|
|
|
$res .= "\n"; |
479
|
|
|
|
|
|
|
} |
480
|
0
|
|
|
|
|
|
$res; |
481
|
|
|
|
|
|
|
} |
482
|
|
|
|
|
|
|
|
483
|
|
|
|
|
|
|
sub XML_hintbin |
484
|
|
|
|
|
|
|
{ |
485
|
0
|
|
|
0
|
0
|
|
my ($dat) = @_; |
486
|
0
|
|
|
|
|
|
my ($l, $res, @words, $num); |
487
|
|
|
|
|
|
|
|
488
|
0
|
|
|
|
|
|
foreach $l (split(/\s*\n\s*/, $dat)) |
489
|
|
|
|
|
|
|
{ |
490
|
0
|
|
|
|
|
|
@words = split(/\s*/, $l); |
491
|
0
|
0
|
|
|
|
|
next unless (defined $hints{$words[0]}); |
492
|
0
|
|
|
|
|
|
$num = $hints{$words[0]}; |
493
|
0
|
|
|
|
|
|
$res .= pack('C', $num); |
494
|
0
|
0
|
|
|
|
|
if ($hints[$num][1] < 0) |
|
|
0
|
|
|
|
|
|
495
|
|
|
|
|
|
|
{ |
496
|
0
|
0
|
|
|
|
|
$res .= pack($hints[$num][1] == -1 ? 'C' : 'n', $#words); |
497
|
0
|
0
|
|
|
|
|
$res .= pack($hints[$num][2] == 1 ? 'C*' : 'n*', @words[1 .. $#words]); |
498
|
|
|
|
|
|
|
} |
499
|
|
|
|
|
|
|
elsif ($hints[$num][1] > 0) |
500
|
|
|
|
|
|
|
{ |
501
|
0
|
0
|
|
|
|
|
$res .= pack($hints[$num][2] == 1 ? 'C*' : 'n*', @words[1 .. $hints[$num][1]]); |
502
|
|
|
|
|
|
|
} |
503
|
|
|
|
|
|
|
} |
504
|
0
|
|
|
|
|
|
$res; |
505
|
|
|
|
|
|
|
} |
506
|
|
|
|
|
|
|
} |
507
|
|
|
|
|
|
|
|
508
|
|
|
|
|
|
|
|
509
|
|
|
|
|
|
|
=head2 make_circle($f, $cmap, [$dia, $sb, $opts]) |
510
|
|
|
|
|
|
|
|
511
|
|
|
|
|
|
|
Adds a dotted circle to a font. This function is very configurable. The |
512
|
|
|
|
|
|
|
parameters passed in are: |
513
|
|
|
|
|
|
|
|
514
|
|
|
|
|
|
|
=over 4 |
515
|
|
|
|
|
|
|
|
516
|
|
|
|
|
|
|
=item $f |
517
|
|
|
|
|
|
|
|
518
|
|
|
|
|
|
|
Font to work with. This is required. |
519
|
|
|
|
|
|
|
|
520
|
|
|
|
|
|
|
=item $cmap |
521
|
|
|
|
|
|
|
|
522
|
|
|
|
|
|
|
A cmap table (not the 'val' sub-element of a cmap) to add the glyph too. Optional. |
523
|
|
|
|
|
|
|
|
524
|
|
|
|
|
|
|
=item $dia |
525
|
|
|
|
|
|
|
|
526
|
|
|
|
|
|
|
Optional diameter for the main circle. Defaults to 80% em |
527
|
|
|
|
|
|
|
|
528
|
|
|
|
|
|
|
=item $sb |
529
|
|
|
|
|
|
|
|
530
|
|
|
|
|
|
|
Side bearing. The left and right side-bearings are always the same. This value |
531
|
|
|
|
|
|
|
defaults to 10% em. |
532
|
|
|
|
|
|
|
|
533
|
|
|
|
|
|
|
=back |
534
|
|
|
|
|
|
|
|
535
|
|
|
|
|
|
|
There are various options to control all sorts of interesting aspects of the circle |
536
|
|
|
|
|
|
|
|
537
|
|
|
|
|
|
|
=over 4 |
538
|
|
|
|
|
|
|
|
539
|
|
|
|
|
|
|
=item numDots |
540
|
|
|
|
|
|
|
|
541
|
|
|
|
|
|
|
Number of dots in the circle |
542
|
|
|
|
|
|
|
|
543
|
|
|
|
|
|
|
=item numPoints |
544
|
|
|
|
|
|
|
|
545
|
|
|
|
|
|
|
Number of curve points to use to create each dot |
546
|
|
|
|
|
|
|
|
547
|
|
|
|
|
|
|
=item uid |
548
|
|
|
|
|
|
|
|
549
|
|
|
|
|
|
|
Unicode reference to store this glyph under in the cmap. Defaults to 0x25CC |
550
|
|
|
|
|
|
|
|
551
|
|
|
|
|
|
|
=item pname |
552
|
|
|
|
|
|
|
|
553
|
|
|
|
|
|
|
Postscript name to give the glyph. Defaults to uni25CC. |
554
|
|
|
|
|
|
|
|
555
|
|
|
|
|
|
|
=item -dRadius |
556
|
|
|
|
|
|
|
|
557
|
|
|
|
|
|
|
Radius of each dot. |
558
|
|
|
|
|
|
|
|
559
|
|
|
|
|
|
|
=back |
560
|
|
|
|
|
|
|
|
561
|
|
|
|
|
|
|
=cut |
562
|
|
|
|
|
|
|
|
563
|
|
|
|
|
|
|
sub make_circle |
564
|
|
|
|
|
|
|
{ |
565
|
0
|
|
|
0
|
1
|
|
my ($font, $cmap, $dia, $sb, %opts) = @_; |
566
|
0
|
|
|
|
|
|
my ($upem) = $font->{'head'}{'unitsPerEm'}; |
567
|
0
|
|
|
|
|
|
my ($glyph) = Font::TTF::Glyph->new('PARENT' => $font, 'read' => 2, 'isDirty' => 1); |
568
|
0
|
|
|
|
|
|
my ($PI) = 3.1415926535; |
569
|
0
|
|
|
|
|
|
my ($R, $r, $xorg, $yorg); |
570
|
0
|
|
|
|
|
|
my ($i, $j, $numg, $maxp); |
571
|
0
|
|
0
|
|
|
|
my ($numc) = $opts{'-numDots'} || 16; |
572
|
0
|
|
0
|
|
|
|
my ($nump) = ($opts{'-numPoints'} * 2) || 8; |
573
|
0
|
|
0
|
|
|
|
my ($uid) = $opts{'-uid'} || 0x25CC; |
574
|
0
|
|
0
|
|
|
|
my ($pname) = $opts{'-pname'} || 'uni25CC'; |
575
|
|
|
|
|
|
|
|
576
|
0
|
|
0
|
|
|
|
$dia ||= $upem * .8; # .95 to fit exactly |
577
|
0
|
|
0
|
|
|
|
$sb ||= $upem * .1; |
578
|
0
|
|
|
|
|
|
$R = $dia / 2; |
579
|
0
|
|
0
|
|
|
|
$r = $opts{'-dRadius'} || ($R * .1); |
580
|
0
|
|
|
|
|
|
($xorg, $yorg) = ($R + $r, $R); |
581
|
|
|
|
|
|
|
|
582
|
0
|
|
|
|
|
|
$xorg += $sb; |
583
|
0
|
|
|
|
|
|
$font->{'post'}->read; |
584
|
0
|
|
|
|
|
|
$font->{'glyf'}->read; |
585
|
0
|
|
|
|
|
|
for ($i = 0; $i < $numc; $i++) |
586
|
|
|
|
|
|
|
{ |
587
|
0
|
|
|
|
|
|
my ($pxorg, $pyorg) = ($xorg + $R * cos(2 * $PI * $i / $numc), |
588
|
|
|
|
|
|
|
$yorg + $R * sin(2 * $PI * $i / $numc)); |
589
|
0
|
|
|
|
|
|
for ($j = 0; $j < $nump; $j++) |
590
|
|
|
|
|
|
|
{ |
591
|
0
|
0
|
|
|
|
|
push (@{$glyph->{'x'}}, int ($pxorg + ($j & 1 ? 1/cos(2*$PI/$nump) : 1) * $r * cos(2 * $PI * $j / $nump))); |
|
0
|
|
|
|
|
|
|
592
|
0
|
0
|
|
|
|
|
push (@{$glyph->{'y'}}, int ($pyorg + ($j & 1 ? 1/cos(2*$PI/$nump) : 1) * $r * sin(2 * $PI * $j / $nump))); |
|
0
|
|
|
|
|
|
|
593
|
0
|
0
|
|
|
|
|
push (@{$glyph->{'flags'}}, $j & 1 ? 0 : 1); |
|
0
|
|
|
|
|
|
|
594
|
|
|
|
|
|
|
} |
595
|
0
|
|
|
|
|
|
push (@{$glyph->{'endPoints'}}, $#{$glyph->{'x'}}); |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
596
|
|
|
|
|
|
|
} |
597
|
0
|
|
|
|
|
|
$glyph->{'numberOfContours'} = $#{$glyph->{'endPoints'}} + 1; |
|
0
|
|
|
|
|
|
|
598
|
0
|
|
|
|
|
|
$glyph->{'numPoints'} = $#{$glyph->{'x'}} + 1; |
|
0
|
|
|
|
|
|
|
599
|
0
|
|
|
|
|
|
$glyph->update; |
600
|
0
|
|
|
|
|
|
$numg = $font->{'maxp'}{'numGlyphs'}; |
601
|
0
|
|
|
|
|
|
$font->{'maxp'}{'numGlyphs'}++; |
602
|
|
|
|
|
|
|
|
603
|
0
|
|
|
|
|
|
$font->{'hmtx'}{'advance'}[$numg] = int($xorg + $R + $r + $sb + .5); |
604
|
0
|
|
|
|
|
|
$font->{'hmtx'}{'lsb'}[$numg] = int($xorg - $R - $r + .5); |
605
|
0
|
|
|
|
|
|
$font->{'loca'}{'glyphs'}[$numg] = $glyph; |
606
|
0
|
0
|
|
|
|
|
$cmap->{'val'}{$uid} = $numg if ($cmap); |
607
|
0
|
|
|
|
|
|
$font->{'post'}{'VAL'}[$numg] = $pname; |
608
|
0
|
|
|
|
|
|
delete $font->{'hdmx'}; |
609
|
0
|
|
|
|
|
|
delete $font->{'VDMX'}; |
610
|
0
|
|
|
|
|
|
delete $font->{'LTSH'}; |
611
|
|
|
|
|
|
|
|
612
|
0
|
|
|
0
|
|
|
$font->tables_do(sub {$_[0]->dirty;}); |
|
0
|
|
|
|
|
|
|
613
|
0
|
|
|
|
|
|
$font->update; |
614
|
0
|
|
|
|
|
|
return ($numg - 1); |
615
|
|
|
|
|
|
|
} |
616
|
|
|
|
|
|
|
|
617
|
|
|
|
|
|
|
|
618
|
|
|
|
|
|
|
1; |
619
|
|
|
|
|
|
|
|
620
|
|
|
|
|
|
|
=head1 BUGS |
621
|
|
|
|
|
|
|
|
622
|
|
|
|
|
|
|
No known bugs |
623
|
|
|
|
|
|
|
|
624
|
|
|
|
|
|
|
=head1 AUTHOR |
625
|
|
|
|
|
|
|
|
626
|
|
|
|
|
|
|
Martin Hosken L. |
627
|
|
|
|
|
|
|
|
628
|
|
|
|
|
|
|
|
629
|
|
|
|
|
|
|
=head1 LICENSING |
630
|
|
|
|
|
|
|
|
631
|
|
|
|
|
|
|
Copyright (c) 1998-2014, SIL International (http://www.sil.org) |
632
|
|
|
|
|
|
|
|
633
|
|
|
|
|
|
|
This module is released under the terms of the Artistic License 2.0. |
634
|
|
|
|
|
|
|
For details, see the full text of the license in the file LICENSE. |
635
|
|
|
|
|
|
|
|
636
|
|
|
|
|
|
|
|
637
|
|
|
|
|
|
|
|
638
|
|
|
|
|
|
|
=cut |
639
|
|
|
|
|
|
|
|
640
|
|
|
|
|
|
|
|