font-shp.lua /size: 13 Kb    last modification: 2020-07-01 14:35
1
if
not
modules
then
modules
=
{
}
end
modules
[
'
font-shp
'
]
=
{
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
local
tonumber
,
next
=
tonumber
,
next
10
local
concat
=
table
.
concat
11
local
formatters
=
string
.
formatters
12 13
local
otf
=
fonts
.
handlers
.
otf
14
local
afm
=
fonts
.
handlers
.
afm
15
local
pfb
=
fonts
.
handlers
.
pfb
16 17
local
hashes
=
fonts
.
hashes
18
local
identifiers
=
hashes
.
identifiers
19 20
local
version
=
0
.
009
21
local
shapescache
=
containers
.
define
(
"
fonts
"
,
"
shapes
"
,
version
,
true
)
22
local
streamscache
=
containers
.
define
(
"
fonts
"
,
"
streams
"
,
version
,
true
)
23 24
-- shapes (can be come a separate file at some point)
25 26
local
compact_streams
=
false
27 28
directives
.
register
(
"
fonts.streams.compact
"
,
function
(
v
)
compact_streams
=
v
end
)
29 30
local
function
packoutlines
(
data
,
makesequence
)
31
local
subfonts
=
data
.
subfonts
32
if
subfonts
then
33
for
i
=
1
,
#
subfonts
do
34
packoutlines
(
subfonts
[
i
]
,
makesequence
)
35
end
36
return
37
end
38
local
common
=
data
.
segments
39
if
common
then
40
return
41
end
42
local
glyphs
=
data
.
glyphs
43
if
not
glyphs
then
44
return
45
end
46
if
makesequence
then
47
for
index
=
0
,
#
glyphs
do
48
local
glyph
=
glyphs
[
index
]
49
if
glyph
then
50
local
segments
=
glyph
.
segments
51
if
segments
then
52
local
sequence
=
{
}
53
local
nofsequence
=
0
54
for
i
=
1
,
#
segments
do
55
local
segment
=
segments
[
i
]
56
local
nofsegment
=
#
segment
57
-- why last first ... needs documenting
58
nofsequence
=
nofsequence
+
1
59
sequence
[
nofsequence
]
=
segment
[
nofsegment
]
60
for
i
=
1
,
nofsegment
-1
do
61
nofsequence
=
nofsequence
+
1
62
sequence
[
nofsequence
]
=
segment
[
i
]
63
end
64
end
65
glyph
.
sequence
=
sequence
66
glyph
.
segments
=
nil
67
end
68
end
69
end
70
else
71
local
hash
=
{
}
72
local
common
=
{
}
73
local
reverse
=
{
}
74
local
last
=
0
75
for
index
=
0
,
#
glyphs
do
76
local
glyph
=
glyphs
[
index
]
77
if
glyph
then
78
local
segments
=
glyph
.
segments
79
if
segments
then
80
for
i
=
1
,
#
segments
do
81
local
h
=
concat
(
segments
[
i
]
,
"
"
)
82
hash
[
h
]
=
(
hash
[
h
]
or
0
)
+
1
83
end
84
end
85
end
86
end
87
for
index
=
0
,
#
glyphs
do
88
local
glyph
=
glyphs
[
index
]
89
if
glyph
then
90
local
segments
=
glyph
.
segments
91
if
segments
then
92
for
i
=
1
,
#
segments
do
93
local
segment
=
segments
[
i
]
94
local
h
=
concat
(
segment
,
"
"
)
95
if
hash
[
h
]
>
1
then
-- minimal one shared in order to hash
96
local
idx
=
reverse
[
h
]
97
if
not
idx
then
98
last
=
last
+
1
99
reverse
[
h
]
=
last
100
common
[
last
]
=
segment
101
idx
=
last
102
end
103
segments
[
i
]
=
idx
104
end
105
end
106
end
107
end
108
end
109
if
last
>
0
then
110
data
.
segments
=
common
111
end
112
end
113
end
114 115
local
function
unpackoutlines
(
data
)
116
local
subfonts
=
data
.
subfonts
117
if
subfonts
then
118
for
i
=
1
,
#
subfonts
do
119
unpackoutlines
(
subfonts
[
i
]
)
120
end
121
return
122
end
123
local
common
=
data
.
segments
124
if
not
common
then
125
return
126
end
127
local
glyphs
=
data
.
glyphs
128
if
not
glyphs
then
129
return
130
end
131
for
index
=
0
,
#
glyphs
do
132
local
glyph
=
glyphs
[
index
]
133
if
glyph
then
134
local
segments
=
glyph
.
segments
135
if
segments
then
136
for
i
=
1
,
#
segments
do
137
local
c
=
common
[
segments
[
i
]
]
138
if
c
then
139
segments
[
i
]
=
c
140
end
141
end
142
end
143
end
144
end
145
data
.
segments
=
nil
146
end
147 148
-- todo: loaders per format
149 150
local
readers
=
otf
.
readers
151
local
cleanname
=
otf
.
readers
.
helpers
.
cleanname
152 153
local
function
makehash
(
filename
,
sub
,
instance
)
154
local
name
=
cleanname
(
file
.
basename
(
filename
)
)
155
if
instance
then
156
return
formatters
[
"
%s-%s-%s
"
]
(
name
,
sub
or
0
,
cleanname
(
instance
)
)
157
else
158
return
formatters
[
"
%s-%s
"
]
(
name
,
sub
or
0
)
159
end
160
end
161 162
local
function
loadoutlines
(
cache
,
filename
,
sub
,
instance
)
163
local
base
=
file
.
basename
(
filename
)
164
local
name
=
file
.
removesuffix
(
base
)
165
local
kind
=
file
.
suffix
(
filename
)
166
local
attr
=
lfs
.
attributes
(
filename
)
167
local
size
=
attr
and
attr
.
size
or
0
168
local
time
=
attr
and
attr
.
modification
or
0
169
local
sub
=
tonumber
(
sub
)
170 171
-- fonts.formats
172 173
if
size
>
0
and
(
kind
=
=
"
otf
"
or
kind
=
=
"
ttf
"
or
kind
=
=
"
tcc
"
)
then
174
local
hash
=
makehash
(
filename
,
sub
,
instance
)
175
data
=
containers
.
read
(
cache
,
hash
)
176
if
not
data
or
data
.
time
~
=
time
or
data
.
size
~
=
size
then
177
data
=
otf
.
readers
.
loadshapes
(
filename
,
sub
,
instance
)
178
if
data
then
179
data
.
size
=
size
180
data
.
format
=
data
.
format
or
(
kind
=
=
"
otf
"
and
"
opentype
"
)
or
"
truetype
"
181
data
.
time
=
time
182
packoutlines
(
data
)
183
containers
.
write
(
cache
,
hash
,
data
)
184
data
=
containers
.
read
(
cache
,
hash
)
-- frees old mem
185
end
186
end
187
unpackoutlines
(
data
)
188
elseif
size
>
0
and
(
kind
=
=
"
pfb
"
)
then
189
local
hash
=
containers
.
cleanname
(
base
)
-- including suffix
190
data
=
containers
.
read
(
cache
,
hash
)
191
if
not
data
or
data
.
time
~
=
time
or
data
.
size
~
=
size
then
192
data
=
afm
.
readers
.
loadshapes
(
filename
)
193
if
data
then
194
data
.
size
=
size
195
data
.
format
=
"
type1
"
196
data
.
time
=
time
197
packoutlines
(
data
)
198
containers
.
write
(
cache
,
hash
,
data
)
199
data
=
containers
.
read
(
cache
,
hash
)
-- frees old mem
200
end
201
end
202
unpackoutlines
(
data
)
203
else
204
data
=
{
205
filename
=
filename
,
206
size
=
0
,
207
time
=
time
,
208
format
=
"
unknown
"
,
209
units
=
1000
,
210
glyphs
=
{
}
211
}
212
end
213
return
data
214
end
215 216
local
function
cachethem
(
cache
,
hash
,
data
)
217
containers
.
write
(
cache
,
hash
,
data
,
compact_streams
)
-- arg 4 aka fast
218
return
containers
.
read
(
cache
,
hash
)
-- frees old mem
219
end
220 221
local
function
loadstreams
(
cache
,
filename
,
sub
,
instance
)
222
local
base
=
file
.
basename
(
filename
)
223
local
name
=
file
.
removesuffix
(
base
)
224
local
kind
=
file
.
suffix
(
filename
)
225
local
attr
=
lfs
.
attributes
(
filename
)
226
local
size
=
attr
and
attr
.
size
or
0
227
local
time
=
attr
and
attr
.
modification
or
0
228
local
sub
=
tonumber
(
sub
)
229
if
size
>
0
and
(
kind
=
=
"
otf
"
or
kind
=
=
"
ttf
"
or
kind
=
=
"
ttc
"
)
then
230
local
hash
=
makehash
(
filename
,
sub
,
instance
)
231
data
=
containers
.
read
(
cache
,
hash
)
232
if
not
data
or
data
.
time
~
=
time
or
data
.
size
~
=
size
then
233
data
=
otf
.
readers
.
loadshapes
(
filename
,
sub
,
instance
,
true
)
234
if
data
then
235
local
glyphs
=
data
.
glyphs
236
local
streams
=
{
}
237
if
glyphs
then
238
for
i
=
0
,
#
glyphs
do
239
local
glyph
=
glyphs
[
i
]
240
if
glyph
then
241
streams
[
i
]
=
glyph
.
stream
or
"
"
242
else
243
streams
[
i
]
=
"
"
244
end
245
end
246
end
247
data
.
streams
=
streams
248
data
.
glyphs
=
nil
249
data
.
size
=
size
250
data
.
format
=
data
.
format
or
(
kind
=
=
"
otf
"
and
"
opentype
"
)
or
"
truetype
"
251
data
.
time
=
time
252
data
=
cachethem
(
cache
,
hash
,
data
)
253
end
254
end
255
elseif
size
>
0
and
(
kind
=
=
"
pfb
"
)
then
256
local
hash
=
makehash
(
filename
,
sub
,
instance
)
257
data
=
containers
.
read
(
cache
,
hash
)
258
if
not
data
or
data
.
time
~
=
time
or
data
.
size
~
=
size
then
259
local
names
,
encoding
,
streams
,
metadata
=
pfb
.
loadvector
(
filename
,
false
,
true
)
260
if
streams
then
261
local
fontbbox
=
metadata
.
fontbbox
or
{
0
,
0
,
0
,
0
}
262
for
i
=
0
,
#
streams
do
263
streams
[
i
]
=
streams
[
i
]
.
stream
or
"
\14
"
264
end
265
data
=
{
266
filename
=
filename
,
267
size
=
size
,
268
time
=
time
,
269
format
=
"
type1
"
,
270
streams
=
streams
,
271
fontheader
=
{
272
fontversion
=
metadata
.
version
,
273
units
=
1000
,
-- can this be different?
274
xmin
=
fontbbox
[
1
]
,
275
ymin
=
fontbbox
[
2
]
,
276
xmax
=
fontbbox
[
3
]
,
277
ymax
=
fontbbox
[
4
]
,
278
}
,
279
horizontalheader
=
{
280
ascender
=
0
,
281
descender
=
0
,
282
}
,
283
maximumprofile
=
{
284
nofglyphs
=
#
streams
+
1
,
285
}
,
286
names
=
{
287
copyright
=
metadata
.
copyright
,
288
family
=
metadata
.
familyname
,
289
fullname
=
metadata
.
fullname
,
290
fontname
=
metadata
.
fontname
,
291
subfamily
=
metadata
.
subfamilyname
,
292
trademark
=
metadata
.
trademark
,
293
notice
=
metadata
.
notice
,
294
version
=
metadata
.
version
,
295
}
,
296
cffinfo
=
{
297
familyname
=
metadata
.
familyname
,
298
fullname
=
metadata
.
fullname
,
299
italicangle
=
metadata
.
italicangle
,
300
monospaced
=
metadata
.
isfixedpitch
and
true
or
false
,
301
underlineposition
=
metadata
.
underlineposition
,
302
underlinethickness
=
metadata
.
underlinethickness
,
303
weight
=
metadata
.
weight
,
304
}
,
305
}
306
data
=
cachethem
(
cache
,
hash
,
data
)
307
end
308
end
309
else
310
data
=
{
311
filename
=
filename
,
312
size
=
0
,
313
time
=
time
,
314
format
=
"
unknown
"
,
315
streams
=
{
}
316
}
317
end
318
return
data
319
end
320 321
local
loadedshapes
=
{
}
322
local
loadedstreams
=
{
}
323 324
local
function
loadoutlinedata
(
fontdata
,
streams
)
325
local
properties
=
fontdata
.
properties
326
local
filename
=
properties
.
filename
327
local
subindex
=
fontdata
.
subindex
328
local
instance
=
properties
.
instance
329
local
hash
=
makehash
(
filename
,
subindex
,
instance
)
330
local
loaded
=
loadedshapes
[
hash
]
331
if
not
loaded
then
332
loaded
=
loadoutlines
(
shapescache
,
filename
,
subindex
,
instance
)
333
loadedshapes
[
hash
]
=
loaded
334
end
335
return
loaded
336
end
337 338
hashes
.
shapes
=
table
.
setmetatableindex
(
function
(
t
,
k
)
339
local
f
=
identifiers
[
k
]
340
if
f
then
341
return
loadoutlinedata
(
f
)
342
end
343
end
)
344 345
local
function
getstreamhash
(
fontid
)
346
local
fontdata
=
identifiers
[
fontid
]
347
if
fontdata
then
348
local
properties
=
fontdata
.
properties
349
return
makehash
(
properties
.
filename
,
properties
.
subfont
,
properties
.
instance
)
350
end
351
end
352 353
local
function
loadstreamdata
(
fontdata
)
354
local
properties
=
fontdata
.
properties
355
local
shared
=
fontdata
.
shared
356
local
rawdata
=
shared
and
shared
.
rawdata
357
local
metadata
=
rawdata
and
rawdata
.
metadata
358
local
filename
=
properties
.
filename
359
local
subindex
=
metadata
and
metadata
.
subfontindex
360
local
instance
=
properties
.
instance
361
local
hash
=
makehash
(
filename
,
subindex
,
instance
)
362
local
loaded
=
loadedstreams
[
hash
]
363
if
not
loaded
then
364
loaded
=
loadstreams
(
streamscache
,
filename
,
subindex
,
instance
)
365
loadedstreams
[
hash
]
=
loaded
366
end
367
return
loaded
368
end
369 370
hashes
.
streams
=
table
.
setmetatableindex
(
function
(
t
,
k
)
371
local
f
=
identifiers
[
k
]
372
if
f
then
373
return
loadstreamdata
(
f
)
374
end
375
end
)
376 377
otf
.
loadoutlinedata
=
loadoutlinedata
-- not public
378
otf
.
loadstreamdata
=
loadstreamdata
-- not public
379
otf
.
loadshapes
=
loadshapes
380
otf
.
getstreamhash
=
getstreamhash
-- not public, might move to other namespace
381 382
local
streams
=
fonts
.
hashes
.
streams
383 384
-- we can now assume that luatex has this one
385 386
callback
.
register
(
"
glyph_stream_provider
"
,
function
(
id
,
index
,
mode
)
387
if
id
>
0
then
388
local
streams
=
streams
[
id
]
.
streams
389
-- print(id,index,streams[index])
390
if
streams
then
391
return
streams
[
index
]
or
"
"
392
end
393
end
394
return
"
"
395
end
)
396