font-nod.lua /size: 16 Kb    last modification: 2020-07-01 14:35
1
if
not
modules
then
modules
=
{
}
end
modules
[
'
font-nod
'
]
=
{
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>This is rather experimental. We need more control and some of this 11might become a runtime module instead. This module will be cleaned up!</p> 12--ldx]]
--
13 14
local
utfchar
=
utf
.
char
15
local
concat
,
fastcopy
=
table
.
concat
,
table
.
fastcopy
16
local
match
,
rep
=
string
.
match
,
string
.
rep
17 18
fonts
=
fonts
or
{
}
19
nodes
=
nodes
or
{
}
20 21 22
local
fonts
=
fonts
23
local
nodes
=
nodes
24
local
context
=
context
25 26
local
tracers
=
nodes
.
tracers
or
{
}
27
nodes
.
tracers
=
tracers
28 29
local
tasks
=
nodes
.
tasks
or
{
}
30
nodes
.
tasks
=
tasks
31 32
local
handlers
=
nodes
.
handlers
or
{
}
33
nodes
.
handlers
=
handlers
34 35
local
nuts
=
nodes
.
nuts
36
local
tonut
=
nuts
.
tonut
37
local
tonode
=
nuts
.
tonode
38 39
local
injections
=
nodes
.
injections
or
{
}
40
nodes
.
injections
=
injections
41 42
local
char_tracers
=
tracers
.
characters
or
{
}
43
tracers
.
characters
=
char_tracers
44 45
local
step_tracers
=
tracers
.
steppers
or
{
}
46
tracers
.
steppers
=
step_tracers
47 48
local
nodecodes
=
nodes
.
nodecodes
49 50
local
glyph_code
=
nodecodes
.
glyph
51
local
hlist_code
=
nodecodes
.
hlist
52
local
vlist_code
=
nodecodes
.
vlist
53
local
disc_code
=
nodecodes
.
disc
54
local
glue_code
=
nodecodes
.
glue
55
local
kern_code
=
nodecodes
.
kern
56
local
dir_code
=
nodecodes
.
dir
57
local
localpar_code
=
nodecodes
.
localpar
58 59
local
getnext
=
nuts
.
getnext
60
local
getprev
=
nuts
.
getprev
61
local
getid
=
nuts
.
getid
62
local
getfont
=
nuts
.
getfont
63
local
getsubtype
=
nuts
.
getsubtype
64
local
getlist
=
nuts
.
getlist
65
local
getdisc
=
nuts
.
getdisc
66
local
getreplace
=
nuts
.
getreplace
67
local
isglyph
=
nuts
.
isglyph
68
local
getkern
=
nuts
.
getkern
69
local
getdirection
=
nuts
.
getdirection
70
local
getwidth
=
nuts
.
getwidth
71 72
local
setbox
=
nuts
.
setbox
73
local
setchar
=
nuts
.
setchar
74
local
setsubtype
=
nuts
.
setsubtype
75 76
local
copy_node_list
=
nuts
.
copy_list
77
local
hpack_node_list
=
nuts
.
hpack
78
local
flush_node_list
=
nuts
.
flush_list
79
local
protect_glyphs
=
nuts
.
protect_glyphs
80
local
start_of_par
=
nuts
.
start_of_par
81 82
local
nextnode
=
nuts
.
traversers
.
node
83
local
nextglyph
=
nuts
.
traversers
.
glyph
84 85
local
nodepool
=
nuts
.
pool
86
local
new_glyph
=
nodepool
.
glyph
87 88
local
formatters
=
string
.
formatters
89
local
formatter
=
string
.
formatter
90 91
local
hashes
=
fonts
.
hashes
92 93
local
fontidentifiers
=
hashes
.
identifiers
94
local
fontdescriptions
=
hashes
.
descriptions
95
local
fontcharacters
=
hashes
.
characters
96
local
fontproperties
=
hashes
.
properties
97
local
fontparameters
=
hashes
.
parameters
98 99
local
properties
=
nodes
.
properties
.
data
100 101
local
function
freeze
(
h
,
where
)
102
for
n
in
nextnode
,
h
do
-- todo: disc but not traced anyway
103
local
p
=
properties
[
n
]
104
if
p
then
105
local
i
=
p
.
injections
if
i
then
p
.
injections
=
fastcopy
(
i
)
end
106
-- local i = r.preinjections if i then p.preinjections = fastcopy(i) end
107
-- local i = r.postinjections if i then p.postinjections = fastcopy(i) end
108
-- local i = r.replaceinjections if i then p.replaceinjections = fastcopy(i) end
109
-- only injections
110
end
111
end
112
end
113 114
function
char_tracers
.
collect
(
head
,
list
,
tag
,
n
)
115
n
=
n
or
0
116
local
ok
=
false
117
local
fn
=
nil
118
while
head
do
119
local
char
,
id
=
isglyph
(
head
)
120
if
char
then
121
local
font
=
id
122
if
font
~
=
fn
then
123
ok
,
fn
=
false
,
font
124
end
125
if
not
ok
then
126
ok
=
true
127
n
=
n
+
1
128
list
[
n
]
=
list
[
n
]
or
{
}
129
list
[
n
]
[
tag
]
=
{
}
130
end
131
local
l
=
list
[
n
]
[
tag
]
132
-- l[#l+1] = { char, font, i }
133
l
[
#
l
+
1
]
=
{
char
,
font
}
134
elseif
id
=
=
disc_code
then
135
-- skip
136
-- local pre, post, replace = getdisc(head)
137
-- if replace then
138
-- for n in nextglyph, replace do
139
-- l[#l+1] = { c, f }
140
-- end
141
-- end
142
-- if pre then
143
-- for n in nextglyph, pre do
144
-- l[#l+1] = { c, f }
145
-- end
146
-- end
147
-- if post then
148
-- for n in nextglyph, post do
149
-- l[#l+1] = { c, f }
150
-- end
151
-- end
152
else
153
ok
=
false
154
end
155
head
=
getnext
(
head
)
156
end
157
end
158 159
function
char_tracers
.
equal
(
ta
,
tb
)
160
if
#
ta
~
=
#
tb
then
161
return
false
162
else
163
for
i
=
1
,
#
ta
do
164
local
a
=
ta
[
i
]
165
local
b
=
tb
[
i
]
166
-- if a[1] ~= b[1] or a[2] ~= b[2] or a[3] ~= b[3] then
167
if
a
[
1
]
~
=
b
[
1
]
or
a
[
2
]
~
=
b
[
2
]
then
168
return
false
169
end
170
end
171
end
172
return
true
173
end
174 175
function
char_tracers
.
string
(
t
)
176
local
tt
=
{
}
177
for
i
=
1
,
#
t
do
178
tt
[
i
]
=
utfchar
(
t
[
i
]
[
1
]
)
179
end
180
return
concat
(
tt
,
"
"
)
181
end
182 183
local
f_unicode
=
formatters
[
"
%U
"
]
184
local
f_badcode
=
formatters
[
"
{%i}
"
]
185 186
function
char_tracers
.
unicodes
(
t
,
decimal
)
187
local
tt
=
{
}
188
for
i
=
1
,
#
t
do
189
local
n
=
t
[
i
]
[
1
]
190
if
n
=
=
0
then
191
tt
[
i
]
=
"
-
"
192
elseif
decimal
then
193
tt
[
i
]
=
n
194
else
195
tt
[
i
]
=
f_unicode
(
n
)
196
end
197
end
198
return
concat
(
tt
,
"
"
)
199
end
200 201
-- function char_tracers.indices(t,decimal)
202
-- local tt = { }
203
-- for i=1,#t do
204
-- local n = t[i][3]
205
-- if n == 0 then
206
-- tt[i] = "-"
207
-- elseif decimal then
208
-- tt[i] = n
209
-- else
210
-- tt[i] = f_unicode(n)
211
-- end
212
-- end
213
-- return concat(tt," ")
214
-- end
215 216
function
char_tracers
.
start
(
)
217
local
npc
=
handlers
.
characters
-- should accept nuts too
218
local
list
=
{
}
219
function
handlers
.
characters
(
head
)
220
local
n
=
#
list
221
char_tracers
.
collect
(
head
,
list
,
'
before
'
,
n
)
222
head
=
npc
(
head
)
-- for the moment tonode
223
char_tracers
.
collect
(
head
,
list
,
'
after
'
,
n
)
224
if
#
list
>
n
then
225
list
[
#
list
+
1
]
=
{
}
226
end
227
return
head
228
end
229
function
char_tracers
.
stop
(
)
230
tracers
.
list
[
'
characters
'
]
=
list
231
local
variables
=
{
232
[
'
title
'
]
=
'
ConTeXt Character Processing Information
'
,
233
[
'
color-background-one
'
]
=
lmx
.
get
(
'
color-background-yellow
'
)
,
234
[
'
color-background-two
'
]
=
lmx
.
get
(
'
color-background-purple
'
)
,
235
}
236
lmx
.
show
(
'
context-characters.lmx
'
,
variables
)
237
handlers
.
characters
=
npc
238
tasks
.
restart
(
"
processors
"
,
"
characters
"
)
239
end
240
tasks
.
restart
(
"
processors
"
,
"
characters
"
)
241
end
242 243
local
stack
=
{
}
244 245
function
tracers
.
start
(
tag
)
246
stack
[
#
stack
+
1
]
=
tag
247
local
tracer
=
tracers
[
tag
]
248
if
tracer
and
tracer
.
start
then
249
tracer
.
start
(
)
250
end
251
end
252
function
tracers
.
stop
(
)
253
local
tracer
=
stack
[
#
stack
]
254
if
tracer
and
tracer
.
stop
then
255
tracer
.
stop
(
)
256
end
257
stack
[
#
stack
]
=
nil
258
end
259 260
-- experimental
261 262
local
collection
,
collecting
,
messages
=
{
}
,
false
,
{
}
263 264
function
step_tracers
.
start
(
)
265
collecting
=
true
266
end
267 268
function
step_tracers
.
stop
(
)
269
collecting
=
false
270
end
271 272
function
step_tracers
.
reset
(
)
273
for
i
=
1
,
#
collection
do
274
local
c
=
collection
[
i
]
275
if
c
then
276
flush_node_list
(
c
)
277
end
278
end
279
collection
,
messages
=
{
}
,
{
}
280
end
281 282
function
step_tracers
.
nofsteps
(
)
283
return
context
(
#
collection
)
284
end
285 286
function
step_tracers
.
glyphs
(
n
,
i
)
287
local
c
=
collection
[
i
]
288
if
c
then
289
local
c
=
copy_node_list
(
c
)
290
local
b
=
hpack_node_list
(
c
)
-- multiple arguments
291
setbox
(
n
,
b
)
292
end
293
end
294 295
function
step_tracers
.
features
(
)
296
-- we cannot use first_glyph here as it only finds characters with subtype < 256
297
local
f
=
collection
[
1
]
298
for
n
,
char
,
font
in
nextglyph
,
f
do
299
local
tfmdata
=
fontidentifiers
[
font
]
300
local
features
=
tfmdata
.
resources
.
features
301
local
result_1
=
{
}
302
local
result_2
=
{
}
303
local
gpos
=
features
and
features
.
gpos
or
{
}
304
local
gsub
=
features
and
features
.
gsub
or
{
}
305
for
feature
,
value
in
table
.
sortedhash
(
tfmdata
.
shared
.
features
)
do
306
if
feature
=
=
"
number
"
or
feature
=
=
"
features
"
then
307
value
=
false
308
elseif
type
(
value
)
=
=
"
boolean
"
then
309
if
value
then
310
value
=
"
yes
"
311
else
312
value
=
false
313
end
314
else
315
-- use value
316
end
317
if
value
then
318
if
gpos
[
feature
]
or
gsub
[
feature
]
or
feature
=
=
"
language
"
or
feature
=
=
"
script
"
then
319
result_1
[
#
result_1
+
1
]
=
formatters
[
"
%s=%s
"
]
(
feature
,
value
)
320
else
321
result_2
[
#
result_2
+
1
]
=
formatters
[
"
%s=%s
"
]
(
feature
,
value
)
322
end
323
end
324
end
325
if
#
result_1
>
0
then
326
context
(
"
{\\bf[basic:} %, t{\\bf]}
"
,
result_1
)
327
else
328
context
(
"
{\\bf[}no basic features{\\bf]}
"
)
329
end
330
if
#
result_2
>
0
then
331
context
(
"
{\\bf[extra:} %, t{\\bf]}
"
,
result_2
)
332
else
333
context
(
"
{\\bf[}no extra features{\\bf]}
"
)
334
end
335
return
336
end
337
end
338 339
function
tracers
.
fontchar
(
font
,
char
)
340
local
n
=
new_glyph
(
font
,
char
)
341
setsubtype
(
n
,
256
)
342
context
(
tonode
(
n
)
)
343
end
344 345
function
step_tracers
.
font
(
command
)
346
local
c
=
collection
[
1
]
347
for
n
,
char
,
font
in
nextglyph
,
c
do
348
local
name
=
file
.
basename
(
fontproperties
[
font
]
.
filename
or
"
unknown
"
)
349
local
size
=
fontparameters
[
font
]
.
size
or
0
350
if
command
then
351
context
[
command
]
(
font
,
name
,
size
)
-- size in sp
352
else
353
context
(
"
[%s: %s @ %p]
"
,
font
,
name
,
size
)
354
end
355
return
356
end
357
end
358 359
local
colors
=
{
360
pre
=
{
"
darkred
"
}
,
361
post
=
{
"
darkgreen
"
}
,
362
replace
=
{
"
darkblue
"
}
,
363
}
364 365
function
step_tracers
.
codes
(
i
,
command
,
space
)
366
local
c
=
collection
[
i
]
367 368
local
function
showchar
(
c
,
f
)
369
if
command
then
370
local
d
=
fontdescriptions
[
f
]
371
local
d
=
d
and
d
[
c
]
372
context
[
command
]
(
f
,
c
,
d
and
d
.
class
or
"
"
)
373
else
374
context
(
"
[%s:U+%X]
"
,
f
,
c
)
375
end
376
end
377 378
local
function
showdisc
(
d
,
w
,
what
)
379
if
w
then
380
context
.
startcolor
(
colors
[
what
]
)
381
context
(
"
%s:
"
,
what
)
382
for
c
,
id
in
nextnode
,
w
do
383
if
id
=
=
glyph_code
then
384
local
c
,
f
=
isglyph
(
c
)
385
showchar
(
c
,
f
)
386
else
387
context
(
"
[%s]
"
,
nodecodes
[
id
]
)
388
end
389
end
390
context
[
space
]
(
)
391
context
.
stopcolor
(
)
392
end
393
end
394 395
while
c
do
396
local
char
,
id
=
isglyph
(
c
)
397
if
char
then
398
showchar
(
char
,
id
)
399
elseif
id
=
=
dir_code
or
(
id
=
=
localpar_code
and
start_of_par
(
c
)
)
then
400
context
(
"
[%s]
"
,
getdirection
(
c
)
or
"
?
"
)
401
elseif
id
=
=
disc_code
then
402
local
pre
,
post
,
replace
=
getdisc
(
c
)
403
if
pre
or
post
or
replace
then
404
context
(
"
[
"
)
405
context
[
space
]
(
)
406
showdisc
(
c
,
pre
,
"
pre
"
)
407
showdisc
(
c
,
post
,
"
post
"
)
408
showdisc
(
c
,
replace
,
"
replace
"
)
409
context
[
space
]
(
)
410
context
(
"
]
"
)
411
else
412
context
(
"
[disc]
"
)
413
end
414
else
415
context
(
"
[%s]
"
,
nodecodes
[
id
]
)
416
end
417
c
=
getnext
(
c
)
418
end
419
end
420 421
function
step_tracers
.
messages
(
i
,
command
,
split
)
422
local
list
=
messages
[
i
]
-- or { "no messages" }
423
if
list
then
424
for
i
=
1
,
#
list
do
425
local
l
=
list
[
i
]
426
if
not
command
then
427
context
(
"
(%s)
"
,
l
)
428
elseif
split
then
429
local
a
,
b
=
match
(
l
,
"
^(.-)%s*:%s*(.*)$
"
)
430
context
[
command
]
(
a
or
l
or
"
"
,
b
or
"
"
)
431
else
432
context
[
command
]
(
l
)
433
end
434
end
435
end
436
end
437 438
-- hooks into the node list processor (see otf)
439 440
function
step_tracers
.
check
(
head
)
441
if
collecting
then
442
step_tracers
.
reset
(
)
443
local
n
=
copy_node_list
(
head
)
444
freeze
(
n
,
"
check
"
)
445
injections
.
keepcounts
(
)
-- one-time
446
local
l
=
injections
.
handler
(
n
,
"
trace
"
)
447
if
l
then
-- hm, can be false
448
n
=
l
449
end
450
protect_glyphs
(
n
)
451
collection
[
1
]
=
n
452
end
453
end
454 455
function
step_tracers
.
register
(
head
)
456
if
collecting
then
457
local
nc
=
#
collection
+
1
458
if
messages
[
nc
]
then
459
local
n
=
copy_node_list
(
head
)
460
freeze
(
n
,
"
register
"
)
461
injections
.
keepcounts
(
)
-- one-time
462
local
l
=
injections
.
handler
(
n
,
"
trace
"
)
463
if
l
then
-- hm, can be false
464
n
=
l
465
end
466
protect_glyphs
(
n
)
467
collection
[
nc
]
=
n
468
end
469
end
470
end
471 472
function
step_tracers
.
message
(
str
,
...
)
473
str
=
formatter
(
str
,
...
)
474
if
collecting
then
475
local
n
=
#
collection
+
1
476
local
m
=
messages
[
n
]
477
if
not
m
then
m
=
{
}
messages
[
n
]
=
m
end
478
m
[
#
m
+
1
]
=
str
479
end
480
return
str
-- saves an intermediate var in the caller
481
end
482 483
--
484 485
local
threshold
=
65536
-- 1pt
486 487
local
function
toutf
(
list
,
result
,
nofresult
,
stopcriterium
,
nostrip
)
488
if
list
then
489
for
n
,
id
in
nextnode
,
tonut
(
list
)
do
490
if
id
=
=
glyph_code
then
491
local
c
,
f
=
isglyph
(
n
)
492
if
c
>
0
then
493
local
fc
=
fontcharacters
[
f
]
494
if
fc
then
495
local
fcc
=
fc
[
c
]
496
if
fcc
then
497
local
u
=
fcc
.
unicode
498
if
not
u
then
499
nofresult
=
nofresult
+
1
500
result
[
nofresult
]
=
utfchar
(
c
)
501
elseif
type
(
u
)
=
=
"
table
"
then
502
for
i
=
1
,
#
u
do
503
nofresult
=
nofresult
+
1
504
result
[
nofresult
]
=
utfchar
(
u
[
i
]
)
505
end
506
else
507
nofresult
=
nofresult
+
1
508
result
[
nofresult
]
=
utfchar
(
u
)
509
end
510
else
511
nofresult
=
nofresult
+
1
512
result
[
nofresult
]
=
utfchar
(
c
)
513
end
514
else
515
nofresult
=
nofresult
+
1
516
result
[
nofresult
]
=
f_unicode
(
c
)
517
end
518
else
519
nofresult
=
nofresult
+
1
520
result
[
nofresult
]
=
f_badcode
(
c
)
521
end
522
elseif
id
=
=
disc_code
then
523
local
replace
=
getreplace
(
n
)
524
result
,
nofresult
=
toutf
(
replace
,
result
,
nofresult
,
false
,
true
)
-- needed?
525
elseif
id
=
=
hlist_code
or
id
=
=
vlist_code
then
526
-- if nofresult > 0 and result[nofresult] ~= " " then
527
-- nofresult = nofresult + 1
528
-- result[nofresult] = " "
529
-- end
530
result
,
nofresult
=
toutf
(
getlist
(
n
)
,
result
,
nofresult
,
false
,
true
)
531
elseif
id
=
=
glue_code
then
532
if
nofresult
>
0
and
result
[
nofresult
]
~
=
"
"
and
getwidth
(
n
)
>
threshold
then
533
nofresult
=
nofresult
+
1
534
result
[
nofresult
]
=
"
"
535
end
536
elseif
id
=
=
kern_code
then
537
if
nofresult
>
0
and
result
[
nofresult
]
~
=
"
"
and
getkern
(
n
)
>
threshold
then
538
nofresult
=
nofresult
+
1
539
result
[
nofresult
]
=
"
"
540
end
541
end
542
if
n
=
=
stopcriterium
then
543
break
544
end
545
end
546
end
547
if
not
nostrip
and
nofresult
>
0
and
result
[
nofresult
]
=
=
"
"
then
548
result
[
nofresult
]
=
nil
549
nofresult
=
nofresult
-
1
550
end
551
return
result
,
nofresult
552
end
553 554
function
nodes
.
toutf
(
list
,
stopcriterium
)
555
local
result
,
nofresult
=
toutf
(
list
,
{
}
,
0
,
stopcriterium
)
556
return
concat
(
result
)
557
end
558