1if 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
13
14local utfchar = utf . char
15local concat , fastcopy = table . concat , table . fastcopy
16local match , rep = string . match , string . rep
17
18fonts = fonts or { }
19nodes = nodes or { }
20
21
22local fonts = fonts
23local nodes = nodes
24local context = context
25
26local tracers = nodes . tracers or { }
27nodes . tracers = tracers
28
29local tasks = nodes . tasks or { }
30nodes . tasks = tasks
31
32local handlers = nodes . handlers or { }
33nodes . handlers = handlers
34
35local nuts = nodes . nuts
36local tonut = nuts . tonut
37local tonode = nuts . tonode
38
39local injections = nodes . injections or { }
40nodes . injections = injections
41
42local char_tracers = tracers . characters or { }
43tracers . characters = char_tracers
44
45local step_tracers = tracers . steppers or { }
46tracers . steppers = step_tracers
47
48local nodecodes = nodes . nodecodes
49
50local glyph_code = nodecodes . glyph
51local hlist_code = nodecodes . hlist
52local vlist_code = nodecodes . vlist
53local disc_code = nodecodes . disc
54local glue_code = nodecodes . glue
55local kern_code = nodecodes . kern
56local dir_code = nodecodes . dir
57local localpar_code = nodecodes . localpar
58
59local getnext = nuts . getnext
60local getprev = nuts . getprev
61local getid = nuts . getid
62local getfont = nuts . getfont
63local getsubtype = nuts . getsubtype
64local getlist = nuts . getlist
65local getdisc = nuts . getdisc
66local getreplace = nuts . getreplace
67local isglyph = nuts . isglyph
68local getkern = nuts . getkern
69local getdirection = nuts . getdirection
70local getwidth = nuts . getwidth
71
72local setbox = nuts . setbox
73local setchar = nuts . setchar
74local setsubtype = nuts . setsubtype
75
76local copy_node_list = nuts . copy_list
77local hpack_node_list = nuts . hpack
78local flush_node_list = nuts . flush_list
79local protect_glyphs = nuts . protect_glyphs
80local start_of_par = nuts . start_of_par
81
82local nextnode = nuts . traversers . node
83local nextglyph = nuts . traversers . glyph
84
85local nodepool = nuts . pool
86local new_glyph = nodepool . glyph
87
88local formatters = string . formatters
89local formatter = string . formatter
90
91local hashes = fonts . hashes
92
93local fontidentifiers = hashes . identifiers
94local fontdescriptions = hashes . descriptions
95local fontcharacters = hashes . characters
96local fontproperties = hashes . properties
97local fontparameters = hashes . parameters
98
99local properties = nodes . properties . data
100
101local function freeze ( h , where )
102 for n in nextnode , h do
103 local p = properties [ n ]
104 if p then
105 local i = p . injections if i then p . injections = fastcopy ( i ) end
106
107
108
109
110 end
111 end
112end
113
114function 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
133 l [ # l + 1 ] = { char , font }
134 elseif id = = disc_code then
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152 else
153 ok = false
154 end
155 head = getnext ( head )
156 end
157end
158
159function 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
167 if a [ 1 ] ~ = b [ 1 ] or a [ 2 ] ~ = b [ 2 ] then
168 return false
169 end
170 end
171 end
172 return true
173end
174
175function 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 , " " )
181end
182
183local f_unicode = formatters [ " %U " ]
184local f_badcode = formatters [ " {%i} " ]
185
186function 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 , " " )
199end
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216function char_tracers . start ( )
217 local npc = handlers . characters
218 local list = { }
219 function handlers . characters ( head )
220 local n = # list
221 char_tracers . collect ( head , list , ' before ' , n )
222 head = npc ( head )
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 " )
241end
242
243local stack = { }
244
245function 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
251end
252function tracers . stop ( )
253 local tracer = stack [ # stack ]
254 if tracer and tracer . stop then
255 tracer . stop ( )
256 end
257 stack [ # stack ] = nil
258end
259
260
261
262local collection , collecting , messages = { } , false , { }
263
264function step_tracers . start ( )
265 collecting = true
266end
267
268function step_tracers . stop ( )
269 collecting = false
270end
271
272function 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 = { } , { }
280end
281
282function step_tracers . nofsteps ( )
283 return context ( # collection )
284end
285
286function 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 )
291 setbox ( n , b )
292 end
293end
294
295function step_tracers . features ( )
296
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
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
337end
338
339function tracers . fontchar ( font , char )
340 local n = new_glyph ( font , char )
341 setsubtype ( n , 256 )
342 context ( tonode ( n ) )
343end
344
345function 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 )
352 else
353 context ( " [%s: %s @ %p] " , font , name , size )
354 end
355 return
356 end
357end
358
359local colors = {
360 pre = { " darkred " } ,
361 post = { " darkgreen " } ,
362 replace = { " darkblue " } ,
363}
364
365function 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
419end
420
421function step_tracers . messages ( i , command , split )
422 local list = messages [ i ]
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
436end
437
438
439
440function 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 ( )
446 local l = injections . handler ( n , " trace " )
447 if l then
448 n = l
449 end
450 protect_glyphs ( n )
451 collection [ 1 ] = n
452 end
453end
454
455function 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 ( )
462 local l = injections . handler ( n , " trace " )
463 if l then
464 n = l
465 end
466 protect_glyphs ( n )
467 collection [ nc ] = n
468 end
469 end
470end
471
472function 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
481end
482
483
484
485local threshold = 65536
486
487local 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 )
525 elseif id = = hlist_code or id = = vlist_code then
526
527
528
529
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
552end
553
554function nodes . toutf ( list , stopcriterium )
555 local result , nofresult = toutf ( list , { } , 0 , stopcriterium )
556 return concat ( result )
557end
558 |