1if not modules then modules = { } end modules [ ' node-fnt ' ] = {
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
9if not context then os . exit ( ) end
10
11local next , type = next , type
12local concat , keys = table . concat , table . keys
13
14local nodes , node , fonts = nodes , node , fonts
15
16local trace_characters = false trackers . register ( " nodes.characters " , function ( v ) trace_characters = v end )
17local trace_fontrun = false trackers . register ( " nodes.fontrun " , function ( v ) trace_fontrun = v end )
18local trace_variants = false trackers . register ( " nodes.variants " , function ( v ) trace_variants = v end )
19
20
21
22local force_discrun = true directives . register ( " nodes.discrun " , function ( v ) force_discrun = v end )
23local force_boundaryrun = true directives . register ( " nodes.boundaryrun " , function ( v ) force_boundaryrun = v end )
24local force_basepass = true directives . register ( " nodes.basepass " , function ( v ) force_basepass = v end )
25local keep_redundant = false directives . register ( " nodes.keepredundant " , function ( v ) keep_redundant = v end )
26
27local report_fonts = logs . reporter ( " fonts " , " processing " )
28
29local fonthashes = fonts . hashes
30local fontdata = fonthashes . identifiers
31local fontvariants = fonthashes . variants
32local fontmodes = fonthashes . modes
33
34local otf = fonts . handlers . otf
35
36local starttiming = statistics . starttiming
37local stoptiming = statistics . stoptiming
38
39local nodecodes = nodes . nodecodes
40local boundarycodes = nodes . boundarycodes
41
42local handlers = nodes . handlers
43
44local nuts = nodes . nuts
45
46local getid = nuts . getid
47local getsubtype = nuts . getsubtype
48local getreplace = nuts . getreplace
49local getnext = nuts . getnext
50local getprev = nuts . getprev
51local getboth = nuts . getboth
52local getdata = nuts . getdata
53local getglyphdata = nuts . getglyphdata
54
55local setchar = nuts . setchar
56local setlink = nuts . setlink
57local setnext = nuts . setnext
58local setprev = nuts . setprev
59
60local isglyph = nuts . isglyph
61local ischar = nuts . ischar
62
63local nextboundary = nuts . traversers . boundary
64local nextdisc = nuts . traversers . disc
65local nextchar = nuts . traversers . char
66
67local flushnode = nuts . flush
68
69local disc_code = nodecodes . disc
70local boundary_code = nodecodes . boundary
71
72local wordboundary_code = boundarycodes . word
73
74local protectglyphs = nuts . protectglyphs
75local unprotectglyphs = nuts . unprotectglyphs
76
77local setmetatableindex = table . setmetatableindex
78
79
80
81
82
83
84local run = 0
85
86local setfontdynamics = { }
87local fontprocesses = { }
88
89setmetatableindex ( setfontdynamics , function ( t , font )
90 local tfmdata = fontdata [ font ]
91 local shared = tfmdata . shared
92 local f = shared and shared . dynamics and otf . setdynamics or false
93 if f then
94 local v = { }
95 t [ font ] = v
96 setmetatableindex ( v , function ( t , k )
97 local v = f ( font , k )
98 t [ k ] = v
99 return v
100 end )
101 return v
102 else
103 t [ font ] = false
104 return false
105 end
106end )
107
108setmetatableindex ( fontprocesses , function ( t , font )
109 local tfmdata = fontdata [ font ]
110 local shared = tfmdata . shared
111 local processes = shared and shared . processes
112 if processes and # processes > 0 then
113 t [ font ] = processes
114 return processes
115 else
116 t [ font ] = false
117 return false
118 end
119end )
120
121fonts . hashes . setdynamics = setfontdynamics
122fonts . hashes . processes = fontprocesses
123
124
125
126
127
128
129
130
131
132
133
134
135
136local ligaturing = nuts . ligaturing
137local kerning = nuts . kerning
138
139local function start_trace ( head )
140 run = run + 1
141 report_fonts ( )
142 report_fonts ( " checking node list, run %s " , run )
143 report_fonts ( )
144 local n = head
145 while n do
146 local char , id = isglyph ( n )
147 if char then
148 local font = id
149 local dynamic = getglyphdata ( n ) or 0
150 report_fonts ( " font %03i, dynamic %03i, glyph %C " , font , dynamic , char )
151 elseif id = = disc_code then
152 report_fonts ( " [disc] %s " , nodes . listtoutf ( n , true , false , n ) )
153 elseif id = = boundary_code then
154 report_fonts ( " [boundary] %i:%i " , getsubtype ( n ) , getdata ( n ) )
155 else
156 report_fonts ( " [%s] " , nodecodes [ id ] )
157 end
158 n = getnext ( n )
159 end
160end
161
162local function stop_trace ( u , usedfonts , d , dynamicfonts , b , basefonts , r , redundant )
163 report_fonts ( )
164 report_fonts ( " statics : %s " , u > 0 and concat ( keys ( usedfonts ) , " " ) or " none " )
165 report_fonts ( " dynamics: %s " , d > 0 and concat ( keys ( dynamicfonts ) , " " ) or " none " )
166 report_fonts ( " built-in: %s " , b > 0 and b or " none " )
167 report_fonts ( " removed : %s " , r > 0 and r or " none " )
168 report_fonts ( )
169end
170
171do
172
173 local usedfonts
174 local dynamicfonts
175 local basefonts
176 local basefont
177 local prevfont
178 local prevdynamic
179 local variants
180 local redundant
181 local firstnone
182 local lastfont
183 local lastproc
184 local lastnone
185
186 local d , u , b , r
187
188 local function protectnone ( )
189 protectglyphs ( firstnone , lastnone )
190 firstnone = nil
191 end
192
193 local function setnone ( n )
194 if firstnone then
195 protectnone ( )
196 end
197 if basefont then
198 basefont [ 2 ] = getprev ( n )
199 basefont = false
200 end
201 if not firstnone then
202 firstnone = n
203 end
204 lastnone = n
205 end
206
207 local function setbase ( n )
208 if firstnone then
209 protectnone ( )
210 end
211 if force_basepass then
212 if basefont then
213 basefont [ 2 ] = getprev ( n )
214 end
215 b = b + 1
216 basefont = { n , false }
217 basefonts [ b ] = basefont
218 end
219 end
220
221 local function setnode ( n , font , dynamic )
222 if firstnone then
223 protectnone ( )
224 end
225 if basefont then
226 basefont [ 2 ] = getprev ( n )
227 basefont = false
228 end
229 if dynamic > 0 then
230 local used = dynamicfonts [ font ]
231 if not used then
232 used = { }
233 dynamicfonts [ font ] = used
234 end
235 if not used [ dynamic ] then
236 local fd = setfontdynamics [ font ]
237 if fd then
238 used [ dynamic ] = fd [ dynamic ]
239 d = d + 1
240 end
241 end
242 else
243 local used = usedfonts [ font ]
244 if not used then
245 lastfont = font
246 lastproc = fontprocesses [ font ]
247 if lastproc then
248 usedfonts [ font ] = lastproc
249 u = u + 1
250 end
251 end
252 end
253 end
254
255 function handlers . characters ( head , groupcode , direction )
256
257 starttiming ( nodes )
258
259 usedfonts = { }
260 dynamicfonts = { }
261 basefonts = { }
262 basefont = nil
263 prevfont = nil
264 prevdynamic = 0
265 variants = nil
266 redundant = nil
267 firstnone = nil
268 lastfont = nil
269 lastproc = nil
270 lastnone = nil
271
272 local fontmode = nil
273
274 d , u , b , r = 0 , 0 , 0 , 0
275
276 if trace_fontrun then
277 start_trace ( head )
278 end
279
280
281
282
283 for n , char , font , dynamic in nextchar , head do
284
285 if font ~ = prevfont then
286 prevfont = font
287 fontmode = fontmodes [ font ]
288 if fontmode = = " none " then
289 prevdynamic = 0
290 variants = false
291 setnone ( n )
292 elseif fontmode = = " base " then
293 prevdynamic = 0
294 variants = false
295 setbase ( n )
296 else
297
298 prevdynamic = dynamic
299 variants = fontvariants [ font ]
300 setnode ( n , font , dynamic )
301 end
302 elseif fontmode = = " node " then
303 local dynamic = getglyphdata ( n ) or 0
304 if dynamic ~ = prevdynamic then
305 prevdynamic = dynamic
306 variants = fontvariants [ font ]
307 setnode ( n , font , dynamic )
308 end
309 elseif firstnone then
310 lastnone = n
311 end
312
313 if variants then
314 if ( char > = 0xFE00 and char < = 0xFE0F ) or ( char > = 0xE0100 and char < = 0xE01EF ) then
315
316
317 local hash = variants [ char ]
318 if hash then
319 local p = getprev ( n )
320 if p then
321 local char = ischar ( p )
322 local variant = hash [ char ]
323 if variant then
324 if trace_variants then
325 report_fonts ( " replacing %C by %C " , char , variant )
326 end
327 setchar ( p , variant )
328 if redundant then
329 r = r + 1
330 redundant [ r ] = n
331 else
332 r = 1
333 redundant = { n }
334 end
335 end
336 end
337 elseif keep_redundant then
338
339 elseif redundant then
340 r = r + 1
341 redundant [ r ] = n
342 else
343 r = 1
344 redundant = { n }
345 end
346 end
347 end
348
349 end
350
351 if firstnone then
352 protectnone ( )
353 end
354
355 if force_boundaryrun then
356
357
358
359
360
361 for b , subtype in nextboundary , head do
362 if subtype = = wordboundary_code then
363 if redundant then
364 r = r + 1
365 redundant [ r ] = b
366 else
367 r = 1
368 redundant = { b }
369 end
370 end
371 end
372
373 end
374
375 if redundant then
376 for i = 1 , r do
377 local r = redundant [ i ]
378 local p , n = getboth ( r )
379 if r = = head then
380 head = n
381 setprev ( n )
382 else
383 setlink ( p , n )
384 end
385 if b > 0 then
386 for i = 1 , b do
387 local bi = basefonts [ i ]
388 local b1 = bi [ 1 ]
389 local b2 = bi [ 2 ]
390 if b1 = = b2 then
391 if b1 = = r then
392 bi [ 1 ] = false
393 bi [ 2 ] = false
394 end
395 elseif b1 = = r then
396 bi [ 1 ] = n
397 elseif b2 = = r then
398 bi [ 2 ] = p
399 end
400 end
401 end
402 flushnode ( r )
403 end
404 end
405
406 if force_discrun then
407
408
409
410 for disc in nextdisc , head do
411
412
413 local r = getreplace ( disc )
414 if r then
415 local prevfont = nil
416 local prevdynamic = nil
417 local none = false
418 firstnone = nil
419 basefont = nil
420 for n , char , font , dynamic in nextchar , r do
421
422 if font ~ = prevfont or dynamic ~ = prevdynamic then
423 prevfont = font
424 prevdynamic = dynamic
425 local fontmode = fontmodes [ font ]
426 if fontmode = = " none " then
427 setnone ( n )
428 elseif fontmode = = " base " then
429
430 setbase ( n )
431 else
432 setnode ( n , font , dynamic )
433 end
434 elseif firstnone then
435
436 lastnone = nil
437 end
438
439
440 break
441 end
442 if firstnone then
443 protectnone ( )
444 end
445 end
446 end
447
448 end
449
450 if trace_fontrun then
451 stop_trace ( u , usedfonts , d , dynamicfonts , b , basefonts , r , redundant )
452 end
453
454
455 if u = = 0 then
456
457 elseif u = = 1 then
458 for i = 1 , # lastproc do
459 head = lastproc [ i ] ( head , lastfont , 0 , direction )
460 end
461 else
462 for font , processors in next , usedfonts do
463 for i = 1 , # processors do
464 head = processors [ i ] ( head , font , 0 , direction , u )
465 end
466 end
467 end
468 if d = = 0 then
469
470 elseif d = = 1 then
471 local font , dynamics = next ( dynamicfonts )
472 for dynamic , processors in next , dynamics do
473 for i = 1 , # processors do
474 head = processors [ i ] ( head , font , dynamic , direction )
475 end
476 end
477 else
478 for font , dynamics in next , dynamicfonts do
479 for dynamic , processors in next , dynamics do
480 for i = 1 , # processors do
481 head = processors [ i ] ( head , font , dynamic , direction , d )
482 end
483 end
484 end
485 end
486 if b = = 0 then
487
488 elseif b = = 1 then
489
490 local range = basefonts [ 1 ]
491 local start = range [ 1 ]
492 local stop = range [ 2 ]
493 if ( start or stop ) and ( start ~ = stop ) then
494 local front = head = = start
495 if stop then
496 start = ligaturing ( start , stop )
497 start = kerning ( start , stop )
498 elseif start then
499 start = ligaturing ( start )
500 start = kerning ( start )
501 end
502 if front and head ~ = start then
503 head = start
504 end
505 end
506 else
507
508 for i = 1 , b do
509 local range = basefonts [ i ]
510 local start = range [ 1 ]
511 local stop = range [ 2 ]
512 if start then
513 local front = head = = start
514 local prev = getprev ( start )
515 local next = getnext ( stop )
516 if stop then
517 start , stop = ligaturing ( start , stop )
518 start , stop = kerning ( start , stop )
519 else
520 start = ligaturing ( start )
521 start = kerning ( start )
522 end
523
524 if prev then
525 setlink ( prev , start )
526 end
527 if next then
528 setlink ( stop , next )
529 end
530
531 if front and head ~ = start then
532 head = start
533 end
534 end
535 end
536 end
537
538 stoptiming ( nodes )
539
540 if trace_characters then
541 nodes . report ( head )
542 end
543
544 return head
545 end
546
547end
548
549handlers . protectglyphs = protectglyphs
550handlers . unprotectglyphs = unprotectglyphs
551 |