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