font-one.lua /size: 30 Kb    last modification: 2021-10-28 13:50
1
if
not
modules
then
modules
=
{
}
end
modules
[
'
font-one
'
]
=
{
2
version
=
1
.
001
,
3
optimize
=
true
,
4
comment
=
"
companion to font-ini.mkiv
"
,
5
author
=
"
Hans Hagen, PRAGMA-ADE, Hasselt NL
"
,
6
copyright
=
"
PRAGMA ADE / ConTeXt Development Team
"
,
7
license
=
"
see context related readme files
"
8
}
9 10
--[[ldx-- 11<p>Some code may look a bit obscure but this has to do with the fact that we also use 12this code for testing and much code evolved in the transition from <l n='tfm'/> to 13<l n='afm'/> to <l n='otf'/>.</p> 14 15<p>The following code still has traces of intermediate font support where we handles 16font encodings. Eventually font encoding went away but we kept some code around in 17other modules.</p> 18 19<p>This version implements a node mode approach so that users can also more easily 20add features.</p> 21--ldx]]
--
22 23
local
fonts
,
logs
,
trackers
,
containers
,
resolvers
=
fonts
,
logs
,
trackers
,
containers
,
resolvers
24 25
local
next
,
type
,
tonumber
,
rawget
=
next
,
type
,
tonumber
,
rawget
26
local
match
,
gsub
=
string
.
match
,
string
.
gsub
27
local
abs
=
math
.
abs
28
local
P
,
S
,
R
,
Cmt
,
C
,
Ct
,
Cs
,
Carg
=
lpeg
.
P
,
lpeg
.
S
,
lpeg
.
R
,
lpeg
.
Cmt
,
lpeg
.
C
,
lpeg
.
Ct
,
lpeg
.
Cs
,
lpeg
.
Carg
29
local
lpegmatch
,
patterns
=
lpeg
.
match
,
lpeg
.
patterns
30
local
sortedhash
=
table
.
sortedhash
31 32
local
trace_features
=
false
trackers
.
register
(
"
afm.features
"
,
function
(
v
)
trace_features
=
v
end
)
33
local
trace_indexing
=
false
trackers
.
register
(
"
afm.indexing
"
,
function
(
v
)
trace_indexing
=
v
end
)
34
local
trace_loading
=
false
trackers
.
register
(
"
afm.loading
"
,
function
(
v
)
trace_loading
=
v
end
)
35
local
trace_defining
=
false
trackers
.
register
(
"
fonts.defining
"
,
function
(
v
)
trace_defining
=
v
end
)
36 37
local
report_afm
=
logs
.
reporter
(
"
fonts
"
,
"
afm loading
"
)
38 39
local
setmetatableindex
=
table
.
setmetatableindex
40
local
derivetable
=
table
.
derive
41 42
local
findbinfile
=
resolvers
.
findbinfile
43 44
local
privateoffset
=
fonts
.
constructors
and
fonts
.
constructors
.
privateoffset
or
0xF0000
-- 0x10FFFF
45 46
local
definers
=
fonts
.
definers
47
local
readers
=
fonts
.
readers
48
local
constructors
=
fonts
.
constructors
49 50
local
afm
=
constructors
.
handlers
.
afm
51
local
pfb
=
constructors
.
handlers
.
pfb
52
local
otf
=
fonts
.
handlers
.
otf
53 54
local
otfreaders
=
otf
.
readers
55
local
otfenhancers
=
otf
.
enhancers
56 57
local
afmfeatures
=
constructors
.
features
.
afm
58
local
registerafmfeature
=
afmfeatures
.
register
59 60
local
afmenhancers
=
constructors
.
enhancers
.
afm
61
local
registerafmenhancer
=
afmenhancers
.
register
62 63
afm
.
version
=
1
.
513
-- incrementing this number one up will force a re-cache
64
afm
.
cache
=
containers
.
define
(
"
fonts
"
,
"
one
"
,
afm
.
version
,
true
)
65
afm
.
autoprefixed
=
true
-- this will become false some day (catches texnansi-blabla.*)
66 67
afm
.
helpdata
=
{
}
-- set later on so no local for this
68
afm
.
syncspace
=
true
-- when true, nicer stretch values
69 70
local
overloads
=
fonts
.
mappings
.
overloads
71 72
local
applyruntimefixes
=
fonts
.
treatments
and
fonts
.
treatments
.
applyfixes
73 74
--[[ldx-- 75<p>We cache files. Caching is taken care of in the loader. We cheat a bit by adding 76ligatures and kern information to the afm derived data. That way we can set them faster 77when defining a font.</p> 78 79<p>We still keep the loading two phased: first we load the data in a traditional 80fashion and later we transform it to sequences. Then we apply some methods also 81used in opentype fonts (like <t>tlig</t>).</p> 82--ldx]]
--
83 84
function
afm
.
load
(
filename
)
85
filename
=
resolvers
.
findfile
(
filename
,
'
afm
'
)
or
"
"
86
if
filename
~
=
"
"
and
not
fonts
.
names
.
ignoredfile
(
filename
)
then
87
local
name
=
file
.
removesuffix
(
file
.
basename
(
filename
)
)
88
local
data
=
containers
.
read
(
afm
.
cache
,
name
)
89
local
attr
=
lfs
.
attributes
(
filename
)
90
local
size
=
attr
and
attr
.
size
or
0
91
local
time
=
attr
and
attr
.
modification
or
0
92
--
93
local
pfbfile
=
file
.
replacesuffix
(
name
,
"
pfb
"
)
94
local
pfbname
=
resolvers
.
findfile
(
pfbfile
,
"
pfb
"
)
or
"
"
95
if
pfbname
=
=
"
"
then
96
pfbname
=
resolvers
.
findfile
(
file
.
basename
(
pfbfile
)
,
"
pfb
"
)
or
"
"
97
end
98
local
pfbsize
=
0
99
local
pfbtime
=
0
100
if
pfbname
~
=
"
"
then
101
local
attr
=
lfs
.
attributes
(
pfbname
)
102
pfbsize
=
attr
.
size
or
0
103
pfbtime
=
attr
.
modification
or
0
104
end
105
if
not
data
or
data
.
size
~
=
size
or
data
.
time
~
=
time
or
data
.
pfbsize
~
=
pfbsize
or
data
.
pfbtime
~
=
pfbtime
then
106
report_afm
(
"
reading %a
"
,
filename
)
107
data
=
afm
.
readers
.
loadfont
(
filename
,
pfbname
)
108
if
data
then
109
afmenhancers
.
apply
(
data
,
filename
)
110
-- otfreaders.addunicodetable(data) -- only when not done yet
111
fonts
.
mappings
.
addtounicode
(
data
,
filename
)
112
otfreaders
.
stripredundant
(
data
)
113
-- otfreaders.extend(data)
114
otfreaders
.
pack
(
data
)
115
data
.
size
=
size
116
data
.
time
=
time
117
data
.
pfbsize
=
pfbsize
118
data
.
pfbtime
=
pfbtime
119
report_afm
(
"
saving %a in cache
"
,
name
)
120
-- data.resources.unicodes = nil -- consistent with otf but here we save not much
121
data
=
containers
.
write
(
afm
.
cache
,
name
,
data
)
122
data
=
containers
.
read
(
afm
.
cache
,
name
)
123
end
124
end
125
if
data
then
126
-- constructors.addcoreunicodes(unicodes)
127
otfreaders
.
unpack
(
data
)
128
otfreaders
.
expand
(
data
)
-- inline tables
129
otfreaders
.
addunicodetable
(
data
)
-- only when not done yet
130
otfenhancers
.
apply
(
data
,
filename
,
data
)
131
if
applyruntimefixes
then
132
applyruntimefixes
(
filename
,
data
)
133
end
134
end
135
return
data
136
end
137
end
138 139
-- we run a more advanced analyzer later on anyway
140 141
local
uparser
=
fonts
.
mappings
.
makenameparser
(
)
-- each time
142 143
local
function
enhance_unify_names
(
data
,
filename
)
144
local
unicodevector
=
fonts
.
encodings
.
agl
.
unicodes
-- loaded runtime in context
145
local
unicodes
=
{
}
146
local
names
=
{
}
147
local
private
=
data
.
private
or
privateoffset
148
local
descriptions
=
data
.
descriptions
149
for
name
,
blob
in
sortedhash
(
data
.
characters
)
do
-- sorting is nicer for privates
150
local
code
=
unicodevector
[
name
]
-- or characters.name_to_unicode[name]
151
if
not
code
then
152
code
=
lpegmatch
(
uparser
,
name
)
153
if
type
(
code
)
~
=
"
number
"
then
154
code
=
private
155
private
=
private
+
1
156
report_afm
(
"
assigning private slot %U for unknown glyph name %a
"
,
code
,
name
)
157
end
158
end
159
local
index
=
blob
.
index
160
unicodes
[
name
]
=
code
161
names
[
name
]
=
index
162
blob
.
name
=
name
163
descriptions
[
code
]
=
{
164
boundingbox
=
blob
.
boundingbox
,
165
width
=
blob
.
width
,
166
kerns
=
blob
.
kerns
,
167
index
=
index
,
168
name
=
name
,
169
}
170
end
171
for
unicode
,
description
in
next
,
descriptions
do
172
local
kerns
=
description
.
kerns
173
if
kerns
then
174
local
krn
=
{
}
175
for
name
,
kern
in
next
,
kerns
do
176
local
unicode
=
unicodes
[
name
]
177
if
unicode
then
178
krn
[
unicode
]
=
kern
179
else
180
-- print(unicode,name)
181
end
182
end
183
description
.
kerns
=
krn
184
end
185
end
186
data
.
characters
=
nil
187
data
.
private
=
private
188
local
resources
=
data
.
resources
189
local
filename
=
resources
.
filename
or
file
.
removesuffix
(
file
.
basename
(
filename
)
)
190
resources
.
filename
=
resolvers
.
unresolve
(
filename
)
-- no shortcut
191
resources
.
unicodes
=
unicodes
-- name to unicode
192
resources
.
marks
=
{
}
-- todo
193
-- resources.names = names -- name to index
194
end
195 196
local
everywhere
=
{
[
"
*
"
]
=
{
[
"
*
"
]
=
true
}
}
-- or: { ["*"] = { "*" } }
197
local
noflags
=
{
false
,
false
,
false
,
false
}
198 199
local
function
enhance_normalize_features
(
data
)
200
local
ligatures
=
setmetatableindex
(
"
table
"
)
201
local
kerns
=
setmetatableindex
(
"
table
"
)
202
local
extrakerns
=
setmetatableindex
(
"
table
"
)
203
for
u
,
c
in
next
,
data
.
descriptions
do
204
local
l
=
c
.
ligatures
205
local
k
=
c
.
kerns
206
local
e
=
c
.
extrakerns
207
if
l
then
208
ligatures
[
u
]
=
l
209
for
u
,
v
in
next
,
l
do
210
l
[
u
]
=
{
ligature
=
v
}
211
end
212
c
.
ligatures
=
nil
213
end
214
if
k
then
215
kerns
[
u
]
=
k
216
for
u
,
v
in
next
,
k
do
217
k
[
u
]
=
v
-- { v, 0 }
218
end
219
c
.
kerns
=
nil
220
end
221
if
e
then
222
extrakerns
[
u
]
=
e
223
for
u
,
v
in
next
,
e
do
224
e
[
u
]
=
v
-- { v, 0 }
225
end
226
c
.
extrakerns
=
nil
227
end
228
end
229
local
features
=
{
230
gpos
=
{
}
,
231
gsub
=
{
}
,
232
}
233
local
sequences
=
{
234
-- only filled ones
235
}
236
if
next
(
ligatures
)
then
237
features
.
gsub
.
liga
=
everywhere
238
data
.
properties
.
hasligatures
=
true
239
sequences
[
#
sequences
+
1
]
=
{
240
features
=
{
241
liga
=
everywhere
,
242
}
,
243
flags
=
noflags
,
244
name
=
"
s_s_0
"
,
245
nofsteps
=
1
,
246
order
=
{
"
liga
"
}
,
247
type
=
"
gsub_ligature
"
,
248
steps
=
{
249
{
250
coverage
=
ligatures
,
251
}
,
252
}
,
253
}
254
end
255
if
next
(
kerns
)
then
256
features
.
gpos
.
kern
=
everywhere
257
data
.
properties
.
haskerns
=
true
258
sequences
[
#
sequences
+
1
]
=
{
259
features
=
{
260
kern
=
everywhere
,
261
}
,
262
flags
=
noflags
,
263
name
=
"
p_s_0
"
,
264
nofsteps
=
1
,
265
order
=
{
"
kern
"
}
,
266
type
=
"
gpos_pair
"
,
267
steps
=
{
268
{
269
format
=
"
kern
"
,
270
coverage
=
kerns
,
271
}
,
272
}
,
273
}
274
end
275
if
next
(
extrakerns
)
then
276
features
.
gpos
.
extrakerns
=
everywhere
277
data
.
properties
.
haskerns
=
true
278
sequences
[
#
sequences
+
1
]
=
{
279
features
=
{
280
extrakerns
=
everywhere
,
281
}
,
282
flags
=
noflags
,
283
name
=
"
p_s_1
"
,
284
nofsteps
=
1
,
285
order
=
{
"
extrakerns
"
}
,
286
type
=
"
gpos_pair
"
,
287
steps
=
{
288
{
289
format
=
"
kern
"
,
290
coverage
=
extrakerns
,
291
}
,
292
}
,
293
}
294
end
295
-- todo: compress kerns
296
data
.
resources
.
features
=
features
297
data
.
resources
.
sequences
=
sequences
298
end
299 300
local
function
enhance_fix_names
(
data
)
301
for
k
,
v
in
next
,
data
.
descriptions
do
302
local
n
=
v
.
name
303
local
r
=
overloads
[
n
]
304
if
r
then
305
local
name
=
r
.
name
306
if
trace_indexing
then
307
report_afm
(
"
renaming characters %a to %a
"
,
n
,
name
)
308
end
309
v
.
name
=
name
310
v
.
unicode
=
r
.
unicode
311
end
312
end
313
end
314 315
--[[ldx-- 316<p>These helpers extend the basic table with extra ligatures, texligatures 317and extra kerns. This saves quite some lookups later.</p> 318--ldx]]
--
319 320
local
addthem
=
function
(
rawdata
,
ligatures
)
321
if
ligatures
then
322
local
descriptions
=
rawdata
.
descriptions
323
local
resources
=
rawdata
.
resources
324
local
unicodes
=
resources
.
unicodes
325
-- local names = resources.names
326
for
ligname
,
ligdata
in
next
,
ligatures
do
327
local
one
=
descriptions
[
unicodes
[
ligname
]
]
328
if
one
then
329
for
_
,
pair
in
next
,
ligdata
do
330
local
two
=
unicodes
[
pair
[
1
]
]
331
local
three
=
unicodes
[
pair
[
2
]
]
332
if
two
and
three
then
333
local
ol
=
one
.
ligatures
334
if
ol
then
335
if
not
ol
[
two
]
then
336
ol
[
two
]
=
three
337
end
338
else
339
one
.
ligatures
=
{
[
two
]
=
three
}
340
end
341
end
342
end
343
end
344
end
345
end
346
end
347 348
local
function
enhance_add_ligatures
(
rawdata
)
349
addthem
(
rawdata
,
afm
.
helpdata
.
ligatures
)
350
end
351 352
--[[ldx-- 353<p>We keep the extra kerns in separate kerning tables so that we can use 354them selectively.</p> 355--ldx]]
--
356 357
-- This is rather old code (from the beginning when we had only tfm). If
358
-- we unify the afm data (now we have names all over the place) then
359
-- we can use shcodes but there will be many more looping then. But we
360
-- could get rid of the tables in char-cmp then. Als, in the generic version
361
-- we don't use the character database. (Ok, we can have a context specific
362
-- variant).
363 364
local
function
enhance_add_extra_kerns
(
rawdata
)
-- using shcodes is not robust here
365
local
descriptions
=
rawdata
.
descriptions
366
local
resources
=
rawdata
.
resources
367
local
unicodes
=
resources
.
unicodes
368
local
function
do_it_left
(
what
)
369
if
what
then
370
for
unicode
,
description
in
next
,
descriptions
do
371
local
kerns
=
description
.
kerns
372
if
kerns
then
373
local
extrakerns
374
for
complex
,
simple
in
next
,
what
do
375
complex
=
unicodes
[
complex
]
376
simple
=
unicodes
[
simple
]
377
if
complex
and
simple
then
378
local
ks
=
kerns
[
simple
]
379
if
ks
and
not
kerns
[
complex
]
then
380
if
extrakerns
then
381
extrakerns
[
complex
]
=
ks
382
else
383
extrakerns
=
{
[
complex
]
=
ks
}
384
end
385
end
386
end
387
end
388
if
extrakerns
then
389
description
.
extrakerns
=
extrakerns
390
end
391
end
392
end
393
end
394
end
395
local
function
do_it_copy
(
what
)
396
if
what
then
397
for
complex
,
simple
in
next
,
what
do
398
complex
=
unicodes
[
complex
]
399
simple
=
unicodes
[
simple
]
400
if
complex
and
simple
then
401
local
complexdescription
=
descriptions
[
complex
]
402
if
complexdescription
then
-- optional
403
local
simpledescription
=
descriptions
[
complex
]
404
if
simpledescription
then
405
local
extrakerns
406
local
kerns
=
simpledescription
.
kerns
407
if
kerns
then
408
for
unicode
,
kern
in
next
,
kerns
do
409
if
extrakerns
then
410
extrakerns
[
unicode
]
=
kern
411
else
412
extrakerns
=
{
[
unicode
]
=
kern
}
413
end
414
end
415
end
416
local
extrakerns
=
simpledescription
.
extrakerns
417
if
extrakerns
then
418
for
unicode
,
kern
in
next
,
extrakerns
do
419
if
extrakerns
then
420
extrakerns
[
unicode
]
=
kern
421
else
422
extrakerns
=
{
[
unicode
]
=
kern
}
423
end
424
end
425
end
426
if
extrakerns
then
427
complexdescription
.
extrakerns
=
extrakerns
428
end
429
end
430
end
431
end
432
end
433
end
434
end
435
-- add complex with values of simplified when present
436
do_it_left
(
afm
.
helpdata
.
leftkerned
)
437
do_it_left
(
afm
.
helpdata
.
bothkerned
)
438
-- copy kerns from simple char to complex char unless set
439
do_it_copy
(
afm
.
helpdata
.
bothkerned
)
440
do_it_copy
(
afm
.
helpdata
.
rightkerned
)
441
end
442 443
--[[ldx-- 444<p>The copying routine looks messy (and is indeed a bit messy).</p> 445--ldx]]
--
446 447
local
function
adddimensions
(
data
)
-- we need to normalize afm to otf i.e. indexed table instead of name
448
if
data
then
449
for
unicode
,
description
in
next
,
data
.
descriptions
do
450
local
bb
=
description
.
boundingbox
451
if
bb
then
452
local
ht
=
bb
[
4
]
453
local
dp
=
-
bb
[
2
]
454
if
ht
=
=
0
or
ht
<
0
then
455
-- no need to set it and no negative heights, nil == 0
456
else
457
description
.
height
=
ht
458
end
459
if
dp
=
=
0
or
dp
<
0
then
460
-- no negative depths and no negative depths, nil == 0
461
else
462
description
.
depth
=
dp
463
end
464
end
465
end
466
end
467
end
468 469
local
function
copytotfm
(
data
)
470
if
data
and
data
.
descriptions
then
471
local
metadata
=
data
.
metadata
472
local
resources
=
data
.
resources
473
local
properties
=
derivetable
(
data
.
properties
)
474
local
descriptions
=
derivetable
(
data
.
descriptions
)
475
local
goodies
=
derivetable
(
data
.
goodies
)
476
local
characters
=
{
}
477
local
parameters
=
{
}
478
local
unicodes
=
resources
.
unicodes
479
--
480
for
unicode
,
description
in
next
,
data
.
descriptions
do
-- use parent table
481
characters
[
unicode
]
=
{
}
482
end
483
--
484
local
filename
=
constructors
.
checkedfilename
(
resources
)
485
local
fontname
=
metadata
.
fontname
or
metadata
.
fullname
486
local
fullname
=
metadata
.
fullname
or
metadata
.
fontname
487
local
endash
=
0x2013
488
local
emdash
=
0x2014
489
local
space
=
0x0020
-- space
490
local
spacer
=
"
space
"
491
local
spaceunits
=
500
492
--
493
local
monospaced
=
metadata
.
monospaced
494
local
charwidth
=
metadata
.
charwidth
495
local
italicangle
=
metadata
.
italicangle
496
local
charxheight
=
metadata
.
xheight
and
metadata
.
xheight
>
0
and
metadata
.
xheight
497
properties
.
monospaced
=
monospaced
498
parameters
.
italicangle
=
italicangle
499
parameters
.
charwidth
=
charwidth
500
parameters
.
charxheight
=
charxheight
501
-- nearly the same as otf, catches
502
local
d_endash
=
descriptions
[
endash
]
503
local
d_emdash
=
descriptions
[
emdash
]
504
local
d_space
=
descriptions
[
space
]
505
if
not
d_space
or
d_space
=
=
0
then
506
d_space
=
d_endash
507
end
508
if
d_space
then
509
spaceunits
,
spacer
=
d_space
.
width
or
0
,
"
space
"
510
end
511
if
properties
.
monospaced
then
512
if
spaceunits
=
=
0
and
d_emdash
then
513
spaceunits
,
spacer
=
d_emdash
.
width
or
0
,
"
emdash
"
514
end
515
else
516
if
spaceunits
=
=
0
and
d_endash
then
517
spaceunits
,
spacer
=
d_emdash
.
width
or
0
,
"
endash
"
518
end
519
end
520
if
spaceunits
=
=
0
and
charwidth
then
521
spaceunits
,
spacer
=
charwidth
or
0
,
"
charwidth
"
522
end
523
if
spaceunits
=
=
0
then
524
spaceunits
=
tonumber
(
spaceunits
)
or
500
525
end
526
if
spaceunits
=
=
0
then
527
spaceunits
=
500
528
end
529
--
530
parameters
.
slant
=
0
531
parameters
.
space
=
spaceunits
532
parameters
.
space_stretch
=
500
533
parameters
.
space_shrink
=
333
534
parameters
.
x_height
=
400
535
parameters
.
quad
=
1000
536
--
537
if
italicangle
and
italicangle
~
=
0
then
538
parameters
.
italicangle
=
italicangle
539
parameters
.
italicfactor
=
math
.
cos
(
math
.
rad
(
90
+
italicangle
)
)
540
parameters
.
slant
=
-
math
.
tan
(
italicangle
*
math
.
pi
/
180
)
541
end
542
if
monospaced
then
543
parameters
.
space_stretch
=
0
544
parameters
.
space_shrink
=
0
545
elseif
afm
.
syncspace
then
546
parameters
.
space_stretch
=
spaceunits
/
2
547
parameters
.
space_shrink
=
spaceunits
/
3
548
end
549
parameters
.
extra_space
=
parameters
.
space_shrink
550
if
charxheight
then
551
parameters
.
x_height
=
charxheight
552
else
553
-- same as otf
554
local
x
=
0x0078
-- x
555
if
x
then
556
local
x
=
descriptions
[
x
]
557
if
x
then
558
parameters
.
x_height
=
x
.
height
559
end
560
end
561
--
562
end
563
--
564
if
metadata
.
sup
then
565
local
dummy
=
{
0
,
0
,
0
}
566
parameters
[
1
]
=
metadata
.
designsize
or
0
567
parameters
[
2
]
=
metadata
.
checksum
or
0
568
parameters
[
3
]
,
569
parameters
[
4
]
,
570
parameters
[
5
]
=
unpack
(
metadata
.
space
or
dummy
)
571
parameters
[
6
]
=
metadata
.
quad
or
0
572
parameters
[
7
]
=
metadata
.
extraspace
or
0
573
parameters
[
8
]
,
574
parameters
[
9
]
,
575
parameters
[
10
]
=
unpack
(
metadata
.
num
or
dummy
)
576
parameters
[
11
]
,
577
parameters
[
12
]
=
unpack
(
metadata
.
denom
or
dummy
)
578
parameters
[
13
]
,
579
parameters
[
14
]
,
580
parameters
[
15
]
=
unpack
(
metadata
.
sup
or
dummy
)
581
parameters
[
16
]
,
582
parameters
[
17
]
=
unpack
(
metadata
.
sub
or
dummy
)
583
parameters
[
18
]
=
metadata
.
supdrop
or
0
584
parameters
[
19
]
=
metadata
.
subdrop
or
0
585
parameters
[
20
]
,
586
parameters
[
21
]
=
unpack
(
metadata
.
delim
or
dummy
)
587
parameters
[
22
]
=
metadata
.
axisheight
or
0
588
end
589
--
590
parameters
.
designsize
=
(
metadata
.
designsize
or
10
)
*
65536
591
parameters
.
ascender
=
abs
(
metadata
.
ascender
or
0
)
592
parameters
.
descender
=
abs
(
metadata
.
descender
or
0
)
593
parameters
.
units
=
1000
594
--
595
properties
.
spacer
=
spacer
596
properties
.
format
=
fonts
.
formats
[
filename
]
or
"
type1
"
597
properties
.
filename
=
filename
598
properties
.
fontname
=
fontname
599
properties
.
fullname
=
fullname
600
properties
.
psname
=
fullname
601
properties
.
name
=
filename
or
fullname
or
fontname
602
properties
.
private
=
properties
.
private
or
data
.
private
or
privateoffset
603
--
604
if
not
CONTEXTLMTXMODE
or
CONTEXTLMTXMODE
=
=
0
then
605
properties
.
encodingbytes
=
2
606
end
607
--
608
if
next
(
characters
)
then
609
return
{
610
characters
=
characters
,
611
descriptions
=
descriptions
,
612
parameters
=
parameters
,
613
resources
=
resources
,
614
properties
=
properties
,
615
goodies
=
goodies
,
616
}
617
end
618
end
619
return
nil
620
end
621 622
--[[ldx-- 623<p>Originally we had features kind of hard coded for <l n='afm'/> files but since I 624expect to support more font formats, I decided to treat this fontformat like any 625other and handle features in a more configurable way.</p> 626--ldx]]
--
627 628
function
afm
.
setfeatures
(
tfmdata
,
features
)
629
local
okay
=
constructors
.
initializefeatures
(
"
afm
"
,
tfmdata
,
features
,
trace_features
,
report_afm
)
630
if
okay
then
631
return
constructors
.
collectprocessors
(
"
afm
"
,
tfmdata
,
features
,
trace_features
,
report_afm
)
632
else
633
return
{
}
-- will become false
634
end
635
end
636 637
local
function
addtables
(
data
)
638
local
resources
=
data
.
resources
639
local
lookuptags
=
resources
.
lookuptags
640
local
unicodes
=
resources
.
unicodes
641
if
not
lookuptags
then
642
lookuptags
=
{
}
643
resources
.
lookuptags
=
lookuptags
644
end
645
setmetatableindex
(
lookuptags
,
function
(
t
,
k
)
646
local
v
=
type
(
k
)
=
=
"
number
"
and
(
"
lookup
"
.
.
k
)
or
k
647
t
[
k
]
=
v
648
return
v
649
end
)
650
if
not
unicodes
then
651
unicodes
=
{
}
652
resources
.
unicodes
=
unicodes
653
setmetatableindex
(
unicodes
,
function
(
t
,
k
)
654
setmetatableindex
(
unicodes
,
nil
)
655
for
u
,
d
in
next
,
data
.
descriptions
do
656
local
n
=
d
.
name
657
if
n
then
658
t
[
n
]
=
u
659
end
660
end
661
return
rawget
(
t
,
k
)
662
end
)
663
end
664
constructors
.
addcoreunicodes
(
unicodes
)
-- do we really need this?
665
end
666 667
local
function
afmtotfm
(
specification
)
668
local
afmname
=
specification
.
filename
or
specification
.
name
669
if
specification
.
forced
=
=
"
afm
"
or
specification
.
format
=
=
"
afm
"
then
-- move this one up
670
if
trace_loading
then
671
report_afm
(
"
forcing afm format for %a
"
,
afmname
)
672
end
673
else
674
local
tfmname
=
findbinfile
(
afmname
,
"
ofm
"
)
or
"
"
675
if
tfmname
~
=
"
"
then
676
if
trace_loading
then
677
report_afm
(
"
fallback from afm to tfm for %a
"
,
afmname
)
678
end
679
return
-- just that
680
end
681
end
682
if
afmname
~
=
"
"
then
683
-- weird, isn't this already done then?
684
local
features
=
constructors
.
checkedfeatures
(
"
afm
"
,
specification
.
features
.
normal
)
685
specification
.
features
.
normal
=
features
686
constructors
.
hashinstance
(
specification
,
true
)
-- also weird here
687
--
688
specification
=
definers
.
resolve
(
specification
)
-- new, was forgotten
689
local
cache_id
=
specification
.
hash
690
local
tfmdata
=
containers
.
read
(
constructors
.
cache
,
cache_id
)
-- cache with features applied
691
if
not
tfmdata
then
692
local
rawdata
=
afm
.
load
(
afmname
)
693
if
rawdata
and
next
(
rawdata
)
then
694
addtables
(
rawdata
)
695
adddimensions
(
rawdata
)
696
tfmdata
=
copytotfm
(
rawdata
)
697
if
tfmdata
and
next
(
tfmdata
)
then
698
local
shared
=
tfmdata
.
shared
699
if
not
shared
then
700
shared
=
{
}
701
tfmdata
.
shared
=
shared
702
end
703
shared
.
rawdata
=
rawdata
704
shared
.
dynamics
=
{
}
705
tfmdata
.
changed
=
{
}
706
shared
.
features
=
features
707
shared
.
processes
=
afm
.
setfeatures
(
tfmdata
,
features
)
708
end
709
elseif
trace_loading
then
710
report_afm
(
"
no (valid) afm file found with name %a
"
,
afmname
)
711
end
712
tfmdata
=
containers
.
write
(
constructors
.
cache
,
cache_id
,
tfmdata
)
713
end
714
return
tfmdata
715
end
716
end
717 718
--[[ldx-- 719<p>As soon as we could intercept the <l n='tfm'/> reader, I implemented an 720<l n='afm'/> reader. Since traditional <l n='pdftex'/> could use <l n='opentype'/> 721fonts with <l n='afm'/> companions, the following method also could handle 722those cases, but now that we can handle <l n='opentype'/> directly we no longer 723need this features.</p> 724--ldx]]
--
725 726
local
function
read_from_afm
(
specification
)
727
local
tfmdata
=
afmtotfm
(
specification
)
728
if
tfmdata
then
729
tfmdata
.
properties
.
name
=
specification
.
name
730
tfmdata
.
properties
.
id
=
specification
.
id
731
tfmdata
=
constructors
.
scale
(
tfmdata
,
specification
)
732
local
allfeatures
=
tfmdata
.
shared
.
features
or
specification
.
features
.
normal
733
constructors
.
applymanipulators
(
"
afm
"
,
tfmdata
,
allfeatures
,
trace_features
,
report_afm
)
734
fonts
.
loggers
.
register
(
tfmdata
,
'
afm
'
,
specification
)
735
end
736
return
tfmdata
737
end
738 739
--[[ldx-- 740<p>We have the usual two modes and related features initializers and processors.</p> 741--ldx]]
--
742 743
registerafmfeature
{
744
name
=
"
mode
"
,
745
description
=
"
mode
"
,
746
initializers
=
{
747
base
=
otf
.
modeinitializer
,
748
node
=
otf
.
modeinitializer
,
749
}
750
}
751 752
registerafmfeature
{
753
name
=
"
features
"
,
754
description
=
"
features
"
,
755
default
=
true
,
756
initializers
=
{
757
node
=
otf
.
nodemodeinitializer
,
758
base
=
otf
.
basemodeinitializer
,
759
}
,
760
processors
=
{
761
node
=
otf
.
featuresprocessor
,
762
}
763
}
764 765
-- readers
766 767
fonts
.
formats
.
afm
=
"
type1
"
768
fonts
.
formats
.
pfb
=
"
type1
"
769 770
local
function
check_afm
(
specification
,
fullname
)
771
local
foundname
=
findbinfile
(
fullname
,
'
afm
'
)
or
"
"
-- just to be sure
772
if
foundname
=
=
"
"
then
773
foundname
=
fonts
.
names
.
getfilename
(
fullname
,
"
afm
"
)
or
"
"
774
end
775
if
fullname
and
foundname
=
=
"
"
and
afm
.
autoprefixed
then
776
local
encoding
,
shortname
=
match
(
fullname
,
"
^(.-)%-(.*)$
"
)
-- context: encoding-name.*
777
if
encoding
and
shortname
and
fonts
.
encodings
.
known
[
encoding
]
then
778
shortname
=
findbinfile
(
shortname
,
'
afm
'
)
or
"
"
-- just to be sure
779
if
shortname
~
=
"
"
then
780
foundname
=
shortname
781
if
trace_defining
then
782
report_afm
(
"
stripping encoding prefix from filename %a
"
,
afmname
)
783
end
784
end
785
end
786
end
787
if
foundname
~
=
"
"
then
788
specification
.
filename
=
foundname
789
specification
.
format
=
"
afm
"
790
return
read_from_afm
(
specification
)
791
end
792
end
793 794
function
readers
.
afm
(
specification
,
method
)
795
local
fullname
=
specification
.
filename
or
"
"
796
local
tfmdata
=
nil
797
if
fullname
=
=
"
"
then
798
local
forced
=
specification
.
forced
or
"
"
799
if
forced
~
=
"
"
then
800
tfmdata
=
check_afm
(
specification
,
specification
.
name
.
.
"
.
"
.
.
forced
)
801
end
802
if
not
tfmdata
then
803
local
check_tfm
=
readers
.
check_tfm
804
method
=
(
check_tfm
and
(
method
or
definers
.
method
or
"
afm or tfm
"
)
)
or
"
afm
"
805
if
method
=
=
"
tfm
"
then
806
tfmdata
=
check_tfm
(
specification
,
specification
.
name
)
807
elseif
method
=
=
"
afm
"
then
808
tfmdata
=
check_afm
(
specification
,
specification
.
name
)
809
elseif
method
=
=
"
tfm or afm
"
then
810
tfmdata
=
check_tfm
(
specification
,
specification
.
name
)
or
check_afm
(
specification
,
specification
.
name
)
811
else
-- method == "afm or tfm" or method == "" then
812
tfmdata
=
check_afm
(
specification
,
specification
.
name
)
or
check_tfm
(
specification
,
specification
.
name
)
813
end
814
end
815
else
816
tfmdata
=
check_afm
(
specification
,
fullname
)
817
end
818
return
tfmdata
819
end
820 821
function
readers
.
pfb
(
specification
,
method
)
-- only called when forced
822
local
original
=
specification
.
specification
823
if
trace_defining
then
824
report_afm
(
"
using afm reader for %a
"
,
original
)
825
end
826
specification
.
forced
=
"
afm
"
827
local
function
swap
(
name
)
828
local
value
=
specification
[
swap
]
829
if
value
then
830
specification
[
swap
]
=
gsub
(
"
%.pfb
"
,
"
.afm
"
,
1
)
831
end
832
end
833
swap
(
"
filename
"
)
834
swap
(
"
fullname
"
)
835
swap
(
"
forcedname
"
)
836
swap
(
"
specification
"
)
837
return
readers
.
afm
(
specification
,
method
)
838
end
839 840
-- now we register them
841 842
registerafmenhancer
(
"
unify names
"
,
enhance_unify_names
)
843
registerafmenhancer
(
"
add ligatures
"
,
enhance_add_ligatures
)
844
registerafmenhancer
(
"
add extra kerns
"
,
enhance_add_extra_kerns
)
845
registerafmenhancer
(
"
normalize features
"
,
enhance_normalize_features
)
846
registerafmenhancer
(
"
check extra features
"
,
otfenhancers
.
enhance
)
847
registerafmenhancer
(
"
fix names
"
,
enhance_fix_names
)
848