font-ttf.lua /size: 57 Kb    last modification: 2020-07-01 14:35
1
if
not
modules
then
modules
=
{
}
end
modules
[
'
font-ttf
'
]
=
{
2
version
=
1
.
001
,
3
comment
=
"
companion to font-ini.mkiv
"
,
4
author
=
"
Hans Hagen, PRAGMA-ADE, Hasselt NL
"
,
5
copyright
=
"
PRAGMA ADE / ConTeXt Development Team
"
,
6
license
=
"
see context related readme files
"
7
}
8 9
-- This version is different from previous in the sense that we no longer store
10
-- contours but keep points and contours (endpoints) separate for a while
11
-- because later on we need to apply deltas and that is easier on a list of
12
-- points.
13 14
-- The code is a bit messy. I looked at the ff code but it's messy too. It has
15
-- to do with the fact that we need to look at points on the curve and control
16
-- points in between. This also means that we start at point 2 and have to look
17
-- at point 1 when we're at the end. We still use a ps like storage with the
18
-- operator last in an entry. It's typical code that evolves stepwise till a
19
-- point of no comprehension.
20 21
-- For deltas we need a rather complex loop over points that can have holes and
22
-- be less than nofpoints and even can have duplicates and also the x and y value
23
-- lists can be shorter than etc. I need fonts in order to complete this simply
24
-- because I need to visualize in order to understand (what the standard tries
25
-- to explain).
26 27
-- 0 point then none applied
28
-- 1 points then applied to all
29
-- otherwise inferred deltas using nearest
30
-- if no lower point then use highest referenced point
31
-- if no higher point then use lowest referenced point
32
-- factor = (target-left)/(right-left)
33
-- delta = (1-factor)*left + factor * right
34 35
local
next
,
type
,
unpack
=
next
,
type
,
unpack
36
local
band
,
rshift
=
bit32
.
band
,
bit32
.
rshift
37
local
sqrt
,
round
=
math
.
sqrt
,
math
.
round
38
local
char
,
rep
=
string
.
char
,
string
.
rep
39
local
concat
=
table
.
concat
40
local
idiv
=
number
.
idiv
41
local
setmetatableindex
=
table
.
setmetatableindex
42 43
local
report
=
logs
.
reporter
(
"
otf reader
"
,
"
ttf
"
)
44 45
local
trace_deltas
=
false
46 47
local
readers
=
fonts
.
handlers
.
otf
.
readers
48
local
streamreader
=
readers
.
streamreader
49 50
local
setposition
=
streamreader
.
setposition
51
local
getposition
=
streamreader
.
getposition
52
local
skipbytes
=
streamreader
.
skip
53
local
readbyte
=
streamreader
.
readcardinal1
-- 8-bit unsigned integer
54
local
readushort
=
streamreader
.
readcardinal2
-- 16-bit unsigned integer
55
local
readulong
=
streamreader
.
readcardinal4
-- 24-bit unsigned integer
56
local
readchar
=
streamreader
.
readinteger1
-- 8-bit signed integer
57
local
readshort
=
streamreader
.
readinteger2
-- 16-bit signed integer
58
local
read2dot14
=
streamreader
.
read2dot14
-- 16-bit signed fixed number with the low 14 bits of fraction (2.14) (F2DOT14)
59
local
readinteger
=
streamreader
.
readinteger1
60
local
readcardinaltable
=
streamreader
.
readcardinaltable
61
local
readintegertable
=
streamreader
.
readintegertable
62 63
directives
.
register
(
"
fonts.streamreader
"
,
function
(
)
64 65
streamreader
=
utilities
.
streams
66 67
setposition
=
streamreader
.
setposition
68
getposition
=
streamreader
.
getposition
69
skipbytes
=
streamreader
.
skip
70
readbyte
=
streamreader
.
readcardinal1
71
readushort
=
streamreader
.
readcardinal2
72
readulong
=
streamreader
.
readcardinal4
73
readchar
=
streamreader
.
readinteger1
74
readshort
=
streamreader
.
readinteger2
75
read2dot14
=
streamreader
.
read2dot14
76
readinteger
=
streamreader
.
readinteger1
77
readcardinaltable
=
streamreader
.
readcardinaltable
78
readintegertable
=
streamreader
.
readintegertable
79 80
end
)
81 82
local
short
=
2
83
local
ushort
=
2
84
local
ulong
=
4
85 86
local
helpers
=
readers
.
helpers
87
local
gotodatatable
=
helpers
.
gotodatatable
88 89
local
function
mergecomposites
(
glyphs
,
shapes
)
90 91
-- todo : deltas
92 93
local
function
merge
(
index
,
shape
,
components
)
94
local
contours
=
{
}
95
local
points
=
{
}
96
local
nofcontours
=
0
97
local
nofpoints
=
0
98
local
offset
=
0
99
local
deltas
=
shape
.
deltas
100
for
i
=
1
,
#
components
do
101
local
component
=
components
[
i
]
102
local
subindex
=
component
.
index
103
local
subshape
=
shapes
[
subindex
]
104
local
subcontours
=
subshape
.
contours
105
local
subpoints
=
subshape
.
points
106
if
not
subcontours
then
107
local
subcomponents
=
subshape
.
components
108
if
subcomponents
then
109
subcontours
,
subpoints
=
merge
(
subindex
,
subshape
,
subcomponents
)
110
end
111
end
112
if
subpoints
then
113
local
matrix
=
component
.
matrix
114
local
xscale
=
matrix
[
1
]
115
local
xrotate
=
matrix
[
2
]
116
local
yrotate
=
matrix
[
3
]
117
local
yscale
=
matrix
[
4
]
118
local
xoffset
=
matrix
[
5
]
119
local
yoffset
=
matrix
[
6
]
120
local
count
=
#
subpoints
121
if
xscale
=
=
1
and
yscale
=
=
1
and
xrotate
=
=
0
and
yrotate
=
=
0
then
122
for
i
=
1
,
count
do
123
local
p
=
subpoints
[
i
]
124
nofpoints
=
nofpoints
+
1
125
points
[
nofpoints
]
=
{
126
p
[
1
]
+
xoffset
,
127
p
[
2
]
+
yoffset
,
128
p
[
3
]
129
}
130
end
131
else
132
for
i
=
1
,
count
do
133
local
p
=
subpoints
[
i
]
134
local
x
=
p
[
1
]
135
local
y
=
p
[
2
]
136
nofpoints
=
nofpoints
+
1
137
points
[
nofpoints
]
=
{
138
xscale
*
x
+
xrotate
*
y
+
xoffset
,
139
yscale
*
y
+
yrotate
*
x
+
yoffset
,
140
p
[
3
]
141
}
142
end
143
end
144
local
subcount
=
#
subcontours
145
if
subcount
=
=
1
then
146
nofcontours
=
nofcontours
+
1
147
contours
[
nofcontours
]
=
offset
+
subcontours
[
1
]
148
else
149
for
i
=
1
,
#
subcontours
do
150
nofcontours
=
nofcontours
+
1
151
contours
[
nofcontours
]
=
offset
+
subcontours
[
i
]
152
end
153
end
154
offset
=
offset
+
count
155
else
156
report
(
"
missing contours composite %s, component %s of %s, glyph %s
"
,
index
,
i
,
#
components
,
subindex
)
157
end
158
end
159
shape
.
points
=
points
-- todo : phantom points
160
shape
.
contours
=
contours
161
shape
.
components
=
nil
162
return
contours
,
points
163
end
164 165
-- for index=1,#glyphs do
166
for
index
=
0
,
#
glyphs
-1
do
167
local
shape
=
shapes
[
index
]
168
if
shape
then
169
local
components
=
shape
.
components
170
if
components
then
171
merge
(
index
,
shape
,
components
)
172
end
173
end
174
end
175 176
end
177 178
local
function
readnothing
(
f
)
179
return
{
180
type
=
"
nothing
"
,
181
}
182
end
183 184
-- begin of converter
185 186
local
function
curveto
(
m_x
,
m_y
,
l_x
,
l_y
,
r_x
,
r_y
)
-- todo: inline this
187
return
188
l_x
+
2
/
3
*
(
m_x
-
l_x
)
,
l_y
+
2
/
3
*
(
m_y
-
l_y
)
,
189
r_x
+
2
/
3
*
(
m_x
-
r_x
)
,
r_y
+
2
/
3
*
(
m_y
-
r_y
)
,
190
r_x
,
r_y
,
"
c
"
191
end
192 193
-- We could omit the operator which saves some 10%:
194
--
195
-- #2=lineto #4=quadratic #6=cubic #3=moveto (with "m")
196
--
197
-- This is tricky ... something to do with phantom points .. however, the hvar
198
-- and vvar tables should take care of the width .. the test font doesn't have
199
-- those so here we go then (we need a flag for hvar).
200
--
201
-- h-advance left-side-bearing v-advance top-side-bearing
202
--
203
-- We had two loops (going backward) but can do it in one loop .. but maybe we
204
-- should only accept fonts with proper hvar tables.
205 206
local
function
applyaxis
(
glyph
,
shape
,
deltas
,
dowidth
)
207
local
points
=
shape
.
points
208
if
points
then
209
local
nofpoints
=
#
points
210
local
h
=
nofpoints
+
2
-- weird, the example font seems to have left first
211
local
l
=
nofpoints
+
1
212
----- v = nofpoints + 3
213
----- t = nofpoints + 4
214
local
dw
=
0
215
local
dl
=
0
216
for
i
=
1
,
#
deltas
do
217
local
deltaset
=
deltas
[
i
]
218
local
xvalues
=
deltaset
.
xvalues
219
local
yvalues
=
deltaset
.
yvalues
220
local
dpoints
=
deltaset
.
points
221
local
factor
=
deltaset
.
factor
222
if
dpoints
then
223
-- todo: interpolate
224
local
nofdpoints
=
#
dpoints
225
for
i
=
1
,
nofdpoints
do
226
local
d
=
dpoints
[
i
]
227
local
p
=
points
[
d
]
228
if
p
then
229
if
xvalues
then
230
local
x
=
xvalues
[
i
]
231
if
x
and
x
~
=
0
then
232
p
[
1
]
=
p
[
1
]
+
factor
*
x
233
end
234
end
235
if
yvalues
then
236
local
y
=
yvalues
[
i
]
237
if
y
and
y
~
=
0
then
238
p
[
2
]
=
p
[
2
]
+
factor
*
y
239
end
240
end
241
elseif
dowidth
then
242
-- we've now ran into phantom points which is a bit fuzzy because:
243
-- are there gaps in there?
244
--
245
-- todo: move this outside the loop (when we can be sure of all 4 being there)
246
if
d
=
=
h
then
247
-- we have a phantom point hadvance
248
local
x
=
xvalues
[
i
]
249
if
x
then
250
dw
=
dw
+
factor
*
x
251
end
252
elseif
d
=
=
l
then
253
local
x
=
xvalues
[
i
]
254
if
x
then
255
dl
=
dl
+
factor
*
x
256
end
257
end
258
end
259
end
260
else
261
for
i
=
1
,
nofpoints
do
262
local
p
=
points
[
i
]
263
if
xvalues
then
264
local
x
=
xvalues
[
i
]
265
if
x
and
x
~
=
0
then
266
p
[
1
]
=
p
[
1
]
+
factor
*
x
267
end
268
end
269
if
yvalues
then
270
local
y
=
yvalues
[
i
]
271
if
y
and
y
~
=
0
then
272
p
[
2
]
=
p
[
2
]
+
factor
*
y
273
end
274
end
275
end
276
if
dowidth
then
277
local
x
=
xvalues
[
h
]
278
if
x
then
279
dw
=
dw
+
factor
*
x
280
end
281
local
x
=
xvalues
[
l
]
282
if
x
then
283
dl
=
dl
+
factor
*
x
284
end
285
end
286
end
287
end
288
-- for i=1,nofpoints do
289
-- local p = points[i]
290
-- p[1] = round(p[1])
291
-- p[2] = round(p[2])
292
-- end
293
if
dowidth
then
294
local
width
=
glyph
.
width
or
0
295
-- local lsb = glyph.lsb or 0
296
glyph
.
width
=
width
+
dw
-
dl
297
end
298
else
299
report
(
"
no points for glyph %a
"
,
glyph
.
name
)
300
end
301
end
302 303
-- round or not ?
304 305
-- local quadratic = true -- both methods work, todo: install a directive
306
local
quadratic
=
false
307 308
local
function
contours2outlines_normal
(
glyphs
,
shapes
)
-- maybe accept the bbox overhead
309
-- for index=1,#glyphs do
310
for
index
=
0
,
#
glyphs
-1
do
311
local
shape
=
shapes
[
index
]
312
if
shape
then
313
local
glyph
=
glyphs
[
index
]
314
local
contours
=
shape
.
contours
315
local
points
=
shape
.
points
316
if
contours
then
317
local
nofcontours
=
#
contours
318
local
segments
=
{
}
319
local
nofsegments
=
0
320
glyph
.
segments
=
segments
321
if
nofcontours
>
0
then
322
local
px
=
0
323
local
py
=
0
324
local
first
=
1
325
for
i
=
1
,
nofcontours
do
326
local
last
=
contours
[
i
]
327
if
last
>
=
first
then
328
local
first_pt
=
points
[
first
]
329
local
first_on
=
first_pt
[
3
]
330
-- todo no new tables but reuse lineto and quadratic
331
if
first
=
=
last
then
332
first_pt
[
3
]
=
"
m
"
-- "moveto"
333
nofsegments
=
nofsegments
+
1
334
segments
[
nofsegments
]
=
first_pt
335
else
-- maybe also treat n == 2 special
336
local
first_on
=
first_pt
[
3
]
337
local
last_pt
=
points
[
last
]
338
local
last_on
=
last_pt
[
3
]
339
local
start
=
1
340
local
control_pt
=
false
341
if
first_on
then
342
start
=
2
343
else
344
if
last_on
then
345
first_pt
=
last_pt
346
else
347
first_pt
=
{
(
first_pt
[
1
]
+
last_pt
[
1
]
)
/
2
,
(
first_pt
[
2
]
+
last_pt
[
2
]
)
/
2
,
false
}
348
end
349
control_pt
=
first_pt
350
end
351
local
x
=
first_pt
[
1
]
352
local
y
=
first_pt
[
2
]
353
if
not
done
then
354
xmin
=
x
355
ymin
=
y
356
xmax
=
x
357
ymax
=
y
358
done
=
true
359
end
360
nofsegments
=
nofsegments
+
1
361
segments
[
nofsegments
]
=
{
x
,
y
,
"
m
"
}
-- "moveto"
362
if
not
quadratic
then
363
px
=
x
364
py
=
y
365
end
366
local
previous_pt
=
first_pt
367
for
i
=
first
,
last
do
368
local
current_pt
=
points
[
i
]
369
local
current_on
=
current_pt
[
3
]
370
local
previous_on
=
previous_pt
[
3
]
371
if
previous_on
then
372
if
current_on
then
373
-- both normal points
374
local
x
,
y
=
current_pt
[
1
]
,
current_pt
[
2
]
375
nofsegments
=
nofsegments
+
1
376
segments
[
nofsegments
]
=
{
x
,
y
,
"
l
"
}
-- "lineto"
377
if
not
quadratic
then
378
px
,
py
=
x
,
y
379
end
380
else
381
control_pt
=
current_pt
382
end
383
elseif
current_on
then
384
local
x1
=
control_pt
[
1
]
385
local
y1
=
control_pt
[
2
]
386
local
x2
=
current_pt
[
1
]
387
local
y2
=
current_pt
[
2
]
388
nofsegments
=
nofsegments
+
1
389
if
quadratic
then
390
segments
[
nofsegments
]
=
{
x1
,
y1
,
x2
,
y2
,
"
q
"
}
-- "quadraticto"
391
else
392
x1
,
y1
,
x2
,
y2
,
px
,
py
=
curveto
(
x1
,
y1
,
px
,
py
,
x2
,
y2
)
393
segments
[
nofsegments
]
=
{
x1
,
y1
,
x2
,
y2
,
px
,
py
,
"
c
"
}
-- "curveto"
394
end
395
control_pt
=
false
396
else
397
local
x2
=
(
previous_pt
[
1
]
+
current_pt
[
1
]
)
/
2
398
local
y2
=
(
previous_pt
[
2
]
+
current_pt
[
2
]
)
/
2
399
local
x1
=
control_pt
[
1
]
400
local
y1
=
control_pt
[
2
]
401
nofsegments
=
nofsegments
+
1
402
if
quadratic
then
403
segments
[
nofsegments
]
=
{
x1
,
y1
,
x2
,
y2
,
"
q
"
}
-- "quadraticto"
404
else
405
x1
,
y1
,
x2
,
y2
,
px
,
py
=
curveto
(
x1
,
y1
,
px
,
py
,
x2
,
y2
)
406
segments
[
nofsegments
]
=
{
x1
,
y1
,
x2
,
y2
,
px
,
py
,
"
c
"
}
-- "curveto"
407
end
408
control_pt
=
current_pt
409
end
410
previous_pt
=
current_pt
411
end
412
if
first_pt
=
=
last_pt
then
413
-- we're already done, probably a simple curve
414
else
415
nofsegments
=
nofsegments
+
1
416
local
x2
=
first_pt
[
1
]
417
local
y2
=
first_pt
[
2
]
418
if
not
control_pt
then
419
segments
[
nofsegments
]
=
{
x2
,
y2
,
"
l
"
}
-- "lineto"
420
elseif
quadratic
then
421
local
x1
=
control_pt
[
1
]
422
local
y1
=
control_pt
[
2
]
423
segments
[
nofsegments
]
=
{
x1
,
y1
,
x2
,
y2
,
"
q
"
}
-- "quadraticto"
424
else
425
local
x1
=
control_pt
[
1
]
426
local
y1
=
control_pt
[
2
]
427
x1
,
y1
,
x2
,
y2
,
px
,
py
=
curveto
(
x1
,
y1
,
px
,
py
,
x2
,
y2
)
428
segments
[
nofsegments
]
=
{
x1
,
y1
,
x2
,
y2
,
px
,
py
,
"
c
"
}
-- "curveto"
429
-- px, py = x2, y2
430
end
431
end
432
end
433
end
434
first
=
last
+
1
435
end
436
end
437
end
438
end
439
end
440
end
441 442
local
function
contours2outlines_shaped
(
glyphs
,
shapes
,
keepcurve
)
443
-- for index=1,#glyphs do
444
for
index
=
0
,
#
glyphs
-1
do
445
local
shape
=
shapes
[
index
]
446
if
shape
then
447
local
glyph
=
glyphs
[
index
]
448
local
contours
=
shape
.
contours
449
local
points
=
shape
.
points
450
if
contours
then
451
local
nofcontours
=
#
contours
452
local
segments
=
keepcurve
and
{
}
or
nil
453
local
nofsegments
=
0
454
if
keepcurve
then
455
glyph
.
segments
=
segments
456
end
457
if
nofcontours
>
0
then
458
local
xmin
,
ymin
,
xmax
,
ymax
,
done
=
0
,
0
,
0
,
0
,
false
459
local
px
,
py
=
0
,
0
-- we could use these in calculations which saves a copy
460
local
first
=
1
461
for
i
=
1
,
nofcontours
do
462
local
last
=
contours
[
i
]
463
if
last
>
=
first
then
464
local
first_pt
=
points
[
first
]
465
local
first_on
=
first_pt
[
3
]
466
-- todo no new tables but reuse lineto and quadratic
467
if
first
=
=
last
then
468
-- this can influence the boundingbox
469
if
keepcurve
then
470
first_pt
[
3
]
=
"
m
"
-- "moveto"
471
nofsegments
=
nofsegments
+
1
472
segments
[
nofsegments
]
=
first_pt
473
end
474
else
-- maybe also treat n == 2 special
475
local
first_on
=
first_pt
[
3
]
476
local
last_pt
=
points
[
last
]
477
local
last_on
=
last_pt
[
3
]
478
local
start
=
1
479
local
control_pt
=
false
480
if
first_on
then
481
start
=
2
482
else
483
if
last_on
then
484
first_pt
=
last_pt
485
else
486
first_pt
=
{
(
first_pt
[
1
]
+
last_pt
[
1
]
)
/
2
,
(
first_pt
[
2
]
+
last_pt
[
2
]
)
/
2
,
false
}
487
end
488
control_pt
=
first_pt
489
end
490
local
x
=
first_pt
[
1
]
491
local
y
=
first_pt
[
2
]
492
if
not
done
then
493
xmin
,
ymin
,
xmax
,
ymax
=
x
,
y
,
x
,
y
494
done
=
true
495
else
496
if
x
<
xmin
then
xmin
=
x
elseif
x
>
xmax
then
xmax
=
x
end
497
if
y
<
ymin
then
ymin
=
y
elseif
y
>
ymax
then
ymax
=
y
end
498
end
499
if
keepcurve
then
500
nofsegments
=
nofsegments
+
1
501
segments
[
nofsegments
]
=
{
x
,
y
,
"
m
"
}
-- "moveto"
502
end
503
if
not
quadratic
then
504
px
=
x
505
py
=
y
506
end
507
local
previous_pt
=
first_pt
508
for
i
=
first
,
last
do
509
local
current_pt
=
points
[
i
]
510
local
current_on
=
current_pt
[
3
]
511
local
previous_on
=
previous_pt
[
3
]
512
if
previous_on
then
513
if
current_on
then
514
-- both normal points
515
local
x
=
current_pt
[
1
]
516
local
y
=
current_pt
[
2
]
517
if
x
<
xmin
then
xmin
=
x
elseif
x
>
xmax
then
xmax
=
x
end
518
if
y
<
ymin
then
ymin
=
y
elseif
y
>
ymax
then
ymax
=
y
end
519
if
keepcurve
then
520
nofsegments
=
nofsegments
+
1
521
segments
[
nofsegments
]
=
{
x
,
y
,
"
l
"
}
-- "lineto"
522
end
523
if
not
quadratic
then
524
px
=
x
525
py
=
y
526
end
527
else
528
control_pt
=
current_pt
529
end
530
elseif
current_on
then
531
local
x1
=
control_pt
[
1
]
532
local
y1
=
control_pt
[
2
]
533
local
x2
=
current_pt
[
1
]
534
local
y2
=
current_pt
[
2
]
535
if
quadratic
then
536
if
x1
<
xmin
then
xmin
=
x1
elseif
x1
>
xmax
then
xmax
=
x1
end
537
if
y1
<
ymin
then
ymin
=
y1
elseif
y1
>
ymax
then
ymax
=
y1
end
538
if
keepcurve
then
539
nofsegments
=
nofsegments
+
1
540
segments
[
nofsegments
]
=
{
x1
,
y1
,
x2
,
y2
,
"
q
"
}
-- "quadraticto"
541
end
542
else
543
x1
,
y1
,
x2
,
y2
,
px
,
py
=
curveto
(
x1
,
y1
,
px
,
py
,
x2
,
y2
)
544
if
x1
<
xmin
then
xmin
=
x1
elseif
x1
>
xmax
then
xmax
=
x1
end
545
if
y1
<
ymin
then
ymin
=
y1
elseif
y1
>
ymax
then
ymax
=
y1
end
546
if
x2
<
xmin
then
xmin
=
x2
elseif
x2
>
xmax
then
xmax
=
x2
end
547
if
y2
<
ymin
then
ymin
=
y2
elseif
y2
>
ymax
then
ymax
=
y2
end
548
if
px
<
xmin
then
xmin
=
px
elseif
px
>
xmax
then
xmax
=
px
end
549
if
py
<
ymin
then
ymin
=
py
elseif
py
>
ymax
then
ymax
=
py
end
550
if
keepcurve
then
551
nofsegments
=
nofsegments
+
1
552
segments
[
nofsegments
]
=
{
x1
,
y1
,
x2
,
y2
,
px
,
py
,
"
c
"
}
-- "curveto"
553
end
554
end
555
control_pt
=
false
556
else
557
local
x2
=
(
previous_pt
[
1
]
+
current_pt
[
1
]
)
/
2
558
local
y2
=
(
previous_pt
[
2
]
+
current_pt
[
2
]
)
/
2
559
local
x1
=
control_pt
[
1
]
560
local
y1
=
control_pt
[
2
]
561
if
quadratic
then
562
if
x1
<
xmin
then
xmin
=
x1
elseif
x1
>
xmax
then
xmax
=
x1
end
563
if
y1
<
ymin
then
ymin
=
y1
elseif
y1
>
ymax
then
ymax
=
y1
end
564
if
keepcurve
then
565
nofsegments
=
nofsegments
+
1
566
segments
[
nofsegments
]
=
{
x1
,
y1
,
x2
,
y2
,
"
q
"
}
-- "quadraticto"
567
end
568
else
569
x1
,
y1
,
x2
,
y2
,
px
,
py
=
curveto
(
x1
,
y1
,
px
,
py
,
x2
,
y2
)
570
if
x1
<
xmin
then
xmin
=
x1
elseif
x1
>
xmax
then
xmax
=
x1
end
571
if
y1
<
ymin
then
ymin
=
y1
elseif
y1
>
ymax
then
ymax
=
y1
end
572
if
x2
<
xmin
then
xmin
=
x2
elseif
x2
>
xmax
then
xmax
=
x2
end
573
if
y2
<
ymin
then
ymin
=
y2
elseif
y2
>
ymax
then
ymax
=
y2
end
574
if
px
<
xmin
then
xmin
=
px
elseif
px
>
xmax
then
xmax
=
px
end
575
if
py
<
ymin
then
ymin
=
py
elseif
py
>
ymax
then
ymax
=
py
end
576
if
keepcurve
then
577
nofsegments
=
nofsegments
+
1
578
segments
[
nofsegments
]
=
{
x1
,
y1
,
x2
,
y2
,
px
,
py
,
"
c
"
}
-- "curveto"
579
end
580
end
581
control_pt
=
current_pt
582
end
583
previous_pt
=
current_pt
584
end
585
if
first_pt
=
=
last_pt
then
586
-- we're already done, probably a simple curve
587
elseif
not
control_pt
then
588
if
keepcurve
then
589
nofsegments
=
nofsegments
+
1
590
segments
[
nofsegments
]
=
{
first_pt
[
1
]
,
first_pt
[
2
]
,
"
l
"
}
-- "lineto"
591
end
592
else
593
local
x1
=
control_pt
[
1
]
594
local
y1
=
control_pt
[
2
]
595
local
x2
=
first_pt
[
1
]
596
local
y2
=
first_pt
[
2
]
597
if
x1
<
xmin
then
xmin
=
x1
elseif
x1
>
xmax
then
xmax
=
x1
end
598
if
y1
<
ymin
then
ymin
=
y1
elseif
y1
>
ymax
then
ymax
=
y1
end
599
if
quadratic
then
600
if
keepcurve
then
601
nofsegments
=
nofsegments
+
1
602
segments
[
nofsegments
]
=
{
x1
,
y1
,
x2
,
y2
,
"
q
"
}
-- "quadraticto"
603
end
604
else
605
x1
,
y1
,
x2
,
y2
,
px
,
py
=
curveto
(
x1
,
y1
,
px
,
py
,
x2
,
y2
)
606
if
x2
<
xmin
then
xmin
=
x2
elseif
x2
>
xmax
then
xmax
=
x2
end
607
if
y2
<
ymin
then
ymin
=
y2
elseif
y2
>
ymax
then
ymax
=
y2
end
608
if
px
<
xmin
then
xmin
=
px
elseif
px
>
xmax
then
xmax
=
px
end
609
if
py
<
ymin
then
ymin
=
py
elseif
py
>
ymax
then
ymax
=
py
end
610
if
keepcurve
then
611
nofsegments
=
nofsegments
+
1
612
segments
[
nofsegments
]
=
{
x1
,
y1
,
x2
,
y2
,
px
,
py
,
"
c
"
}
-- "curveto"
613
end
614
-- px, py = x2, y2
615
end
616
end
617
end
618
end
619
first
=
last
+
1
620
end
621
glyph
.
boundingbox
=
{
round
(
xmin
)
,
round
(
ymin
)
,
round
(
xmax
)
,
round
(
ymax
)
}
622
end
623
end
624
end
625
end
626
end
627 628
-- optimize for zero
629 630
local
c_zero
=
char
(
0
)
631
local
s_zero
=
char
(
0
,
0
)
632 633
-- local shorthash = setmetatableindex(function(t,k)
634
-- t[k] = char(band(rshift(k,8),0xFF),band(k,0xFF)) return t[k]
635
-- end)
636 637
local
function
toushort
(
n
)
638
return
char
(
band
(
rshift
(
n
,
8
)
,
0xFF
)
,
band
(
n
,
0xFF
)
)
639
-- return shorthash[n]
640
end
641 642
local
function
toshort
(
n
)
643
if
n
<
0
then
644
n
=
n
+
0x10000
645
end
646
return
char
(
band
(
rshift
(
n
,
8
)
,
0xFF
)
,
band
(
n
,
0xFF
)
)
647
-- return shorthash[n]
648
end
649 650
-- todo: we can reuse result, xpoints and ypoints
651 652
local
chars
=
setmetatableindex
(
function
(
t
,
k
)
653
for
i
=
0
,
255
do
local
v
=
char
(
i
)
t
[
i
]
=
v
end
return
t
[
k
]
654
end
)
655 656
local
function
repackpoints
(
glyphs
,
shapes
)
657
local
noboundingbox
=
{
0
,
0
,
0
,
0
}
658
local
result
=
{
}
-- reused
659
local
xpoints
=
{
}
-- reused
660
local
ypoints
=
{
}
-- reused
661
for
index
=
0
,
#
glyphs
-1
do
662
local
shape
=
shapes
[
index
]
663
if
shape
then
664
local
r
=
0
665
local
glyph
=
glyphs
[
index
]
666
local
contours
=
shape
.
contours
667
local
nofcontours
=
contours
and
#
contours
or
0
668
local
boundingbox
=
glyph
.
boundingbox
or
noboundingbox
669
r
=
r
+
1
result
[
r
]
=
toshort
(
nofcontours
)
670
r
=
r
+
1
result
[
r
]
=
toshort
(
boundingbox
[
1
]
)
-- xmin
671
r
=
r
+
1
result
[
r
]
=
toshort
(
boundingbox
[
2
]
)
-- ymin
672
r
=
r
+
1
result
[
r
]
=
toshort
(
boundingbox
[
3
]
)
-- xmax
673
r
=
r
+
1
result
[
r
]
=
toshort
(
boundingbox
[
4
]
)
-- ymax
674
if
nofcontours
>
0
then
675
for
i
=
1
,
nofcontours
do
676
r
=
r
+
1
result
[
r
]
=
toshort
(
contours
[
i
]
-1
)
677
end
678
r
=
r
+
1
result
[
r
]
=
s_zero
-- no instructions
679
local
points
=
shape
.
points
680
local
currentx
=
0
681
local
currenty
=
0
682
-- local xpoints = { }
683
-- local ypoints = { }
684
local
x
=
0
685
local
y
=
0
686
local
lastflag
=
nil
687
local
nofflags
=
0
688
for
i
=
1
,
#
points
do
689
local
pt
=
points
[
i
]
690
local
px
=
pt
[
1
]
691
local
py
=
pt
[
2
]
692
local
fl
=
pt
[
3
]
and
0x01
or
0x00
693
if
px
=
=
currentx
then
694
fl
=
fl
+
0x10
695
else
696
local
dx
=
round
(
px
-
currentx
)
697
x
=
x
+
1
698
if
dx
<
-255
or
dx
>
255
then
699
xpoints
[
x
]
=
toshort
(
dx
)
700
elseif
dx
<
0
then
701
fl
=
fl
+
0x02
702
-- xpoints[x] = char(-dx)
703
xpoints
[
x
]
=
chars
[
-
dx
]
704
elseif
dx
>
0
then
705
fl
=
fl
+
0x12
706
-- xpoints[x] = char(dx)
707
xpoints
[
x
]
=
chars
[
dx
]
708
else
709
fl
=
fl
+
0x02
710
xpoints
[
x
]
=
c_zero
711
end
712
end
713
if
py
=
=
currenty
then
714
fl
=
fl
+
0x20
715
else
716
local
dy
=
round
(
py
-
currenty
)
717
y
=
y
+
1
718
if
dy
<
-255
or
dy
>
255
then
719
ypoints
[
y
]
=
toshort
(
dy
)
720
elseif
dy
<
0
then
721
fl
=
fl
+
0x04
722
-- ypoints[y] = char(-dy)
723
ypoints
[
y
]
=
chars
[
-
dy
]
724
elseif
dy
>
0
then
725
fl
=
fl
+
0x24
726
-- ypoints[y] = char(dy)
727
ypoints
[
y
]
=
chars
[
dy
]
728
else
729
fl
=
fl
+
0x04
730
ypoints
[
y
]
=
c_zero
731
end
732
end
733
currentx
=
px
734
currenty
=
py
735
if
lastflag
=
=
fl
then
736
if
nofflags
=
=
255
then
737
-- This happens in koeieletters!
738
lastflag
=
lastflag
+
0x08
739
r
=
r
+
1
result
[
r
]
=
char
(
lastflag
,
nofflags
-1
)
740
nofflags
=
1
741
lastflag
=
fl
742
else
743
nofflags
=
nofflags
+
1
744
end
745
else
-- if > 255
746
if
nofflags
=
=
1
then
747
-- r = r + 1 result[r] = char(lastflag)
748
r
=
r
+
1
result
[
r
]
=
chars
[
lastflag
]
749
elseif
nofflags
=
=
2
then
750
r
=
r
+
1
result
[
r
]
=
char
(
lastflag
,
lastflag
)
751
elseif
nofflags
>
2
then
752
lastflag
=
lastflag
+
0x08
753
r
=
r
+
1
result
[
r
]
=
char
(
lastflag
,
nofflags
-1
)
754
end
755
nofflags
=
1
756
lastflag
=
fl
757
end
758
end
759
if
nofflags
=
=
1
then
760
-- r = r + 1 result[r] = char(lastflag)
761
r
=
r
+
1
result
[
r
]
=
chars
[
lastflag
]
762
elseif
nofflags
=
=
2
then
763
r
=
r
+
1
result
[
r
]
=
char
(
lastflag
,
lastflag
)
764
elseif
nofflags
>
2
then
765
lastflag
=
lastflag
+
0x08
766
r
=
r
+
1
result
[
r
]
=
char
(
lastflag
,
nofflags
-1
)
767
end
768
-- r = r + 1 result[r] = concat(xpoints)
769
-- r = r + 1 result[r] = concat(ypoints)
770
r
=
r
+
1
result
[
r
]
=
concat
(
xpoints
,
"
"
,
1
,
x
)
771
r
=
r
+
1
result
[
r
]
=
concat
(
ypoints
,
"
"
,
1
,
y
)
772
end
773
-- can be helper or delegated to user
774
local
stream
=
concat
(
result
,
"
"
,
1
,
r
)
775
local
length
=
#
stream
776
local
padding
=
idiv
(
length
+
3
,
4
)
*
4
-
length
777
if
padding
>
0
then
778
-- stream = stream .. rep("\0",padding) -- can be a repeater
779
if
padding
=
=
1
then
780
padding
=
"
\0
"
781
elseif
padding
=
=
2
then
782
padding
=
"
\0\0
"
783
else
784
padding
=
"
\0\0\0
"
785
end
786
padding
=
stream
.
.
padding
787
end
788
glyph
.
stream
=
stream
789
end
790
end
791
end
792 793
-- end of converter
794 795
local
flags
=
{
}
796 797
local
function
readglyph
(
f
,
nofcontours
)
-- read deltas here, saves space
798
local
points
=
{
}
799
-- local instructions = { }
800
local
contours
=
{
}
-- readintegertable(f,nofcontours,short)
801
for
i
=
1
,
nofcontours
do
802
contours
[
i
]
=
readshort
(
f
)
+
1
803
end
804
local
nofpoints
=
contours
[
nofcontours
]
805
local
nofinstructions
=
readushort
(
f
)
806
skipbytes
(
f
,
nofinstructions
)
807
-- because flags can repeat we don't know the amount ... in fact this is
808
-- not that efficient (small files but more mem)
809
local
i
=
1
810
while
i
<
=
nofpoints
do
811
local
flag
=
readbyte
(
f
)
812
flags
[
i
]
=
flag
813
if
band
(
flag
,
0x08
)
~
=
0
then
814
local
n
=
readbyte
(
f
)
815
if
n
=
=
1
then
816
i
=
i
+
1
817
flags
[
i
]
=
flag
818
else
819
for
j
=
1
,
n
do
820
i
=
i
+
1
821
flags
[
i
]
=
flag
822
end
823
end
824
end
825
i
=
i
+
1
826
end
827
-- first come the x coordinates, and next the y coordinates and they
828
-- can be repeated
829
local
x
=
0
830
for
i
=
1
,
nofpoints
do
831
local
flag
=
flags
[
i
]
832
-- local short = band(flag,0x04) ~= 0
833
-- local same = band(flag,0x20) ~= 0
834
if
band
(
flag
,
0x02
)
~
=
0
then
835
if
band
(
flag
,
0x10
)
~
=
0
then
836
x
=
x
+
readbyte
(
f
)
837
else
838
x
=
x
-
readbyte
(
f
)
839
end
840
elseif
band
(
flag
,
0x10
)
~
=
0
then
841
-- copy
842
else
843
x
=
x
+
readshort
(
f
)
844
end
845
points
[
i
]
=
{
x
,
0
,
band
(
flag
,
0x01
)
~
=
0
}
846
end
847
local
y
=
0
848
for
i
=
1
,
nofpoints
do
849
local
flag
=
flags
[
i
]
850
-- local short = band(flag,0x04) ~= 0
851
-- local same = band(flag,0x20) ~= 0
852
if
band
(
flag
,
0x04
)
~
=
0
then
853
if
band
(
flag
,
0x20
)
~
=
0
then
854
y
=
y
+
readbyte
(
f
)
855
else
856
y
=
y
-
readbyte
(
f
)
857
end
858
elseif
band
(
flag
,
0x20
)
~
=
0
then
859
-- copy
860
else
861
y
=
y
+
readshort
(
f
)
862
end
863
points
[
i
]
[
2
]
=
y
864
end
865
return
{
866
type
=
"
glyph
"
,
867
points
=
points
,
868
contours
=
contours
,
869
nofpoints
=
nofpoints
,
870
}
871
end
872 873
local
function
readcomposite
(
f
)
874
local
components
=
{
}
875
local
nofcomponents
=
0
876
local
instructions
=
false
877
while
true
do
878
local
flags
=
readushort
(
f
)
879
local
index
=
readushort
(
f
)
880
----- f_words = band(flags,0x0001) ~= 0
881
local
f_xyarg
=
band
(
flags
,
0x0002
)
~
=
0
882
----- f_round = band(flags,0x0006) ~= 0 -- 2 + 4
883
----- f_scale = band(flags,0x0008) ~= 0
884
----- f_reserved = band(flags,0x0010) ~= 0
885
----- f_more = band(flags,0x0020) ~= 0
886
----- f_xyscale = band(flags,0x0040) ~= 0
887
----- f_matrix = band(flags,0x0080) ~= 0
888
----- f_instruct = band(flags,0x0100) ~= 0
889
----- f_usemine = band(flags,0x0200) ~= 0
890
----- f_overlap = band(flags,0x0400) ~= 0
891
local
f_offset
=
band
(
flags
,
0x0800
)
~
=
0
892
----- f_uoffset = band(flags,0x1000) ~= 0
893
local
xscale
=
1
894
local
xrotate
=
0
895
local
yrotate
=
0
896
local
yscale
=
1
897
local
xoffset
=
0
898
local
yoffset
=
0
899
local
base
=
false
900
local
reference
=
false
901
if
f_xyarg
then
902
if
band
(
flags
,
0x0001
)
~
=
0
then
-- f_words
903
xoffset
=
readshort
(
f
)
904
yoffset
=
readshort
(
f
)
905
else
906
xoffset
=
readchar
(
f
)
-- signed byte, stupid name
907
yoffset
=
readchar
(
f
)
-- signed byte, stupid name
908
end
909
else
910
if
band
(
flags
,
0x0001
)
~
=
0
then
-- f_words
911
base
=
readshort
(
f
)
912
reference
=
readshort
(
f
)
913
else
914
base
=
readchar
(
f
)
-- signed byte, stupid name
915
reference
=
readchar
(
f
)
-- signed byte, stupid name
916
end
917
end
918
if
band
(
flags
,
0x0008
)
~
=
0
then
-- f_scale
919
xscale
=
read2dot14
(
f
)
920
yscale
=
xscale
921
if
f_xyarg
and
f_offset
then
922
xoffset
=
xoffset
*
xscale
923
yoffset
=
yoffset
*
yscale
924
end
925
elseif
band
(
flags
,
0x0040
)
~
=
0
then
-- f_xyscale
926
xscale
=
read2dot14
(
f
)
927
yscale
=
read2dot14
(
f
)
928
if
f_xyarg
and
f_offset
then
929
xoffset
=
xoffset
*
xscale
930
yoffset
=
yoffset
*
yscale
931
end
932
elseif
band
(
flags
,
0x0080
)
~
=
0
then
-- f_matrix
933
xscale
=
read2dot14
(
f
)
934
xrotate
=
read2dot14
(
f
)
935
yrotate
=
read2dot14
(
f
)
936
yscale
=
read2dot14
(
f
)
937
if
f_xyarg
and
f_offset
then
938
xoffset
=
xoffset
*
sqrt
(
xscale
^
2
+
xrotate
^
2
)
939
yoffset
=
yoffset
*
sqrt
(
yrotate
^
2
+
yscale
^
2
)
940
end
941
end
942
nofcomponents
=
nofcomponents
+
1
943
components
[
nofcomponents
]
=
{
944
index
=
index
,
945
usemine
=
band
(
flags
,
0x0200
)
~
=
0
,
-- f_usemine
946
round
=
band
(
flags
,
0x0006
)
~
=
0
,
-- f_round,
947
base
=
base
,
948
reference
=
reference
,
949
matrix
=
{
xscale
,
xrotate
,
yrotate
,
yscale
,
xoffset
,
yoffset
}
,
950
}
951
if
band
(
flags
,
0x0100
)
~
=
0
then
952
instructions
=
true
953
end
954
if
band
(
flags
,
0x0020
)
=
=
0
then
-- f_more
955
break
956
end
957
end
958
return
{
959
type
=
"
composite
"
,
960
components
=
components
,
961
}
962
end
963 964
-- function readers.cff(f,offset,glyphs,doshapes) -- false == no shapes (nil or true otherwise)
965 966
-- The glyf table depends on the loca table. We have one entry to much
967
-- in the locations table (the last one is a dummy) because we need to
968
-- calculate the size of a glyph blob from the delta, although we not
969
-- need it in our usage (yet). We can remove the locations table when
970
-- we're done (todo: cleanup finalizer).
971 972
function
readers
.
loca
(
f
,
fontdata
,
specification
)
973
if
specification
.
glyphs
then
974
local
datatable
=
fontdata
.
tables
.
loca
975
if
datatable
then
976
-- locations are relative to the glypdata table (glyf)
977
local
offset
=
fontdata
.
tables
.
glyf
.
offset
978
local
format
=
fontdata
.
fontheader
.
indextolocformat
979
local
profile
=
fontdata
.
maximumprofile
980
local
nofglyphs
=
profile
and
profile
.
nofglyphs
981
local
locations
=
{
}
982
setposition
(
f
,
datatable
.
offset
)
983
if
format
=
=
1
then
984
if
not
nofglyphs
then
985
nofglyphs
=
idiv
(
datatable
.
length
,
4
)
-
1
986
end
987
for
i
=
0
,
nofglyphs
do
988
locations
[
i
]
=
offset
+
readulong
(
f
)
989
end
990
fontdata
.
nofglyphs
=
nofglyphs
991
else
992
if
not
nofglyphs
then
993
nofglyphs
=
idiv
(
datatable
.
length
,
2
)
-
1
994
end
995
for
i
=
0
,
nofglyphs
do
996
locations
[
i
]
=
offset
+
readushort
(
f
)
*
2
997
end
998
end
999
fontdata
.
nofglyphs
=
nofglyphs
1000
fontdata
.
locations
=
locations
1001
end
1002
end
1003
end
1004 1005
function
readers
.
glyf
(
f
,
fontdata
,
specification
)
-- part goes to cff module
1006
local
tableoffset
=
gotodatatable
(
f
,
fontdata
,
"
glyf
"
,
specification
.
glyphs
)
1007
if
tableoffset
then
1008
local
locations
=
fontdata
.
locations
1009
if
locations
then
1010
local
glyphs
=
fontdata
.
glyphs
1011
local
nofglyphs
=
fontdata
.
nofglyphs
1012
local
filesize
=
fontdata
.
filesize
1013
local
nothing
=
{
0
,
0
,
0
,
0
}
1014
local
shapes
=
{
}
1015
local
loadshapes
=
specification
.
shapes
or
specification
.
instance
or
specification
.
streams
1016
for
index
=
0
,
nofglyphs
-1
do
1017
local
location
=
locations
[
index
]
1018
local
length
=
locations
[
index
+
1
]
-
location
1019
if
location
>
=
filesize
then
1020
report
(
"
discarding %s glyphs due to glyph location bug
"
,
nofglyphs
-
index
+
1
)
1021
fontdata
.
nofglyphs
=
index
-
1
1022
fontdata
.
badfont
=
true
1023
break
1024
elseif
length
>
0
then
1025
setposition
(
f
,
location
)
1026
local
nofcontours
=
readshort
(
f
)
1027
glyphs
[
index
]
.
boundingbox
=
{
1028
readshort
(
f
)
,
-- xmin
1029
readshort
(
f
)
,
-- ymin
1030
readshort
(
f
)
,
-- xmax
1031
readshort
(
f
)
,
-- ymax
1032
}
1033
if
not
loadshapes
then
1034
-- save space
1035
elseif
nofcontours
=
=
0
then
1036
shapes
[
index
]
=
readnothing
(
f
)
1037
elseif
nofcontours
>
0
then
1038
shapes
[
index
]
=
readglyph
(
f
,
nofcontours
)
1039
else
1040
shapes
[
index
]
=
readcomposite
(
f
,
nofcontours
)
1041
end
1042
else
1043
if
loadshapes
then
1044
shapes
[
index
]
=
readnothing
(
f
)
1045
end
1046
glyphs
[
index
]
.
boundingbox
=
nothing
1047
end
1048
end
1049
if
loadshapes
then
1050
if
readers
.
gvar
then
1051
readers
.
gvar
(
f
,
fontdata
,
specification
,
glyphs
,
shapes
)
1052
end
1053
mergecomposites
(
glyphs
,
shapes
)
1054
if
specification
.
instance
then
1055
if
specification
.
streams
then
1056
repackpoints
(
glyphs
,
shapes
)
1057
else
1058
contours2outlines_shaped
(
glyphs
,
shapes
,
specification
.
shapes
)
1059
end
1060
elseif
specification
.
shapes
then
1061
if
specification
.
streams
then
1062
repackpoints
(
glyphs
,
shapes
)
1063
else
1064
contours2outlines_normal
(
glyphs
,
shapes
)
1065
end
1066
elseif
specification
.
streams
then
1067
repackpoints
(
glyphs
,
shapes
)
1068
end
1069
end
1070
end
1071
end
1072
end
1073 1074
-- gvar is a bit crazy format and one can really wonder if the bit-jugling obscurity
1075
-- is still needed in these days .. cff is much nicer with these blends while the ttf
1076
-- coding variant looks quite horrible
1077 1078
local
function
readtuplerecord
(
f
,
nofaxis
)
1079
local
record
=
{
}
1080
for
i
=
1
,
nofaxis
do
1081
record
[
i
]
=
read2dot14
(
f
)
1082
end
1083
return
record
1084
end
1085 1086
-- (1) the first is a real point the rest deltas
1087
-- (2) points can be present more than once (multiple deltas then)
1088 1089
local
function
readpoints
(
f
)
1090
local
count
=
readbyte
(
f
)
1091
if
count
=
=
0
then
1092
-- second byte not used, deltas for all point numbers
1093
return
nil
,
0
-- todo
1094
else
1095
if
count
<
128
then
1096
-- no second byte, use count
1097
elseif
band
(
count
,
0x80
)
~
=
0
then
1098
count
=
band
(
count
,
0x7F
)
*
256
+
readbyte
(
f
)
1099
else
1100
-- bad news
1101
end
1102
local
points
=
{
}
1103
local
p
=
0
1104
local
n
=
1
-- indices
1105
while
p
<
count
do
1106
local
control
=
readbyte
(
f
)
1107
local
runreader
=
band
(
control
,
0x80
)
~
=
0
and
readushort
or
readbyte
1108
local
runlength
=
band
(
control
,
0x7F
)
1109
for
i
=
1
,
runlength
+
1
do
1110
n
=
n
+
runreader
(
f
)
1111
p
=
p
+
1
1112
points
[
p
]
=
n
1113
end
1114
end
1115
return
points
,
p
1116
end
1117
end
1118 1119
local
function
readdeltas
(
f
,
nofpoints
)
1120
local
deltas
=
{
}
1121
local
p
=
0
1122
local
z
=
0
1123
while
nofpoints
>
0
do
1124
local
control
=
readbyte
(
f
)
1125
if
not
control
then
1126
break
1127
end
1128
local
allzero
=
band
(
control
,
0x80
)
~
=
0
1129
local
runlength
=
band
(
control
,
0x3F
)
+
1
1130
if
allzero
then
1131
z
=
z
+
runlength
1132
else
1133
local
runreader
=
band
(
control
,
0x40
)
~
=
0
and
readshort
or
readinteger
1134
if
z
>
0
then
1135
for
i
=
1
,
z
do
1136
p
=
p
+
1
1137
deltas
[
p
]
=
0
1138
end
1139
z
=
0
1140
end
1141
for
i
=
1
,
runlength
do
1142
p
=
p
+
1
1143
deltas
[
p
]
=
runreader
(
f
)
1144
end
1145
end
1146
nofpoints
=
nofpoints
-
runlength
1147
end
1148
-- saves space
1149
-- if z > 0 then
1150
-- for i=1,z do
1151
-- p = p + 1
1152
-- deltas[p] = 0
1153
-- end
1154
-- end
1155
if
p
>
0
then
1156
-- forget about trailing zeros
1157
return
deltas
1158
else
1159
-- forget about all zeros
1160
end
1161
end
1162 1163
local
function
readdeltas
(
f
,
nofpoints
)
1164
local
deltas
=
{
}
1165
local
p
=
0
1166
while
nofpoints
>
0
do
1167
local
control
=
readbyte
(
f
)
1168
if
control
then
1169
local
allzero
=
band
(
control
,
0x80
)
~
=
0
1170
local
runlength
=
band
(
control
,
0x3F
)
+
1
1171
if
allzero
then
1172
for
i
=
1
,
runlength
do
1173
p
=
p
+
1
1174
deltas
[
p
]
=
0
1175
end
1176
else
1177
local
runreader
=
band
(
control
,
0x40
)
~
=
0
and
readshort
or
readinteger
1178
for
i
=
1
,
runlength
do
1179
p
=
p
+
1
1180
deltas
[
p
]
=
runreader
(
f
)
1181
end
1182
end
1183
nofpoints
=
nofpoints
-
runlength
1184
else
1185
-- it happens
1186
break
1187
end
1188
end
1189
-- saves space
1190
if
p
>
0
then
1191
return
deltas
1192
else
1193
-- forget about all zeros
1194
end
1195
end
1196 1197
function
readers
.
gvar
(
f
,
fontdata
,
specification
,
glyphdata
,
shapedata
)
1198
-- this is one of the messiest tables
1199
local
instance
=
specification
.
instance
1200
if
not
instance
then
1201
return
1202
end
1203
local
factors
=
specification
.
factors
1204
if
not
factors
then
1205
return
1206
end
1207
local
tableoffset
=
gotodatatable
(
f
,
fontdata
,
"
gvar
"
,
specification
.
variable
or
specification
.
shapes
)
1208
if
tableoffset
then
1209
local
version
=
readulong
(
f
)
-- 1.0
1210
local
nofaxis
=
readushort
(
f
)
1211
local
noftuples
=
readushort
(
f
)
1212
local
tupleoffset
=
tableoffset
+
readulong
(
f
)
1213
local
nofglyphs
=
readushort
(
f
)
1214
local
flags
=
readushort
(
f
)
1215
local
dataoffset
=
tableoffset
+
readulong
(
f
)
1216
local
data
=
{
}
1217
local
tuples
=
{
}
1218
local
glyphdata
=
fontdata
.
glyphs
1219
local
dowidth
=
not
fontdata
.
variabledata
.
hvarwidths
1220
-- there is one more offset (so that one can calculate the size i suppose)
1221
-- so we could test for overflows but we simply assume sane font files
1222
if
band
(
flags
,
0x0001
)
~
=
0
then
1223
for
i
=
1
,
nofglyphs
+
1
do
1224
data
[
i
]
=
dataoffset
+
readulong
(
f
)
1225
end
1226
else
1227
for
i
=
1
,
nofglyphs
+
1
do
1228
data
[
i
]
=
dataoffset
+
2
*
readushort
(
f
)
1229
end
1230
end
1231
--
1232
if
noftuples
>
0
then
1233
setposition
(
f
,
tupleoffset
)
1234
for
i
=
1
,
noftuples
do
1235
tuples
[
i
]
=
readtuplerecord
(
f
,
nofaxis
)
1236
end
1237
end
1238
local
nextoffset
=
false
1239
local
startoffset
=
data
[
1
]
1240
for
i
=
1
,
nofglyphs
do
-- hm one more cf spec
1241
nextoffset
=
data
[
i
+
1
]
1242
local
glyph
=
glyphdata
[
i
-1
]
1243
local
name
=
trace_deltas
and
glyph
.
name
1244
if
startoffset
=
=
nextoffset
then
1245
if
name
then
1246
report
(
"
no deltas for glyph %a
"
,
name
)
1247
end
1248
else
1249
local
shape
=
shapedata
[
i
-1
]
-- todo 0
1250
if
not
shape
then
1251
if
name
then
1252
report
(
"
no shape for glyph %a
"
,
name
)
1253
end
1254
else
1255
lastoffset
=
startoffset
1256
setposition
(
f
,
startoffset
)
1257
local
flags
=
readushort
(
f
)
1258
local
count
=
band
(
flags
,
0x0FFF
)
1259
local
offset
=
startoffset
+
readushort
(
f
)
-- to serialized
1260
local
deltas
=
{
}
1261
local
allpoints
=
(
shape
.
nofpoints
or
0
)
-- + 1
1262
local
shared
=
false
1263
local
nofshared
=
0
1264
if
band
(
flags
,
0x8000
)
~
=
0
then
-- has shared points
1265
-- go to the packed stream (get them once)
1266
local
current
=
getposition
(
f
)
1267
setposition
(
f
,
offset
)
1268
shared
,
nofshared
=
readpoints
(
f
)
1269
offset
=
getposition
(
f
)
1270
setposition
(
f
,
current
)
1271
-- and back to the table
1272
end
1273
for
j
=
1
,
count
do
1274
local
size
=
readushort
(
f
)
-- check
1275
local
flags
=
readushort
(
f
)
1276
local
index
=
band
(
flags
,
0x0FFF
)
1277
local
haspeak
=
band
(
flags
,
0x8000
)
~
=
0
1278
local
intermediate
=
band
(
flags
,
0x4000
)
~
=
0
1279
local
private
=
band
(
flags
,
0x2000
)
~
=
0
1280
local
peak
=
nil
1281
local
start
=
nil
1282
local
stop
=
nil
1283
local
xvalues
=
nil
1284
local
yvalues
=
nil
1285
local
points
=
shared
-- we default to shared
1286
local
nofpoints
=
nofshared
-- we default to shared
1287
-- local advance = 4
1288
if
haspeak
then
1289
peak
=
readtuplerecord
(
f
,
nofaxis
)
1290
-- advance = advance + 2*nofaxis
1291
else
1292
if
index
+
1
>
#
tuples
then
1293
report
(
"
error, bad tuple index
"
,
index
)
1294
end
1295
peak
=
tuples
[
index
+
1
]
-- hm, needs checking, only peak?
1296
end
1297
if
intermediate
then
1298
start
=
readtuplerecord
(
f
,
nofaxis
)
1299
stop
=
readtuplerecord
(
f
,
nofaxis
)
1300
-- advance = advance + 4*nofaxis
1301
end
1302
-- get the deltas
1303
if
size
>
0
then
1304
local
current
=
getposition
(
f
)
1305
-- goto the packed stream
1306
setposition
(
f
,
offset
)
1307
if
private
then
1308
points
,
nofpoints
=
readpoints
(
f
)
1309
end
-- else
1310
if
nofpoints
=
=
0
then
1311
nofpoints
=
allpoints
+
4
1312
end
1313
if
nofpoints
>
0
then
1314
-- a nice test is to do only one
1315
xvalues
=
readdeltas
(
f
,
nofpoints
)
1316
yvalues
=
readdeltas
(
f
,
nofpoints
)
1317
end
1318
-- resync offset
1319
offset
=
offset
+
size
1320
-- back to the table
1321
setposition
(
f
,
current
)
1322
end
1323
if
not
xvalues
and
not
yvalues
then
1324
points
=
nil
1325
end
1326
local
s
=
1
1327
for
i
=
1
,
nofaxis
do
1328
local
f
=
factors
[
i
]
1329
local
peak
=
peak
and
peak
[
i
]
or
0
1330
-- local start = start and start[i] or 0
1331
-- local stop = stop and stop [i] or 0
1332
local
start
=
start
and
start
[
i
]
or
(
peak
<
0
and
peak
or
0
)
1333
local
stop
=
stop
and
stop
[
i
]
or
(
peak
>
0
and
peak
or
0
)
1334
-- do we really need these tests ... can't we assume sane values
1335
if
start
>
peak
or
peak
>
stop
then
1336
-- * 1
1337
elseif
start
<
0
and
stop
>
0
and
peak
~
=
0
then
1338
-- * 1
1339
elseif
peak
=
=
0
then
1340
-- * 1
1341
elseif
f
<
start
or
f
>
stop
then
1342
-- * 0
1343
s
=
0
1344
break
1345
elseif
f
<
peak
then
1346
-- s = - s * (f - start) / (peak - start)
1347
s
=
s
*
(
f
-
start
)
/
(
peak
-
start
)
1348
elseif
f
>
peak
then
1349
s
=
s
*
(
stop
-
f
)
/
(
stop
-
peak
)
1350
else
1351
-- * 1
1352
end
1353
end
1354
if
s
=
=
0
then
1355
if
name
then
1356
report
(
"
no deltas applied for glyph %a
"
,
name
)
1357
end
1358
else
1359
deltas
[
#
deltas
+
1
]
=
{
1360
factor
=
s
,
1361
points
=
points
,
1362
xvalues
=
xvalues
,
1363
yvalues
=
yvalues
,
1364
}
1365
end
1366
end
1367
if
shape
.
type
=
=
"
glyph
"
then
1368
applyaxis
(
glyph
,
shape
,
deltas
,
dowidth
)
1369
else
1370
-- todo: args_are_xy_values mess .. i have to be really bored
1371
-- and motivated to deal with it
1372
shape
.
deltas
=
deltas
1373
end
1374
end
1375
end
1376
startoffset
=
nextoffset
1377
end
1378
end
1379
end
1380