font-mps.lua /size: 15 Kb    last modification: 2021-10-28 13:50
1
if
not
modules
then
modules
=
{
}
end
modules
[
'
font-mps
'
]
=
{
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
tostring
=
tostring
10
local
concat
=
table
.
concat
11
local
formatters
=
string
.
formatters
12 13
-- QP0 [QP1] QP2 => CP0 [CP1 CP2] CP3
14 15
-- CP0 = QP0
16
-- CP3 = QP2
17
--
18
-- CP1 = QP0 + 2/3 *(QP1-QP0)
19
-- CP2 = QP2 + 2/3 *(QP1-QP2)
20 21
fonts
=
fonts
or
{
}
22
local
metapost
=
fonts
.
metapost
or
{
}
23
fonts
.
metapost
=
metapost
24 25
local
f_moveto
=
formatters
[
"
(%N,%N)
"
]
26
local
f_lineto
=
formatters
[
"
--(%N,%N)
"
]
27
local
f_curveto
=
formatters
[
"
..controls(%N,%N)and(%N,%N)..(%N,%N)
"
]
28
local
s_cycle
=
"
--cycle
"
29 30
local
f_nofill
=
formatters
[
"
nofill %s;
"
]
31
local
f_dofill
=
formatters
[
"
fill %s;
"
]
32 33
local
f_draw_trace
=
formatters
[
"
drawpathonly %s;
"
]
34
local
f_draw
=
formatters
[
"
draw %s;
"
]
35 36
local
f_boundingbox
=
formatters
[
"
((%N,%N)--(%N,%N)--(%N,%N)--(%N,%N)--cycle)
"
]
37
local
f_vertical
=
formatters
[
"
((%N,%N)--(%N,%N))
"
]
38 39
function
metapost
.
boundingbox
(
d
,
factor
)
40
local
bounds
=
d
.
boundingbox
41
local
factor
=
factor
or
1
42
local
llx
=
factor
*
bounds
[
1
]
43
local
lly
=
factor
*
bounds
[
2
]
44
local
urx
=
factor
*
bounds
[
3
]
45
local
ury
=
factor
*
bounds
[
4
]
46
return
f_boundingbox
(
llx
,
lly
,
urx
,
lly
,
urx
,
ury
,
llx
,
ury
)
47
end
48 49
function
metapost
.
widthline
(
d
,
factor
)
50
local
bounds
=
d
.
boundingbox
51
local
factor
=
factor
or
1
52
local
lly
=
factor
*
bounds
[
2
]
53
local
ury
=
factor
*
bounds
[
4
]
54
local
width
=
factor
*
d
.
width
55
return
f_vertical
(
width
,
lly
,
width
,
ury
)
56
end
57 58
function
metapost
.
zeroline
(
d
,
factor
)
59
local
bounds
=
d
.
boundingbox
60
local
factor
=
factor
or
1
61
local
lly
=
factor
*
bounds
[
2
]
62
local
ury
=
factor
*
bounds
[
4
]
63
return
f_vertical
(
0
,
lly
,
0
,
ury
)
64
end
65 66
function
metapost
.
paths
(
d
,
xfactor
,
yfactor
)
67
local
sequence
=
d
.
sequence
68
local
segments
=
d
.
segments
69
local
list
=
{
}
70
local
path
=
{
}
-- recycled
71
local
size
=
0
72
local
xfactor
=
xfactor
or
1
73
local
yfactor
=
yfactor
or
xfactor
74
if
sequence
then
75
local
i
=
1
76
local
n
=
#
sequence
77
while
i
<
n
do
78
local
operator
=
sequence
[
i
]
79
if
operator
=
=
"
m
"
then
-- "moveto"
80
if
size
>
0
then
81
size
=
size
+
1
82
path
[
size
]
=
s_cycle
83
list
[
#
list
+
1
]
=
concat
(
path
,
"
"
,
1
,
size
)
84
size
=
1
85
else
86
size
=
size
+
1
87
end
88
path
[
size
]
=
f_moveto
(
xfactor
*
sequence
[
i
+
1
]
,
yfactor
*
sequence
[
i
+
2
]
)
89
i
=
i
+
3
90
elseif
operator
=
=
"
l
"
then
-- "lineto"
91
size
=
size
+
1
92
path
[
size
]
=
f_lineto
(
xfactor
*
sequence
[
i
+
1
]
,
yfactor
*
sequence
[
i
+
2
]
)
93
i
=
i
+
3
94
elseif
operator
=
=
"
c
"
then
-- "curveto"
95
size
=
size
+
1
96
path
[
size
]
=
f_curveto
(
xfactor
*
sequence
[
i
+
1
]
,
yfactor
*
sequence
[
i
+
2
]
,
xfactor
*
sequence
[
i
+
3
]
,
yfactor
*
sequence
[
i
+
4
]
,
xfactor
*
sequence
[
i
+
5
]
,
yfactor
*
sequence
[
i
+
6
]
)
97
i
=
i
+
7
98
elseif
operator
=
=
"
q
"
then
-- "quadraticto"
99
size
=
size
+
1
100
-- first is always a moveto
101
local
l_x
=
xfactor
*
sequence
[
i
-2
]
102
local
l_y
=
yfactor
*
sequence
[
i
-1
]
103
local
m_x
=
xfactor
*
sequence
[
i
+
1
]
104
local
m_y
=
yfactor
*
sequence
[
i
+
2
]
105
local
r_x
=
xfactor
*
sequence
[
i
+
3
]
106
local
r_y
=
yfactor
*
sequence
[
i
+
4
]
107
path
[
size
]
=
f_curveto
(
108
l_x
+
2
/
3
*
(
m_x
-
l_x
)
,
109
l_y
+
2
/
3
*
(
m_y
-
l_y
)
,
110
r_x
+
2
/
3
*
(
m_x
-
r_x
)
,
111
r_y
+
2
/
3
*
(
m_y
-
r_y
)
,
112
r_x
,
r_y
113
)
114
i
=
i
+
5
115
else
116
-- weird
117
i
=
i
+
1
118
end
119
end
120
elseif
segments
then
121
for
i
=
1
,
#
segments
do
122
local
segment
=
segments
[
i
]
123
local
operator
=
segment
[
#
segment
]
124
if
operator
=
=
"
m
"
then
-- "moveto"
125
if
size
>
0
then
126
size
=
size
+
1
127
path
[
size
]
=
s_cycle
128
list
[
#
list
+
1
]
=
concat
(
path
,
"
"
,
1
,
size
)
129
size
=
1
130
else
131
size
=
size
+
1
132
end
133
path
[
size
]
=
f_moveto
(
xfactor
*
segment
[
1
]
,
yfactor
*
segment
[
2
]
)
134
elseif
operator
=
=
"
l
"
then
-- "lineto"
135
size
=
size
+
1
136
path
[
size
]
=
f_lineto
(
xfactor
*
segment
[
1
]
,
yfactor
*
segment
[
2
]
)
137
elseif
operator
=
=
"
c
"
then
-- "curveto"
138
size
=
size
+
1
139
path
[
size
]
=
f_curveto
(
xfactor
*
segment
[
1
]
,
yfactor
*
segment
[
2
]
,
xfactor
*
segment
[
3
]
,
yfactor
*
segment
[
4
]
,
xfactor
*
segment
[
5
]
,
yfactor
*
segment
[
6
]
)
140
elseif
operator
=
=
"
q
"
then
-- "quadraticto"
141
size
=
size
+
1
142
-- first is always a moveto
143
local
prev
=
segments
[
i
-1
]
144
local
l_x
=
xfactor
*
prev
[
#
prev
-2
]
145
local
l_y
=
yfactor
*
prev
[
#
prev
-1
]
146
local
m_x
=
xfactor
*
segment
[
1
]
147
local
m_y
=
yfactor
*
segment
[
2
]
148
local
r_x
=
xfactor
*
segment
[
3
]
149
local
r_y
=
yfactor
*
segment
[
4
]
150
path
[
size
]
=
f_curveto
(
151
l_x
+
2
/
3
*
(
m_x
-
l_x
)
,
152
l_y
+
2
/
3
*
(
m_y
-
l_y
)
,
153
r_x
+
2
/
3
*
(
m_x
-
r_x
)
,
154
r_y
+
2
/
3
*
(
m_y
-
r_y
)
,
155
r_x
,
r_y
156
)
157
else
158
-- weird
159
end
160
end
161
else
162
return
163
end
164
if
size
>
0
then
165
size
=
size
+
1
166
path
[
size
]
=
s_cycle
167
list
[
#
list
+
1
]
=
concat
(
path
,
"
"
,
1
,
size
)
168
end
169
return
list
170
end
171 172
function
metapost
.
fill
(
paths
)
173
local
r
=
{
}
174
local
n
=
#
paths
175
for
i
=
1
,
n
do
176
if
i
<
n
then
177
r
[
i
]
=
f_nofill
(
paths
[
i
]
)
178
else
179
r
[
i
]
=
f_dofill
(
paths
[
i
]
)
180
end
181
end
182
return
concat
(
r
)
183
end
184 185
function
metapost
.
draw
(
paths
,
trace
)
186
local
r
=
{
}
187
local
n
=
#
paths
188
for
i
=
1
,
n
do
189
if
trace
then
190
r
[
i
]
=
f_draw_trace
(
paths
[
i
]
)
191
else
192
r
[
i
]
=
f_draw
(
paths
[
i
]
)
193
end
194
end
195
return
concat
(
r
)
196
end
197 198
function
metapost
.
maxbounds
(
data
,
index
,
factor
)
199
local
maxbounds
=
data
.
maxbounds
200
local
factor
=
factor
or
1
201
local
glyphs
=
data
.
glyphs
202
local
glyph
=
glyphs
[
index
]
203
local
boundingbox
=
glyph
.
boundingbox
204
local
xmin
,
ymin
,
xmax
,
ymax
205
if
not
maxbounds
then
206
xmin
=
0
207
ymin
=
0
208
xmax
=
0
209
ymax
=
0
210
for
i
=
1
,
#
glyphs
do
211
local
d
=
glyphs
[
i
]
212
if
d
then
213
local
b
=
d
.
boundingbox
214
if
b
then
215
if
b
[
1
]
<
xmin
then
xmin
=
b
[
1
]
end
216
if
b
[
2
]
<
ymin
then
ymin
=
b
[
2
]
end
217
if
b
[
3
]
>
xmax
then
xmax
=
b
[
3
]
end
218
if
b
[
4
]
>
ymax
then
ymax
=
b
[
4
]
end
219
end
220
end
221
end
222
maxbounds
=
{
xmin
,
ymin
,
xmax
,
ymax
}
223
data
.
maxbounds
=
maxbounds
224
else
225
xmin
=
maxbounds
[
1
]
226
ymin
=
maxbounds
[
2
]
227
xmax
=
maxbounds
[
3
]
228
ymax
=
maxbounds
[
4
]
229
end
230
local
llx
=
boundingbox
[
1
]
231
local
lly
=
boundingbox
[
2
]
232
local
urx
=
boundingbox
[
3
]
233
local
ury
=
boundingbox
[
4
]
234
local
width
=
glyph
.
width
235
if
llx
>
0
then
236
llx
=
0
237
end
238
if
width
>
urx
then
239
urx
=
width
240
end
241
return
f_boundingbox
(
242
factor
*
llx
,
factor
*
ymin
,
243
factor
*
urx
,
factor
*
ymin
,
244
factor
*
urx
,
factor
*
ymax
,
245
factor
*
llx
,
factor
*
ymax
246
)
247
end
248 249
-- This is a nice example of tex, metapost and lua working in tandem. Each kicks in at the
250
-- right time. It's probably why I like watching https://www.youtube.com/watch?v=c5FqpddnJmc
251
-- so much: precisely (and perfectly) timed too.
252 253
local
nodecodes
=
nodes
.
nodecodes
-- no nuts yet
254
local
rulecodes
=
nodes
.
rulecodes
255 256
local
glyph_code
=
nodecodes
.
glyph
257
local
disc_code
=
nodecodes
.
disc
258
local
kern_code
=
nodecodes
.
kern
259
local
glue_code
=
nodecodes
.
glue
260
local
hlist_code
=
nodecodes
.
hlist
261
local
vlist_code
=
nodecodes
.
vlist
262
local
rule_code
=
nodecodes
.
rule
263 264
local
normalrule_code
=
rulecodes
.
normal
265 266
local
nuts
=
nodes
.
nuts
267
local
getnext
=
nuts
.
getnext
268
local
getid
=
nuts
.
getid
269
local
getlist
=
nuts
.
getlist
270
local
getsubtype
=
nuts
.
getsubtype
271
local
getreplace
=
nuts
.
getreplace
272
local
getbox
=
nuts
.
getbox
273
local
getwhd
=
nuts
.
getwhd
274
local
getkern
=
nuts
.
getkern
275
local
getshift
=
nuts
.
getshift
276
local
getwidth
=
nuts
.
getwidth
277
local
getheight
=
nuts
.
getheight
278
local
getdepth
=
nuts
.
getdepth
279
local
getexpansion
=
nuts
.
getexpansion
280
local
isglyph
=
nuts
.
isglyph
281 282
local
effectiveglue
=
nuts
.
effectiveglue
283 284
local
characters
=
fonts
.
hashes
.
characters
285
local
parameters
=
fonts
.
hashes
.
parameters
286
local
shapes
=
fonts
.
hashes
.
shapes
287
local
topaths
=
metapost
.
paths
288 289
local
f_code
=
formatters
[
"
mfun_do_outline_text_flush(%q,%i,%N,%N,%q)(%,t);
"
]
290
local
f_rule
=
formatters
[
"
mfun_do_outline_rule_flush(%q,%N,%N,%N,%N);
"
]
291
local
f_bounds
=
formatters
[
"
checkbounds(%N,%N,%N,%N);
"
]
292
local
s_nothing
=
"
(origin scaled 10)
"
293 294
local
sc
=
10
295
local
fc
=
number
.
dimenfactors
.
bp
*
sc
/
sc
296 297
-- todo: make the next more efficient:
298 299
function
metapost
.
output
(
kind
,
font
,
char
,
advance
,
shift
,
ex
)
300
local
character
=
characters
[
font
]
[
char
]
301
if
character
then
302
local
index
=
character
.
index
303
if
index
then
304
local
shapedata
=
shapes
[
font
]
305
local
glyphs
=
shapedata
.
glyphs
-- todo: subfonts fonts.shapes.indexed(font,sub)
306
if
glyphs
then
307
local
glyf
=
glyphs
[
index
]
308
if
glyf
then
309
local
units
=
1000
-- factor already takes shapedata.units into account
310
local
yfactor
=
(
sc
/
units
)
*
parameters
[
font
]
.
factor
/
655
.
36
311
local
xfactor
=
yfactor
312
local
shift
=
shift
or
0
313
local
advance
=
advance
or
0
314
local
exfactor
=
ex
or
0
315
local
wfactor
=
1
316
local
detail
=
kind
=
=
"
p
"
and
tostring
(
char
)
or
"
"
317
if
exfactor
~
=
0
then
318
wfactor
=
(
1
+
(
ex
/
units
)
/
1000
)
319
xfactor
=
xfactor
*
wfactor
320
end
321
local
paths
=
topaths
(
glyf
,
xfactor
,
yfactor
)
322
if
paths
then
323
local
code
=
f_code
(
kind
,
#
paths
,
advance
,
shift
,
detail
,
paths
)
324
return
code
,
character
.
width
*
fc
*
wfactor
325
else
326
return
"
"
,
0
327
end
328
end
329
end
330
end
331
end
332
return
s_nothing
,
10
*
sc
/
1000
333
end
334 335
-- not ok yet: leftoffset in framed not handled well
336 337
local
signal
=
-0x3FFFFFFF
-
1
338 339
function
fonts
.
metapost
.
boxtomp
(
n
,
kind
)
340 341
local
result
=
{
}
342
local
advance
=
0
-- in bp
343
local
distance
=
0
344 345
local
llx
,
lly
,
urx
,
ury
=
0
,
0
,
0
,
0
346 347
local
horizontal
,
vertical
348 349
horizontal
=
function
(
parent
,
current
,
xoffset
,
yoffset
)
350
local
dx
=
0
351
while
current
do
352
local
char
,
id
=
isglyph
(
current
)
353
if
char
then
354
local
code
,
width
=
metapost
.
output
(
kind
,
id
,
char
,
xoffset
+
dx
,
yoffset
,
getexpansion
(
current
)
)
355
result
[
#
result
+
1
]
=
code
356
dx
=
dx
+
width
357
elseif
id
=
=
disc_code
then
358
local
replace
=
getreplace
(
current
)
359
if
replace
then
360
dx
=
dx
+
horizontal
(
parent
,
replace
,
xoffset
+
dx
,
yoffset
)
361
end
362
elseif
id
=
=
kern_code
then
363
dx
=
dx
+
getkern
(
current
)
*
fc
364
elseif
id
=
=
glue_code
then
365
dx
=
dx
+
effectiveglue
(
current
,
parent
)
*
fc
366
elseif
id
=
=
hlist_code
then
367
local
list
=
getlist
(
current
)
368
if
list
then
369
horizontal
(
current
,
list
,
xoffset
+
dx
,
yoffset
-
getshift
(
current
)
*
fc
)
370
end
371
dx
=
dx
+
getwidth
(
current
)
*
fc
372
elseif
id
=
=
vlist_code
then
373
local
list
=
getlist
(
current
)
374
if
list
then
375
vertical
(
current
,
list
,
xoffset
+
dx
,
yoffset
-
getshift
(
current
)
*
fc
)
376
end
377
dx
=
dx
+
getwidth
(
current
)
*
fc
378
elseif
id
=
=
rule_code
then
379
local
wd
,
ht
,
dp
=
getwhd
(
current
)
380
if
wd
~
=
0
then
381
wd
=
wd
*
fc
382
if
ht
=
=
signal
then
383
ht
=
getheight
(
parent
)
384
end
385
if
dp
=
=
signal
then
386
dp
=
getdepth
(
parent
)
387
end
388
local
hd
=
(
ht
+
dp
)
*
fc
389
if
hd
~
=
0
and
getsubtype
(
current
)
=
=
normalrule_code
then
390
result
[
#
result
+
1
]
=
f_rule
(
kind
,
xoffset
+
dx
+
wd
/
2
,
yoffset
+
hd
/
2
,
wd
,
hd
)
391
end
392
dx
=
dx
+
wd
393
end
394
end
395
current
=
getnext
(
current
)
396
end
397
return
dx
398
end
399 400
vertical
=
function
(
parent
,
current
,
xoffset
,
yoffset
)
401
local
dy
=
getheight
(
parent
)
*
fc
402
while
current
do
403
local
id
=
getid
(
current
)
404
if
id
=
=
hlist_code
then
405
local
_
,
ht
,
dp
=
getwhd
(
current
)
406
dy
=
dy
-
ht
*
fc
407
local
list
=
getlist
(
current
)
408
if
list
then
409
horizontal
(
current
,
list
,
xoffset
+
getshift
(
current
)
*
fc
,
yoffset
+
dy
)
410
end
411
dy
=
dy
-
dp
*
fc
412
elseif
id
=
=
vlist_code
then
413
local
wd
,
ht
,
dp
=
getwhd
(
current
)
414
dy
=
dy
-
ht
*
fc
415
local
list
=
getlist
(
current
)
416
if
list
then
417
vertical
(
current
,
list
,
xoffset
+
getshift
(
current
)
*
fc
,
yoffset
+
dy
)
418
end
419
dy
=
dy
-
dp
*
fc
420
elseif
id
=
=
kern_code
then
421
dy
=
dy
-
getkern
(
current
)
*
fc
422
elseif
id
=
=
glue_code
then
423
dy
=
dy
-
effectiveglue
(
current
,
parent
)
*
fc
424
elseif
id
=
=
rule_code
then
425
local
wd
,
ht
,
dp
=
getwhd
(
current
)
426
local
hd
=
(
ht
+
dp
)
*
fc
427
if
hd
~
=
0
then
428
if
wd
=
=
signal
then
429
wd
=
getwidth
(
parent
)
*
fc
430
else
431
wd
=
wd
*
fc
432
end
433
dy
=
dy
-
ht
*
fc
434
if
wd
~
=
0
and
getsubtype
(
current
)
=
=
0
then
435
result
[
#
result
+
1
]
=
f_rule
(
kind
,
xoffset
+
wd
/
2
,
yoffset
+
dy
+
hd
/
2
,
wd
,
hd
)
436
end
437
dy
=
dy
-
dp
*
fc
438
end
439
end
440
current
=
getnext
(
current
)
441
end
442
return
dy
443
end
444 445
local
box
=
getbox
(
n
)
446
local
list
=
box
and
getlist
(
box
)
447
if
list
then
448
(
getid
(
box
)
=
=
hlist_code
and
horizontal
or
vertical
)
(
box
,
list
,
0
,
0
)
449
end
450 451
local
wd
,
ht
,
dp
=
getwhd
(
box
)
452 453
result
[
#
result
+
1
]
=
f_bounds
(
0
,
-
dp
*
fc
,
wd
*
fc
,
ht
*
fc
)
454 455
return
concat
(
result
)
456 457
end
458