1if not modules then modules = { } end modules ['font-otj'] = {
2 version = 1.001,
3 optimize = true,
4 comment = "companion to font-lib.mkiv",
5 author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
6 copyright = "PRAGMA ADE / ConTeXt Development Team",
7 license = "see context related readme files",
8}
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35if not nodes.properties then return end
36
37local next, rawget, tonumber = next, rawget, tonumber
38local fastcopy = table.fastcopy
39
40local registertracker = trackers.register
41local registerdirective = directives.register
42
43local trace_injections = false registertracker("fonts.injections", function(v) trace_injections = v end)
44local trace_marks = false registertracker("fonts.injections.marks", function(v) trace_marks = v end)
45local trace_cursive = false registertracker("fonts.injections.cursive", function(v) trace_cursive = v end)
46local trace_spaces = false registertracker("fonts.injections.spaces", function(v) trace_spaces = v end)
47
48
49
50
51
52
53
54local report_injections = logs.reporter("fonts","injections")
55local report_spaces = logs.reporter("fonts","spaces")
56
57local attributes, nodes, node = attributes, nodes, node
58
59fonts = fonts
60local hashes = fonts.hashes
61local fontdata = hashes.identifiers
62local fontmarks = hashes.marks
63local parameters = fonts.hashes.parameters
64
65
66nodes.injections = nodes.injections or { }
67local injections = nodes.injections
68
69local tracers = nodes.tracers
70local setcolor = tracers and tracers.colors.set
71local resetcolor = tracers and tracers.colors.reset
72
73local nodecodes = nodes.nodecodes
74local glyph_code = nodecodes.glyph
75local disc_code = nodecodes.disc
76local kern_code = nodecodes.kern
77local glue_code = nodecodes.glue
78
79local nuts = nodes.nuts
80local nodepool = nuts.pool
81
82local tonode = nuts.tonode
83local tonut = nuts.tonut
84
85local getnext = nuts.getnext
86local getprev = nuts.getprev
87local getid = nuts.getid
88local getchar = nuts.getchar
89local getcharspec = nuts.getcharspec
90local setchar = nuts.setchar
91
92
93local getoffsets = nuts.getoffsets
94local getxscale = nuts.getxscale
95local getyscale = nuts.getyscale
96local getxyscales = nuts.getxyscales
97local xscaled = nuts.xscaled
98local yscaled = nuts.yscaled
99local getboth = nuts.getboth
100local getdisc = nuts.getdisc
101local setdisc = nuts.setdisc
102local getreplace = nuts.getreplace
103local setreplace = nuts.setreplace
104local setoffsets = nuts.setoffsets
105local addxoffset = nuts.addxoffset
106local addyoffset = nuts.addyoffset
107local ischar = nuts.ischar
108local isnextchar = nuts.isnextchar
109local getkern = nuts.getkern
110local setkern = nuts.setkern
111local setlink = nuts.setlink
112local setwidth = nuts.setwidth
113local getwidth = nuts.getwidth
114local addxymargins = nuts.addxymargins
115local copynode = nuts.copy
116local setattrlist = nuts.setattrlist
117
118local nextchar = nuts.traversers.char
119local nextglue = nuts.traversers.glue
120
121local insertnodebefore = nuts.insertbefore
122local insertnodeafter = nuts.insertafter
123
124local properties = nodes.properties.data
125
126local fontkern = nuts.pool and nuts.pool.fontkern
127local spacefontkern = nuts.pool and nuts.pool.spacefontkern
128
129local function somekern(makekern,amount,current)
130 local kern = makekern(amount)
131 setattrlist(kern,current)
132 return kern
133end
134
135local usespacefontkerns = false
136local useadvance = false
137
138directives.register("fonts.injections.usespacefontkerns", function(v)
139 if v then
140 report_injections("using spacefontkerns for space kerns (tracing only)")
141 end
142 usespacefontkerns = v
143end)
144
145registerdirective("fonts.injections.method", function(v)
146 useadvance = v == "advance"
147end)
148
149function injections.installnewkern() end
150
151local nofregisteredkerns = 0
152local nofregisteredpositions = 0
153local nofregisteredmarks = 0
154local nofregisteredcursives = 0
155local keepregisteredcounts = false
156
157function injections.keepcounts()
158 keepregisteredcounts = true
159end
160
161function injections.resetcounts()
162 nofregisteredkerns = 0
163 nofregisteredpositions = 0
164 nofregisteredmarks = 0
165 nofregisteredcursives = 0
166 keepregisteredcounts = false
167end
168
169
170
171function injections.reset(n)
172 local p = rawget(properties,n)
173 if p then
174 p.injections = false
175 else
176 properties[n] = false
177 end
178end
179
180function injections.copy(target,source)
181 local sp = rawget(properties,source)
182 if sp then
183 local tp = rawget(properties,target)
184 local si = sp.injections
185 if si then
186 si = fastcopy(si)
187 if tp then
188 tp.injections = si
189 else
190 properties[target] = {
191 injections = si,
192 }
193 end
194 elseif tp then
195 tp.injections = false
196 else
197 properties[target] = { injections = { } }
198 end
199 else
200 local tp = rawget(properties,target)
201 if tp then
202 tp.injections = false
203 else
204 properties[target] = false
205 end
206 end
207end
208
209function injections.setligaindex(n,index)
210 local p = rawget(properties,n)
211 if p then
212 local i = p.injections
213 if i then
214 i.ligaindex = index
215 else
216 p.injections = {
217 ligaindex = index
218 }
219 end
220 else
221 properties[n] = {
222 injections = {
223 ligaindex = index
224 }
225 }
226 end
227end
228
229function injections.getligaindex(n,default)
230 local p = rawget(properties,n)
231 if p then
232 local i = p.injections
233 if i then
234 return i.ligaindex or default
235 end
236 end
237 return default
238end
239
240function injections.setcursive(start,nxt,factor,rlmode,exit,entry,tfmstart,tfmnext,r2lflag)
241
242
243
244
245
246
247
248
249 local dx = factor*(exit[1]-entry[1])
250 local dy = -factor*(exit[2]-entry[2])
251 local ws = tfmstart.width
252 local wn = tfmnext.width
253 nofregisteredcursives = nofregisteredcursives + 1
254 if rlmode < 0 then
255 dx = -(dx + wn)
256 else
257 dx = dx - ws
258 end
259 if dx == 0 then
260
261 dx = 0
262 end
263
264 local p = rawget(properties,start)
265 if p then
266 local i = p.injections
267 if i then
268 i.cursiveanchor = true
269 else
270 p.injections = {
271 cursiveanchor = true,
272 }
273 end
274 else
275 properties[start] = {
276 injections = {
277 cursiveanchor = true,
278 },
279 }
280 end
281 local p = rawget(properties,nxt)
282 if p then
283 local i = p.injections
284 if i then
285 i.cursivex = dx
286 i.cursivey = dy
287 else
288 p.injections = {
289 cursivex = dx,
290 cursivey = dy,
291 }
292 end
293 else
294 properties[nxt] = {
295 injections = {
296 cursivex = dx,
297 cursivey = dy,
298 },
299 }
300 end
301 return dx, dy, nofregisteredcursives
302end
303
304
305
306function injections.setposition(kind,current,factor,rlmode,spec,injection)
307 local x = factor * (spec[1] or 0)
308 local y = factor * (spec[2] or 0)
309 local w = factor * (spec[3] or 0)
310 local h = factor * (spec[4] or 0)
311 if x ~= 0 or w ~= 0 or y ~= 0 or h ~= 0 then
312 local yoffset = y - h
313 local leftkern = x
314 local rightkern = w - x
315 if leftkern ~= 0 or rightkern ~= 0 or yoffset ~= 0 then
316 nofregisteredpositions = nofregisteredpositions + 1
317 if rlmode and rlmode < 0 then
318 leftkern, rightkern = rightkern, leftkern
319 end
320 if not injection then
321 injection = "injections"
322 end
323 local p = rawget(properties,current)
324 if p then
325 local i = p[injection]
326 if i then
327 if leftkern ~= 0 then
328 i.leftkern = (i.leftkern or 0) + leftkern
329 end
330 if rightkern ~= 0 then
331 i.rightkern = (i.rightkern or 0) + rightkern
332 end
333 if yoffset ~= 0 then
334 i.yoffset = (i.yoffset or 0) + yoffset
335 end
336 elseif leftkern ~= 0 or rightkern ~= 0 then
337 p[injection] = {
338 leftkern = leftkern,
339 rightkern = rightkern,
340 yoffset = yoffset,
341 }
342 else
343 p[injection] = {
344 yoffset = yoffset,
345 }
346 end
347 elseif leftkern ~= 0 or rightkern ~= 0 then
348 properties[current] = {
349 [injection] = {
350 leftkern = leftkern,
351 rightkern = rightkern,
352 yoffset = yoffset,
353 },
354 }
355 else
356 properties[current] = {
357 [injection] = {
358 yoffset = yoffset,
359 },
360 }
361 end
362 return x, y, w, h, nofregisteredpositions
363 end
364 end
365 return x, y, w, h
366end
367
368
369
370
371
372function injections.setkern(current,factor,rlmode,x,injection)
373 local dx = factor * x
374 if dx ~= 0 then
375 nofregisteredkerns = nofregisteredkerns + 1
376 local p = rawget(properties,current)
377 if not injection then
378 injection = "injections"
379 end
380 if p then
381 local i = p[injection]
382 if i then
383 i.leftkern = dx + (i.leftkern or 0)
384 else
385 p[injection] = {
386 leftkern = dx,
387 }
388 end
389 else
390 properties[current] = {
391 [injection] = {
392 leftkern = dx,
393 },
394 }
395 end
396 return dx, nofregisteredkerns
397 else
398 return 0, 0
399 end
400end
401
402
403
404
405
406function injections.setmove(current,factor,rlmode,x,injection)
407 local dx = factor * x
408 if dx ~= 0 then
409 nofregisteredkerns = nofregisteredkerns + 1
410 local p = rawget(properties,current)
411 if not injection then
412 injection = "injections"
413 end
414 if rlmode and rlmode < 0 then
415
416
417 if p then
418 local i = p[injection]
419 if i then
420 i.rightkern = dx + (i.rightkern or 0)
421 else
422 p[injection] = {
423 rightkern = dx,
424 }
425 end
426 else
427 properties[current] = {
428 [injection] = {
429 rightkern = dx,
430 },
431 }
432 end
433 else
434 if p then
435 local i = p[injection]
436 if i then
437 i.leftkern = dx + (i.leftkern or 0)
438 else
439 p[injection] = {
440 leftkern = dx,
441 }
442 end
443 else
444 properties[current] = {
445 [injection] = {
446 leftkern = dx,
447 },
448 }
449 end
450 end
451 return dx, nofregisteredkerns
452 else
453 return 0, 0
454 end
455end
456
457function injections.setmark(start,base,factor,rlmode,ba,ma,tfmbase,mkmk,checkmark)
458 local dx = factor*(ba[1]-ma[1])
459 local dy = factor*(ba[2]-ma[2])
460 nofregisteredmarks = nofregisteredmarks + 1
461 if rlmode >= 0 then
462 dx = tfmbase.width - dx
463 end
464 local p = rawget(properties,start)
465
466 if p then
467 local i = p.injections
468 if i then
469 if i.markmark then
470
471 else
472
473
474
475
476
477
478
479
480
481 i.markx = dx
482 i.marky = dy
483 i.markdir = rlmode or 0
484 i.markbase = nofregisteredmarks
485 i.markbasenode = base
486 i.markmark = mkmk
487 i.checkmark = checkmark
488 end
489 else
490 p.injections = {
491 markx = dx,
492 marky = dy,
493 markdir = rlmode or 0,
494 markbase = nofregisteredmarks,
495 markbasenode = base,
496 markmark = mkmk,
497 checkmark = checkmark,
498 }
499 end
500 else
501 properties[start] = {
502 injections = {
503 markx = dx,
504 marky = dy,
505 markdir = rlmode or 0,
506 markbase = nofregisteredmarks,
507 markbasenode = base,
508 markmark = mkmk,
509 checkmark = checkmark,
510 },
511 }
512 end
513 return dx, dy, nofregisteredmarks
514end
515
516local function dir(n)
517 return (n and n<0 and "r-to-l") or (n and n>0 and "l-to-r") or "unset"
518end
519
520local function showchar(n,nested)
521 local char, font = getcharspec(n)
522 report_injections("%wfont %s, char %U, glyph %c",nested and 2 or 0,font,char,char)
523end
524
525local function show(n,what,nested,symbol)
526 if n then
527 local p = rawget(properties,n)
528 if p then
529 local i = p[what]
530 if i then
531 local leftkern = i.leftkern or 0
532 local rightkern = i.rightkern or 0
533 local yoffset = i.yoffset or 0
534 local markx = i.markx or 0
535 local marky = i.marky or 0
536 local markdir = i.markdir or 0
537 local markbase = i.markbase or 0
538 local cursivex = i.cursivex or 0
539 local cursivey = i.cursivey or 0
540 local ligaindex = i.ligaindex or 0
541 local cursbase = i.cursiveanchor
542 local margin = nested and 4 or 2
543
544 if rightkern ~= 0 or yoffset ~= 0 then
545 report_injections("%w%s pair: lx %p, rx %p, dy %p",margin,symbol,leftkern,rightkern,yoffset)
546 elseif leftkern ~= 0 then
547 report_injections("%w%s kern: dx %p",margin,symbol,leftkern)
548 end
549 if markx ~= 0 or marky ~= 0 or markbase ~= 0 then
550 report_injections("%w%s mark: dx %p, dy %p, dir %s, base %s",margin,symbol,markx,marky,markdir,markbase ~= 0 and "yes" or "no")
551 end
552 if cursivex ~= 0 or cursivey ~= 0 then
553 if cursbase then
554 report_injections("%w%s curs: base dx %p, dy %p",margin,symbol,cursivex,cursivey)
555 else
556 report_injections("%w%s curs: dx %p, dy %p",margin,symbol,cursivex,cursivey)
557 end
558 elseif cursbase then
559 report_injections("%w%s curs: base",margin,symbol)
560 end
561 if ligaindex ~= 0 then
562 report_injections("%w%s liga: index %i",margin,symbol,ligaindex)
563 end
564 end
565 end
566 end
567end
568
569local function showsub(n,what,where)
570 report_injections("begin subrun: %s",where)
571 for n in nextchar, n do
572 showchar(n,where)
573 show(n,what,where," ")
574 end
575 report_injections("end subrun")
576end
577
578local function trace(head,where)
579 report_injections()
580 report_injections("begin run %s: %s kerns, %s positions, %s marks and %s cursives registered",
581 where or "",nofregisteredkerns,nofregisteredpositions,nofregisteredmarks,nofregisteredcursives)
582 local n = head
583 while n do
584 local id = getid(n)
585 if id == glyph_code then
586 showchar(n)
587 show(n,"injections",false," ")
588 show(n,"preinjections",false,"<")
589 show(n,"postinjections",false,">")
590 show(n,"replaceinjections",false,"=")
591 show(n,"emptyinjections",false,"*")
592 elseif id == disc_code then
593 local pre, post, replace = getdisc(n)
594 if pre then
595 showsub(pre,"preinjections","pre")
596 end
597 if post then
598 showsub(post,"postinjections","post")
599 end
600 if replace then
601 showsub(replace,"replaceinjections","replace")
602 end
603 show(n,"emptyinjections",false,"*")
604 end
605 n = getnext(n)
606 end
607 report_injections("end run")
608end
609
610local function show_result(head)
611 local current = head
612 local skipping = false
613 while current do
614 local id = getid(current)
615 if id == glyph_code then
616 local w = getwidth(current)
617 local x, y = getoffsets(current)
618 report_injections("char: %C, width %p, xoffset %p, yoffset %p",getchar(current),w,x,y)
619 skipping = false
620 elseif id == kern_code then
621 report_injections("kern: %p",getkern(current))
622 skipping = false
623 elseif not skipping then
624 report_injections()
625 skipping = true
626 end
627 current = getnext(current)
628 end
629 report_injections()
630end
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827local function inject_kerns_only_kerns(head,where)
828 if trace_injections then
829 trace(head,"kerns")
830 end
831 local current = head
832 local prev
833 local prevdisc
834 local pre
835 local post
836 local replace
837 local pretail
838 local posttail
839 local replacetail
840 while current do
841 local next, char, id = isnextchar(current)
842 if char then
843 local p = rawget(properties,current)
844 if p then
845 local i = p.injections
846 if i then
847
848 local leftkern = i.leftkern
849 if leftkern and leftkern ~= 0 then
850 leftkern = xscaled(current,leftkern)
851 if prev and getid(prev) == glue_code then
852 if usespacefontkerns then
853 head = insertnodebefore(head,current,spacefontkern(leftkern))
854 else
855 setwidth(prev,getwidth(prev) + leftkern)
856 end
857 else
858 head = insertnodebefore(head,current,somekern(fontkern,leftkern,current))
859 end
860 end
861 end
862 if prevdisc then
863 local done = false
864 if post then
865 local i = p.postinjections
866 if i then
867 local leftkern = i.leftkern
868 if leftkern and leftkern ~= 0 then
869 setlink(posttail,somekern(fontkern,xscaled(current,leftkern),current))
870 done = true
871 end
872 end
873 end
874 if replace then
875 local i = p.replaceinjections
876 if i then
877 local leftkern = i.leftkern
878 if leftkern and leftkern ~= 0 then
879 setlink(replacetail,somekern(fontkern,xscaled(current,leftkern),current))
880 done = true
881 end
882 end
883 else
884 local i = p.emptyinjections
885 if i then
886
887 local leftkern = i.leftkern
888 if leftkern and leftkern ~= 0 then
889 replace = somekern(fontkern,xscaled(current,leftkern),current)
890 done = true
891 end
892 end
893 end
894 if done then
895 setdisc(prevdisc,pre,post,replace)
896 end
897 end
898 end
899 prevdisc = nil
900
901 elseif char == false then
902
903 prevdisc = nil
904
905 elseif id == disc_code then
906 pre, post, replace, pretail, posttail, replacetail = getdisc(current,true)
907 local done = false
908 if pre then
909
910 for n in nextchar, pre do
911 local p = rawget(properties,n)
912 if p then
913 local i = p.injections or p.preinjections
914 if i then
915 local leftkern = i.leftkern
916 if leftkern and leftkern ~= 0 then
917 pre = insertnodebefore(pre,n,somekern(fontkern,xscaled(n,leftkern),n))
918 done = true
919 end
920 end
921 end
922 end
923 end
924 if post then
925
926 for n in nextchar, post do
927 local p = rawget(properties,n)
928 if p then
929 local i = p.injections or p.postinjections
930 if i then
931 local leftkern = i.leftkern
932 if leftkern and leftkern ~= 0 then
933 post = insertnodebefore(post,n,somekern(fontkern,xscaled(n,leftkern),n))
934 done = true
935 end
936 end
937 end
938 end
939 end
940 if replace then
941
942 for n in nextchar, replace do
943 local p = rawget(properties,n)
944 if p then
945 local i = p.injections or p.replaceinjections
946 if i then
947 local leftkern = i.leftkern
948 if leftkern and leftkern ~= 0 then
949 replace = insertnodebefore(replace,n,somekern(fontkern,xscaled(n,leftkern),n))
950 done = true
951 end
952 end
953 end
954 end
955 end
956 if done then
957 setdisc(current,pre,post,replace)
958 end
959
960 prevdisc = current
961 else
962
963 prevdisc = nil
964 end
965 prev = current
966 current = next
967 end
968
969 if keepregisteredcounts then
970 keepregisteredcounts = false
971 else
972 nofregisteredkerns = 0
973 end
974 if trace_injections then
975 show_result(head)
976 end
977 return head
978end
979
980local function inject_kerns_only_margins(head,where)
981 if trace_injections then
982 trace(head,"kerns")
983 end
984 local current = head
985 local prevdisc
986 local pre
987 local post
988 local replace
989 local pretail
990 local posttail
991 local replacetail
992 while current do
993 local next, char, id = isnextchar(current)
994 if char then
995 local p = rawget(properties,current)
996 if p then
997 if prevdisc then
998 if post then
999 local i = p.postinjections
1000 if i then
1001 local leftkern = i.leftkern
1002 if leftkern and leftkern ~= 0 then
1003 addxymargins(posttail,false,-leftkern)
1004 end
1005 end
1006 end
1007 if replace then
1008 local i = p.replaceinjections
1009 if i then
1010 local leftkern = i.leftkern
1011 if leftkern and leftkern ~= 0 then
1012 addxymargins(replacetail,false,-leftkern)
1013 end
1014 end
1015 else
1016 local i = p.emptyinjections
1017 if i then
1018 local leftkern = i.leftkern
1019 if leftkern and leftkern ~= 0 then
1020
1021 addxymargins(current,-leftkern)
1022 end
1023 end
1024 end
1025 end
1026
1027 local i = p.injections
1028 if i then
1029 local leftkern = i.leftkern
1030 if leftkern and leftkern ~= 0 then
1031 addxymargins(current,-leftkern)
1032 end
1033 end
1034 end
1035 prevdisc = nil
1036 elseif char == false then
1037 prevdisc = nil
1038 elseif id == disc_code then
1039 pre, post, replace, pretail, posttail, replacetail = getdisc(current,true)
1040 if pre then
1041 for n in nextchar, pre do
1042 local p = rawget(properties,n)
1043 if p then
1044 local i = p.injections or p.preinjections
1045 if i then
1046 local leftkern = i.leftkern
1047 if leftkern and leftkern ~= 0 then
1048 addxymargins(n,-leftkern)
1049 end
1050 end
1051 end
1052 end
1053 end
1054 if post then
1055 for n in nextchar, post do
1056 local p = rawget(properties,n)
1057 if p then
1058 local i = p.injections or p.postinjections
1059 if i then
1060 local leftkern = i.leftkern
1061 if leftkern and leftkern ~= 0 then
1062 addxymargins(n,-leftkern)
1063 end
1064 end
1065 end
1066 end
1067 end
1068 if replace then
1069 for n in nextchar, replace do
1070 local p = rawget(properties,n)
1071 if p then
1072 local i = p.injections or p.replaceinjections
1073 if i then
1074 local leftkern = i.leftkern
1075 if leftkern and leftkern ~= 0 then
1076 addxymargins(n,-leftkern)
1077 end
1078 end
1079 end
1080 end
1081 end
1082 prevdisc = current
1083 else
1084 prevdisc = nil
1085 end
1086 current = next
1087 end
1088 if keepregisteredcounts then
1089 keepregisteredcounts = false
1090 else
1091 nofregisteredkerns = 0
1092 end
1093 if trace_injections then
1094 show_result(head)
1095 end
1096 return head
1097end
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417local function inject_positions_only_kerns(head,where)
1418 if trace_injections then
1419 trace(head,"positions")
1420 end
1421 local current = head
1422 local prev = nil
1423 local next = nil
1424 local prevdisc = nil
1425 local prevglyph = nil
1426 local pre = nil
1427 local post = nil
1428 local replace = nil
1429 local pretail = nil
1430 local posttail = nil
1431 local replacetail = nil
1432 while current do
1433 local next, char, id = isnextchar(current)
1434 if char then
1435 local p = rawget(properties,current)
1436 if p then
1437 local i = p.injections
1438 if i then
1439
1440 local yoffset = i.yoffset
1441 if yoffset and yoffset ~= 0 then
1442
1443 addyoffset(current,yscaled(current,yoffset))
1444 end
1445 local leftkern = i.leftkern or 0
1446 local rightkern = i.rightkern or 0
1447 if leftkern ~= 0 then
1448 leftkern = xscaled(current,leftkern)
1449 end
1450 if rightkern ~= 0 then
1451 rightkern = xscaled(current,rightkern)
1452 end
1453 if leftkern ~= 0 then
1454 if leftkern == -rightkern then
1455 addxoffset(current,leftkern)
1456 rightkern = 0
1457 elseif prev and getid(prev) == glue_code then
1458 if usespacefontkerns then
1459 head = insertnodebefore(head,current,spacefontkern(leftkern))
1460 else
1461 setwidth(prev,getwidth(prev)+leftkern)
1462 end
1463 else
1464 head = insertnodebefore(head,current,somekern(fontkern,leftkern,current))
1465 end
1466 end
1467 if rightkern ~= 0 then
1468 if next and getid(next) == glue_code then
1469 if usespacefontkerns then
1470 insertnodeafter(head,current,spacefontkern(rightkern))
1471 else
1472 setwidth(next, getwidth(next)+rightkern)
1473 end
1474 else
1475 insertnodeafter(head,current,somekern(fontkern,rightkern,current))
1476 end
1477 end
1478 elseif next then
1479 local i = p.emptyinjections
1480 if i then
1481
1482 local rightkern = i.rightkern
1483 if rightkern and rightkern ~= 0 and getid(next) == disc_code then
1484 local replace = getreplace(next)
1485 if replace then
1486
1487 else
1488 setreplace(next,somekern(fontkern,xscaled(current,rightkern),current))
1489 end
1490 end
1491 end
1492 end
1493 if prevdisc then
1494 local done = false
1495 if post then
1496 local i = p.postinjections
1497 if i then
1498 local leftkern = i.leftkern
1499 if leftkern and leftkern ~= 0 then
1500 setlink(posttail,somekern(fontkern,xscaled(current,leftkern),current))
1501 done = true
1502 end
1503 end
1504 end
1505 if replace then
1506 local i = p.replaceinjections
1507 if i then
1508 local leftkern = i.leftkern
1509 if leftkern and leftkern ~= 0 then
1510 setlink(replacetail,somekern(fontkern,xscaled(current,leftkern),current))
1511 done = true
1512 end
1513 end
1514 else
1515 local i = p.emptyinjections
1516 if i then
1517
1518 local leftkern = i.leftkern
1519 if leftkern and leftkern ~= 0 then
1520 replace = somekern(fontkern,xscaled(current,leftkern),current)
1521 done = true
1522 end
1523 end
1524 end
1525 if done then
1526 setdisc(prevdisc,pre,post,replace)
1527 end
1528 end
1529 end
1530 prevdisc = nil
1531 prevglyph = current
1532 elseif char == false then
1533 prevdisc = nil
1534 prevglyph = current
1535 elseif id == disc_code then
1536 pre, post, replace, pretail, posttail, replacetail = getdisc(current,true)
1537 local done = false
1538 if pre then
1539
1540 for n in nextchar, pre do
1541 local p = rawget(properties,n)
1542 if p then
1543 local i = p.injections or p.preinjections
1544 if i then
1545 local yoffset = i.yoffset
1546 local leftkern = i.leftkern
1547 local rightkern = i.rightkern
1548 if yoffset and yoffset ~= 0 then
1549 addyoffset(n,yscaled(n,yoffset))
1550 end
1551 if leftkern and leftkern ~= 0 then
1552 pre = insertnodebefore(pre,n,somekern(fontkern,xscaled(n,leftkern),n))
1553 done = true
1554 end
1555 if rightkern and rightkern ~= 0 then
1556 insertnodeafter(pre,n,somekern(fontkern,xscaled(n,rightkern),n))
1557 done = true
1558 end
1559 end
1560 end
1561 end
1562 end
1563 if post then
1564
1565 for n in nextchar, post do
1566 local p = rawget(properties,n)
1567 if p then
1568 local i = p.injections or p.postinjections
1569 if i then
1570 local yoffset = i.yoffset
1571 local leftkern = i.leftkern
1572 local rightkern = i.rightkern
1573 if yoffset and yoffset ~= 0 then
1574 addyoffset(n,yscaled(n,yoffset))
1575 end
1576 if leftkern and leftkern ~= 0 then
1577 post = insertnodebefore(post,n,somekern(fontkern,xscaled(n,leftkern),n))
1578 done = true
1579 end
1580 if rightkern and rightkern ~= 0 then
1581 insertnodeafter(post,n,somekern(fontkern,xscaled(n,rightkern),n))
1582 done = true
1583 end
1584 end
1585 end
1586 end
1587 end
1588 if replace then
1589
1590 for n in nextchar, replace do
1591 local p = rawget(properties,n)
1592 if p then
1593 local i = p.injections or p.replaceinjections
1594 if i then
1595 local yoffset = i.yoffset
1596 local leftkern = i.leftkern
1597 local rightkern = i.rightkern
1598 if yoffset and yoffset ~= 0 then
1599 addyoffset(n,yscaled(n,yoffset))
1600 end
1601 if leftkern and leftkern ~= 0 then
1602 replace = insertnodebefore(replace,n,somekern(fontkern,xscaled(n,leftkern),n))
1603 done = true
1604 end
1605 if rightkern and rightkern ~= 0 then
1606 insertnodeafter(replace,n,somekern(fontkern,xscaled(n,rightkern),n))
1607 done = true
1608 end
1609 end
1610 end
1611 end
1612 end
1613 if prevglyph then
1614
1615 if pre then
1616 local p = rawget(properties,prevglyph)
1617 if p then
1618 local i = p.preinjections
1619 if i then
1620
1621 local rightkern = i.rightkern
1622 if rightkern and rightkern ~= 0 then
1623 pre = insertnodebefore(pre,pre,somekern(fontkern,xscaled(prevglyph,rightkern),prevglyph))
1624 done = true
1625 end
1626 end
1627 end
1628 end
1629 if replace then
1630 local p = rawget(properties,prevglyph)
1631 if p then
1632 local i = p.replaceinjections
1633 if i then
1634
1635 local rightkern = i.rightkern
1636 if rightkern and rightkern ~= 0 then
1637 replace = insertnodebefore(replace,replace,somekern(fontkern,xscaled(prevglyph,rightkern),prevglyph))
1638 done = true
1639 end
1640 end
1641 end
1642 end
1643 end
1644 if done then
1645 setdisc(current,pre,post,replace)
1646 end
1647 prevglyph = nil
1648 prevdisc = current
1649 else
1650 prevglyph = nil
1651 prevdisc = nil
1652 end
1653 prev = current
1654 current = next
1655 end
1656
1657 if keepregisteredcounts then
1658 keepregisteredcounts = false
1659 else
1660 nofregisteredpositions = 0
1661 end
1662 if trace_injections then
1663 show_result(head)
1664 end
1665 return head
1666end
1667
1668local function inject_positions_only_margins(head,where)
1669 if trace_injections then
1670 trace(head,"positions")
1671 end
1672 local current = head
1673 local prev = nil
1674 local next = nil
1675 local prevdisc = nil
1676 local prevglyph = nil
1677 local pre = nil
1678 local post = nil
1679 local replace = nil
1680 local pretail = nil
1681 local posttail = nil
1682 local replacetail = nil
1683 while current do
1684 local next, char, id = isnextchar(current)
1685 if char then
1686 local p = rawget(properties,current)
1687 if p then
1688 local i = p.injections
1689 if i then
1690
1691 local yoffset = i.yoffset or 0
1692 local leftkern = i.leftkern or 0
1693 local rightkern = i.rightkern or 0
1694 if leftkern ~= 0 or rightkern ~= 0 or yoffset ~= 0 then
1695 addxymargins(n,-leftkern,-rightkern,yoffset)
1696 end
1697 elseif next then
1698 local i = p.emptyinjections
1699 if i then
1700
1701 local rightkern = i.rightkern
1702 if rightkern and rightkern ~= 0 and getid(next) == disc_code then
1703 local replace = getreplace(next)
1704 if replace then
1705
1706 else
1707 setreplace(next,somekern(fontkern,xscaled(current,rightkern),current))
1708 end
1709 end
1710 end
1711 end
1712 if prevdisc then
1713 if post then
1714 local i = p.postinjections
1715 if i then
1716 local leftkern = i.leftkern
1717 if leftkern and leftkern ~= 0 then
1718 addxymargins(posttail,-leftkern)
1719 end
1720 end
1721 end
1722 if replace then
1723 local i = p.replaceinjections
1724 if i then
1725 local leftkern = i.leftkern
1726 if leftkern and leftkern ~= 0 then
1727 addxymargins(replacetail,-leftkern)
1728 end
1729 end
1730 else
1731 local i = p.emptyinjections
1732 if i then
1733
1734 local leftkern = i.leftkern
1735 if leftkern and leftkern ~= 0 then
1736
1737 addxymargins(current,-leftkern)
1738 end
1739 end
1740 end
1741 end
1742 end
1743 prevdisc = nil
1744 prevglyph = current
1745 elseif char == false then
1746 prevdisc = nil
1747 prevglyph = current
1748 elseif id == disc_code then
1749 pre, post, replace, pretail, posttail, replacetail = getdisc(current,true)
1750 if pre then
1751
1752 for n in nextchar, pre do
1753 local p = rawget(properties,n)
1754 if p then
1755 local i = p.injections or p.preinjections
1756 if i then
1757 local yoffset = i.yoffset or 0
1758 local leftkern = i.leftkern or 0
1759 local rightkern = i.rightkern or 0
1760 if leftkern ~= 0 or rightkern ~= 0 or yoffset ~= 0 then
1761 addxymargins(n,-leftkern,-rightkern,yoffset)
1762 end
1763 end
1764 end
1765 end
1766 end
1767 if post then
1768
1769 for n in nextchar, post do
1770 local p = rawget(properties,n)
1771 if p then
1772 local i = p.injections or p.postinjections
1773 if i then
1774 local yoffset = i.yoffset or 0
1775 local leftkern = i.leftkern or 0
1776 local rightkern = i.rightkern or 0
1777 if leftkern ~= 0 or rightkern ~= 0 or yoffset ~= 0 then
1778 addxymargins(n,-leftkern,-rightkern,yoffset)
1779 end
1780 end
1781 end
1782 end
1783 end
1784 if replace then
1785
1786 for n in nextchar, replace do
1787 local p = rawget(properties,n)
1788 if p then
1789 local i = p.injections or p.replaceinjections
1790 if i then
1791 local yoffset = i.yoffset or 0
1792 local leftkern = i.leftkern or 0
1793 local rightkern = i.rightkern or 0
1794 if leftkern ~= 0 or rightkern ~= 0 or yoffset ~= 0 then
1795 addxymargins(n,-leftkern,-rightkern,yoffset)
1796 end
1797 end
1798 end
1799 end
1800 end
1801 if prevglyph then
1802 if pre then
1803 local p = rawget(properties,prevglyph)
1804 if p then
1805 local i = p.preinjections
1806 if i then
1807
1808 local rightkern = i.rightkern
1809 if rightkern and rightkern ~= 0 then
1810 addxymargins(pre,-rightkern,0,0)
1811 end
1812 end
1813 end
1814 end
1815 if replace then
1816 local p = rawget(properties,prevglyph)
1817 if p then
1818 local i = p.replaceinjections
1819 if i then
1820
1821 local rightkern = i.rightkern
1822 if rightkern and rightkern ~= 0 then
1823 addxymargins(replace,-rightkern,0,0)
1824 end
1825 end
1826 end
1827 end
1828 end
1829 prevglyph = nil
1830 prevdisc = current
1831 else
1832 prevglyph = nil
1833 prevdisc = nil
1834 end
1835 prev = current
1836 current = next
1837 end
1838
1839 if keepregisteredcounts then
1840 keepregisteredcounts = false
1841 else
1842 nofregisteredpositions = 0
1843 end
1844 if trace_injections then
1845 show_result(head)
1846 end
1847 return head
1848end
1849
1850local function showoffset(n,flag)
1851 local x, y = getoffsets(n)
1852 if x ~= 0 or y ~= 0 then
1853 setcolor(n,"darkgray")
1854 end
1855end
1856
1857local function processmark(p,n,pn)
1858 local px, py = getoffsets(p)
1859 local nx, ny = getoffsets(n)
1860 local sx, sy = getxyscales(n)
1861 local ox = 0
1862 local rightkern = nil
1863 local pp = rawget(properties,p)
1864 if pp then
1865 pp = pp.injections
1866 if pp then
1867 rightkern = pp.rightkern
1868 end
1869 end
1870 local markdir = pn.markdir
1871 if rightkern then
1872 ox = px - sx * (pn.markx or 0) - rightkern
1873 if markdir and markdir < 0 then
1874
1875 if not pn.markmark then
1876 ox = ox + sx * (pn.leftkern or 0)
1877 end
1878 else
1879
1880
1881
1882
1883
1884
1885
1886
1887 if false then
1888
1889 local leftkern = pp.leftkern
1890 if leftkern then
1891 ox = ox - sx * leftkern
1892 end
1893 end
1894 end
1895 else
1896 ox = px - sx * (pn.markx or 0)
1897 if markdir and markdir < 0 then
1898 if not pn.markmark then
1899 local leftkern = pn.leftkern
1900 if leftkern then
1901 ox = ox + sx * leftkern
1902 end
1903 end
1904 end
1905 if pn.checkmark then
1906 local wn = getwidth(n)
1907 if wn and wn ~= 0 then
1908 wn = wn/2
1909 if trace_injections then
1910 report_injections("correcting non zero width mark %C",getchar(n))
1911 end
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923 insertnodebefore(n,n,somekern(fontkern,-wn,n))
1924 insertnodeafter(n,n,somekern(fontkern,-wn,n))
1925 end
1926 end
1927 end
1928 local oy = ny + py + sy * (pn.marky or 0)
1929 if not pn.markmark then
1930 local yoffset = pn.yoffset
1931 if yoffset then
1932 oy = oy + sy * yoffset
1933 end
1934 end
1935 setoffsets(n,ox,oy)
1936 if trace_marks then
1937 showoffset(n,true)
1938 end
1939end
1940
1941local function inject_everything(head,where)
1942 if trace_injections then
1943 trace(head,"everything")
1944 end
1945 local hascursives = nofregisteredcursives > 0
1946 local hasmarks = nofregisteredmarks > 0
1947
1948 local current = head
1949 local last = nil
1950 local prev = nil
1951 local next = nil
1952 local prevdisc = nil
1953 local prevglyph = nil
1954 local pre = nil
1955 local post = nil
1956 local replace = nil
1957 local pretail = nil
1958 local posttail = nil
1959 local replacetail = nil
1960
1961 local cursiveanchor = nil
1962 local minc = 0
1963 local maxc = 0
1964 local glyphs = { }
1965 local marks = { }
1966 local nofmarks = 0
1967
1968 while current do
1969 local next, char, id = isnextchar(current)
1970 if char then
1971 local p = rawget(properties,current)
1972 if p then
1973 local i = p.injections
1974 if i then
1975 local pm = i.markbasenode
1976 if pm then
1977 nofmarks = nofmarks + 1
1978 marks[nofmarks] = current
1979 else
1980 local yoffset = i.yoffset
1981 if yoffset and yoffset ~= 0 then
1982 addyoffset(current,yscaled(current,yoffset))
1983 end
1984 if hascursives then
1985 local cursivex = i.cursivex
1986 if cursivex then
1987 if cursiveanchor then
1988 if cursivex ~= 0 then
1989 i.leftkern = (i.leftkern or 0) + cursivex
1990 end
1991 if maxc == 0 then
1992 minc = 1
1993 maxc = 1
1994 glyphs[1] = cursiveanchor
1995 else
1996 maxc = maxc + 1
1997 glyphs[maxc] = cursiveanchor
1998 end
1999 properties[cursiveanchor].cursivedy = i.cursivey
2000 last = current
2001 else
2002 maxc = 0
2003 end
2004 elseif maxc > 0 then
2005 local nx, ny = getoffsets(current)
2006 for i=maxc,minc,-1 do
2007 local ti = glyphs[i]
2008 ny = ny + yscaled(current,properties[ti].cursivedy)
2009 setoffsets(ti,false,ny)
2010 if trace_cursive then
2011 showoffset(ti)
2012 end
2013 end
2014 maxc = 0
2015 cursiveanchor = nil
2016 end
2017 if i.cursiveanchor then
2018 cursiveanchor = current
2019 else
2020 if maxc > 0 then
2021 local nx, ny = getoffsets(current)
2022 for i=maxc,minc,-1 do
2023 local ti = glyphs[i]
2024 ny = ny + yscaled(current,properties[ti].cursivedy)
2025 setoffsets(ti,false,ny)
2026 if trace_cursive then
2027 showoffset(ti)
2028 end
2029 end
2030 maxc = 0
2031 end
2032 cursiveanchor = nil
2033 end
2034 end
2035
2036 local leftkern = i.leftkern
2037 local rightkern = i.rightkern
2038 if leftkern and leftkern ~= 0 then
2039 local opposite = rightkern and leftkern == -rightkern
2040 leftkern = xscaled(current,leftkern)
2041 if opposite then
2042 addxoffset(current,leftkern)
2043 rightkern = 0
2044 elseif prev and getid(prev) == glue_code then
2045 if usespacefontkerns then
2046 head = insertnodebefore(head,current,spacefontkern(leftkern))
2047 else
2048 setwidth(prev, getwidth(prev) + leftkern)
2049 end
2050 else
2051 head = insertnodebefore(head,current,somekern(fontkern,leftkern,current))
2052 end
2053 end
2054 if rightkern and rightkern ~= 0 then
2055 rightkern = xscaled(current,rightkern)
2056 if next and getid(next) == glue_code then
2057 if usespacefontkerns then
2058 insertnodeafter(head,current,spacefontkern(rightkern))
2059 else
2060 setwidth(next, getwidth(next) + rightkern)
2061 end
2062 else
2063 insertnodeafter(head,current,somekern(fontkern,rightkern,current))
2064 end
2065 end
2066 end
2067 elseif next then
2068 local i = p.emptyinjections
2069 if i then
2070
2071 local rightkern = i.rightkern
2072 if rightkern and rightkern ~= 0 and getid(next) == disc_code then
2073 local replace = getreplace(next)
2074 if replace then
2075
2076 else
2077 setreplace(next,somekern(fontkern,xscaled(current,rightkern),current))
2078 end
2079 end
2080 end
2081 end
2082 if prevdisc then
2083 if p then
2084 local done = false
2085 if post then
2086 local i = p.postinjections
2087 if i then
2088 local leftkern = i.leftkern
2089 if leftkern and leftkern ~= 0 then
2090 setlink(posttail,somekern(fontkern,xscaled(current,leftkern),current))
2091 done = true
2092 end
2093 end
2094 end
2095 if replace then
2096 local i = p.replaceinjections
2097 if i then
2098 local leftkern = i.leftkern
2099 if leftkern and leftkern ~= 0 then
2100 setlink(replacetail,somekern(fontkern,xscaled(current,leftkern),current))
2101 done = true
2102 end
2103 end
2104 else
2105 local i = p.emptyinjections
2106 if i then
2107 local leftkern = i.leftkern
2108 if leftkern and leftkern ~= 0 then
2109 replace = somekern(fontkern,xscaled(current,leftkern),current)
2110 done = true
2111 end
2112 end
2113 end
2114 if done then
2115 setdisc(prevdisc,pre,post,replace)
2116 end
2117 end
2118 end
2119 else
2120
2121 if hascursives and maxc > 0 then
2122 local nx, ny = getoffsets(current)
2123 for i=maxc,minc,-1 do
2124 local ti = glyphs[i]
2125 ny = ny + yscaled(current,properties[ti].cursivedy)
2126 setoffsets(ti,false,ny)
2127 end
2128 maxc = 0
2129 cursiveanchor = nil
2130 end
2131 end
2132 prevdisc = nil
2133 prevglyph = current
2134 elseif char == false then
2135
2136 prevdisc = nil
2137 prevglyph = current
2138 elseif id == disc_code then
2139
2140 pre, post, replace, pretail, posttail, replacetail = getdisc(current,true)
2141 local done = false
2142 if pre then
2143
2144 for n in nextchar, pre do
2145 local p = rawget(properties,n)
2146 if p then
2147 local i = p.injections or p.preinjections
2148 if i then
2149 local yoffset = i.yoffset
2150 if yoffset and yoffset ~= 0 then
2151 addyoffset(n,yscaled(n,yoffset))
2152 end
2153 local leftkern = i.leftkern
2154 if leftkern and leftkern ~= 0 then
2155 pre = insertnodebefore(pre,n,somekern(fontkern,xscaled(n,leftkern),n))
2156 done = true
2157 end
2158 local rightkern = i.rightkern
2159 if rightkern and rightkern ~= 0 then
2160 insertnodeafter(pre,n,somekern(fontkern,xscaled(n,rightkern),n))
2161 done = true
2162 end
2163 if hasmarks then
2164 local pm = i.markbasenode
2165 if pm then
2166 processmark(pm,n,i)
2167 end
2168 end
2169 end
2170 end
2171 end
2172 end
2173 if post then
2174
2175 for n in nextchar, post do
2176 local p = rawget(properties,n)
2177 if p then
2178 local i = p.injections or p.postinjections
2179 if i then
2180 local yoffset = i.yoffset
2181 if yoffset and yoffset ~= 0 then
2182 addyoffset(n,yscaled(n,yoffset))
2183 end
2184 local leftkern = i.leftkern
2185 if leftkern and leftkern ~= 0 then
2186 post = insertnodebefore(post,n,somekern(fontkern,xscaled(n,leftkern),n))
2187 done = true
2188 end
2189 local rightkern = i.rightkern
2190 if rightkern and rightkern ~= 0 then
2191 done = true
2192 insertnodeafter(post,n,somekern(fontkern,xscaled(n,rightkern),n))
2193 end
2194 if hasmarks then
2195 local pm = i.markbasenode
2196 if pm then
2197 processmark(pm,n,i)
2198 end
2199 end
2200 end
2201 end
2202 end
2203 end
2204 if replace then
2205
2206 for n in nextchar, replace do
2207 local p = rawget(properties,n)
2208 if p then
2209 local i = p.injections or p.replaceinjections
2210 if i then
2211 local yoffset = i.yoffset
2212 if yoffset and yoffset ~= 0 then
2213 addyoffset(n,yscaled(n,yoffset))
2214 end
2215 local leftkern = i.leftkern
2216 if leftkern and leftkern ~= 0 then
2217 replace = insertnodebefore(replace,n,somekern(fontkern,xscaled(n,leftkern),n))
2218 done = true
2219 end
2220 local rightkern = i.rightkern
2221 if rightkern and rightkern ~= 0 then
2222 insertnodeafter(replace,n,somekern(fontkern,xscaled(n,rightkern),n))
2223 done = true
2224 end
2225 if hasmarks then
2226 local pm = i.markbasenode
2227 if pm then
2228 processmark(pm,n,i)
2229 end
2230 end
2231 end
2232 end
2233 end
2234 end
2235 if prevglyph then
2236 if pre then
2237 local p = rawget(properties,prevglyph)
2238 if p then
2239 local i = p.preinjections
2240 if i then
2241
2242 local rightkern = i.rightkern
2243 if rightkern and rightkern ~= 0 then
2244 pre = insertnodebefore(pre,pre,somekern(fontkern,xscaled(prevglyph,rightkern),prevglyph))
2245 done = true
2246 end
2247 end
2248 end
2249 end
2250 if replace then
2251 local p = rawget(properties,prevglyph)
2252 if p then
2253 local i = p.replaceinjections
2254 if i then
2255
2256 local rightkern = i.rightkern
2257 if rightkern and rightkern ~= 0 then
2258 replace = insertnodebefore(replace,replace,somekern(fontkern,xscaled(prevglyph,rightkern),prevglyph))
2259 done = true
2260 end
2261 end
2262 end
2263 end
2264 end
2265 if done then
2266 setdisc(current,pre,post,replace)
2267 end
2268 prevglyph = nil
2269 prevdisc = current
2270 else
2271
2272 prevglyph = nil
2273 prevdisc = nil
2274 end
2275 prev = current
2276 current = next
2277 end
2278
2279 if hascursives and maxc > 0 then
2280 local nx, ny = getoffsets(last)
2281 for i=maxc,minc,-1 do
2282 local ti = glyphs[i]
2283 ny = ny + yscaled(properties[ti].cursivedy)
2284 setoffsets(ti,false,ny)
2285 if trace_cursive then
2286 showoffset(ti)
2287 end
2288 end
2289 end
2290
2291 if nofmarks > 0 then
2292 for i=1,nofmarks do
2293 local m = marks[i]
2294 local p = rawget(properties,m)
2295 local i = p.injections
2296 local b = i.markbasenode
2297 processmark(b,m,i)
2298 end
2299 elseif hasmarks then
2300
2301 end
2302
2303 if keepregisteredcounts then
2304 keepregisteredcounts = false
2305 else
2306 nofregisteredkerns = 0
2307 nofregisteredpositions = 0
2308 nofregisteredmarks = 0
2309 nofregisteredcursives = 0
2310 end
2311 if trace_injections then
2312 show_result(head)
2313 end
2314 return head
2315end
2316
2317
2318
2319local triggers = false
2320
2321function nodes.injections.setspacekerns(font,sequence)
2322 if triggers then
2323 triggers[font] = sequence
2324 else
2325 triggers = { [font] = sequence }
2326 end
2327end
2328
2329local threshold = 1
2330
2331directives.register("otf.threshold", function(v) threshold = tonumber(v) or 1 end)
2332
2333local getthreshold = function(font)
2334 local p = parameters[font]
2335 local f = p.factor
2336 local s = p.spacing
2337 local t = threshold * (s and s.width or p.space or 0) - 2
2338 return t > 0 and t or 0, f
2339end
2340
2341injections.getthreshold = getthreshold
2342
2343function injections.isspace(n,threshold,id)
2344 if (id or getid(n)) == glue_code then
2345 local w = getwidth(n)
2346 if threshold and w > threshold then
2347 return 32
2348 end
2349 end
2350end
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375local getspaceboth = getboth
2376
2377function injections.installgetspaceboth(gb)
2378 getspaceboth = gb or getboth
2379end
2380
2381local function injectspaces(head)
2382
2383 if not triggers then
2384 return head
2385 end
2386 local lastfont = nil
2387 local spacekerns = nil
2388 local leftkerns = nil
2389 local rightkerns = nil
2390 local factor = 0
2391 local threshold = 0
2392 local leftkern = false
2393 local rightkern = false
2394 local xscale = 1
2395
2396 local function updatefont(font,trig)
2397 leftkerns = trig.left
2398 rightkerns = trig.right
2399 lastfont = font
2400 threshold,
2401 factor = getthreshold(font)
2402 end
2403
2404 for n in nextglue, head do
2405 local prev, next = getspaceboth(n)
2406 local prevchar, prevfont = getcharspec(prev)
2407 local nextchar, nextfont = getcharspec(next)
2408 if nextchar then
2409 local trig = triggers[nextfont]
2410 if trig then
2411 if lastfont ~= nextfont then
2412 updatefont(nextfont,trig)
2413 end
2414 if rightkerns then
2415 rightkern = rightkerns[nextchar]
2416 if rightkern then
2417 xscale = getxscale(next)
2418 end
2419 end
2420 end
2421 end
2422 if prevchar then
2423 local trig = triggers[prevfont]
2424 if trig then
2425 if lastfont ~= prevfont then
2426 updatefont(prevfont,trig)
2427 end
2428 if leftkerns then
2429 leftkern = leftkerns[prevchar]
2430 if leftkern then
2431 xscale = getxscale(prev)
2432 end
2433 end
2434 end
2435 end
2436 if leftkern then
2437 local old = getwidth(n)
2438 if old > xscale*threshold then
2439 if rightkern then
2440 if usespacefontkerns then
2441 local lnew = leftkern * factor
2442 local rnew = rightkern * factor
2443 if trace_spaces then
2444 report_spaces("%C [%p + %p + %p] %C",prevchar,lnew,old,rnew,nextchar)
2445 end
2446 lnew = lnew * xscale
2447 rnew = rnew * xscale
2448 head = insertnodebefore(head,n,spacefontkern(lnew))
2449 insertnodeafter(head,n,spacefontkern(rnew))
2450 else
2451 local new = old + (leftkern + rightkern) * factor * xscale
2452 if trace_spaces then
2453 report_spaces("%C [%p -> %p] %C",prevchar,old,new,nextchar)
2454 end
2455 setwidth(n,new)
2456 end
2457 rightkern = false
2458 else
2459 if usespacefontkerns then
2460 local new = leftkern * factor * xscale
2461 if trace_spaces then
2462 report_spaces("%C [%p + %p]",prevchar,old,new)
2463 end
2464 insertnodeafter(head,n,spacefontkern(new))
2465 else
2466 local new = old + leftkern * factor * xscale
2467 if trace_spaces then
2468 report_spaces("%C [%p -> %p]",prevchar,old,new)
2469 end
2470 setwidth(n,new)
2471 end
2472 end
2473 end
2474 leftkern = false
2475 elseif rightkern then
2476 local old = getwidth(n)
2477 if old > xscale*threshold then
2478 local new = rightkern * factor * xscale
2479 if usespacefontkerns then
2480 if trace_spaces then
2481 report_spaces("[%p + %p] %C",old,new,nextchar)
2482 end
2483 insertnodeafter(head,n,spacefontkern(new))
2484 else
2485 new = old + new
2486 if trace_spaces then
2487 report_spaces("[%p -> %p] %C",old,new,nextchar)
2488 end
2489 setwidth(n,new)
2490 end
2491 else
2492
2493 end
2494 rightkern = false
2495 end
2496 end
2497
2498 triggers = false
2499
2500 return head
2501end
2502
2503
2504
2505
2506
2507function injections.handler(head,where)
2508 if triggers then
2509 head = injectspaces(head)
2510 end
2511 if nofregisteredmarks > 0 or nofregisteredcursives > 0 then
2512 if trace_injections then
2513 report_injections("injection variant %a (%s)","everything","kerns")
2514 end
2515
2516
2517 return inject_everything(head,where)
2518 elseif nofregisteredpositions > 0 then
2519 if trace_injections then
2520 report_injections("injection variant %a (%s)","positions",useadvance and "margins" or "kerns")
2521 end
2522 if useadvance then
2523 return inject_positions_only_margins(head,where)
2524 else
2525 return inject_positions_only_kerns(head,where)
2526 end
2527 elseif nofregisteredkerns > 0 then
2528 if trace_injections then
2529 report_injections("injection variant %a (%s)","kerns",useadvance and "margins" or "kerns")
2530 end
2531 if useadvance then
2532 return inject_kerns_only_margins(head,where)
2533
2534 else
2535 return inject_kerns_only_kerns(head,where)
2536 end
2537 else
2538 return head
2539 end
2540end
2541
2542 |