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