typo-pnc.lmt /size: 7399 b    last modification: 2024-01-16 10:22
1if not modules then modules = { } end modules ['typo-pnc'] = {
2    version   = 1.001,
3    comment   = "companion to typo-pnc.mkiv",
4    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
5    copyright = "PRAGMA ADE / ConTeXt Development Team",
6    license   = "see context related readme files"
7}
8
9local nodes           = nodes
10local fonts           = fonts
11
12local enableaction    = nodes.tasks.enableaction
13
14local nuts            = nodes.nuts
15local tonut           = nodes.tonut
16
17local nodecodes       = nodes.nodecodes
18local gluecodes       = nodes.gluecodes
19local glyph_code      = nodecodes.glyph
20local glue_code       = nodecodes.glue
21local spaceskip_code  = gluecodes.spaceskip
22
23local new_kern        = nuts.pool.kern
24local insertafter     = nuts.insertafter
25
26local nextglyph       = nuts.traversers.glyph
27
28local getchar         = nuts.getchar
29local getfont         = nuts.getfont
30local getboth         = nuts.getboth
31local getnext         = nuts.getnext
32local getattr         = nuts.getattr
33local getid           = nuts.getid
34local getsubtype      = nuts.getsubtype
35local getwidth        = nuts.getwidth
36local setwidth        = nuts.setwidth
37local findattribute   = nuts.findattribute
38
39local glyph_code      = nodes.nodecodes.glyph
40
41local parameters      = fonts.hashes.parameters
42local categories      = characters.categories
43
44local texsetattribute = tex.setattribute
45local unsetvalue      = attributes.unsetvalue
46
47local period          = 0x2E
48local factor          = 0.5
49
50-- alternative: tex.getlccode and tex.getuccode
51
52typesetters             = typesetters or { }
53local typesetters       = typesetters
54
55local periodkerns       = typesetters.periodkerns or { }
56typesetters.periodkerns = periodkerns
57
58local report            = logs.reporter("period kerns")
59local trace             = false
60
61trackers.register("typesetters.periodkerns",function(v) trace = v end)
62
63periodkerns.mapping     = periodkerns.mapping or { }
64periodkerns.factors     = periodkerns.factors or { }
65local a_periodkern      = attributes.private("periodkern")
66
67storage.register("typesetters/periodkerns/mapping", periodkerns.mapping, "typesetters.periodkerns.mapping")
68storage.register("typesetters/periodkerns/factors", periodkerns.factors, "typesetters.periodkerns.factors")
69
70local mapping = periodkerns.mapping
71local factors = periodkerns.factors
72
73function periodkerns.handler(head)
74    local _, start = findattribute(head,a_periodkern,glyph_code)
75    if start then
76        for current, char, font in nextglyph, start do
77            if char == period then
78                local a = getattr(current,a_periodkern)
79                if a then
80                    local factor = mapping[a]
81                    if factor then
82                        local prev, next = getboth(current)
83                        if prev and next and getid(prev) == glyph_code and getid(next) == glyph_code then
84                            local pchar = getchar(prev)
85                            local pcode = categories[pchar]
86                            if pcode == "lu" or pcode == "ll" then
87                                local nchar = getchar(next)
88                                local ncode = categories[nchar]
89                                if ncode == "lu" or ncode == "ll" then
90                                    local next2 = getnext(next)
91                                    if next2 and getid(next2) == glyph_code and getchar(next2) == period then
92                                        -- A.B.
93                                        local fontspace, inserted
94                                        if factor ~= 0 then
95                                            fontspace = parameters[getfont(current)].space -- can be sped up
96                                            inserted  = factor * fontspace
97                                            insertafter(head,current,new_kern(inserted))
98                                            if trace then
99                                                report("inserting space at %C . [%p] %C .",pchar,inserted,nchar)
100                                            end
101                                        end
102                                        local next3 = getnext(next2)
103                                        if next3 and getid(next3) == glue_code and getsubtype(next3) == spaceskip_code then
104                                            local width = getwidth(next3)
105                                            local space = fontspace or parameters[getfont(current)].space -- can be sped up
106                                            if width > space then -- space + extraspace
107                                                local next4 = getnext(next3)
108                                                if next4 and getid(next4) == glyph_code then
109                                                    local fchar = getchar(next4)
110                                                    if categories[fchar] ~= "lu" then
111                                                        -- A.B.<glue>X
112                                                        if trace then
113                                                            if inserted then
114                                                                report("reverting space at %C . [%p] %C . [%p->%p] %C",pchar,inserted,nchar,width,space,fchar)
115                                                            else
116                                                                report("reverting space at %C . %C . [%p->%p] %C",pchar,nchar,width,space,fchar)
117                                                            end
118                                                        end
119                                                        setwidth(next3,space)
120                                                    else
121                                                        if trace then
122                                                            if inserted then
123                                                                report("keeping space at %C . [%p] %C . [%p] %C",pchar,inserted,nchar,width,fchar)
124                                                            else
125                                                                report("keeping space at %C . %C . [%p] %C",pchar,nchar,width,fchar)
126                                                            end
127                                                        end
128                                                    end
129                                                end
130                                            end
131                                        end
132                                    end
133                                end
134                            end
135                        end
136                    end
137                end
138            end
139        end
140    end
141    return head
142end
143
144local enabled = false
145
146function periodkerns.set(factor)
147    factor = tonumber(factor) or 0
148    if not enabled then
149        enableaction("processors","typesetters.periodkerns.handler")
150        enabled = true
151    end
152    local a = factors[factor]
153    if not a then
154        a = #mapping + 1
155        factors[factors], mapping[a] = a, factor
156    end
157    factor = a
158    texsetattribute(a_periodkern,factor)
159    return factor
160end
161
162-- interface
163
164interfaces.implement {
165    name      = "setperiodkerning",
166    actions   = periodkerns.set,
167    arguments = "string"
168}
169
170
171