typo-pnc.lua /size: 6961 b    last modification: 2021-10-28 13:50
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
37
38local parameters      = fonts.hashes.parameters
39local categories      = characters.categories
40
41local texsetattribute = tex.setattribute
42local unsetvalue      = attributes.unsetvalue
43
44local period          = 0x2E
45local factor          = 0.5
46
47-- alternative: tex.getlccode and tex.getuccode
48
49typesetters             = typesetters or { }
50local typesetters       = typesetters
51
52local periodkerns       = typesetters.periodkerns or { }
53typesetters.periodkerns = periodkerns
54
55local report            = logs.reporter("period kerns")
56local trace             = false
57
58trackers.register("typesetters.periodkerns",function(v) trace = v end)
59
60periodkerns.mapping     = periodkerns.mapping or { }
61periodkerns.factors     = periodkerns.factors or { }
62local a_periodkern      = attributes.private("periodkern")
63
64storage.register("typesetters/periodkerns/mapping", periodkerns.mapping, "typesetters.periodkerns.mapping")
65storage.register("typesetters/periodkerns/factors", periodkerns.factors, "typesetters.periodkerns.factors")
66
67local mapping = periodkerns.mapping
68local factors = periodkerns.factors
69
70function periodkerns.handler(head)
71    for current, char, font in nextglyph, head do
72        if char == period then
73            local a = getattr(current,a_periodkern)
74            if a then
75                local factor = mapping[a]
76                if factor then
77                    local prev, next = getboth(current)
78                    if prev and next and getid(prev) == glyph_code and getid(next) == glyph_code then
79                        local pchar = getchar(prev)
80                        local pcode = categories[pchar]
81                        if pcode == "lu" or pcode == "ll" then
82                            local nchar = getchar(next)
83                            local ncode = categories[nchar]
84                            if ncode == "lu" or ncode == "ll" then
85                                local next2 = getnext(next)
86                                if next2 and getid(next2) == glyph_code and getchar(next2) == period then
87                                    -- A.B.
88                                    local fontspace, inserted
89                                    if factor ~= 0 then
90                                        fontspace = parameters[getfont(current)].space -- can be sped up
91                                        inserted  = factor * fontspace
92                                        insertafter(head,current,new_kern(inserted))
93                                        if trace then
94                                            report("inserting space at %C . [%p] %C .",pchar,inserted,nchar)
95                                        end
96                                    end
97                                    local next3 = getnext(next2)
98                                    if next3 and getid(next3) == glue_code and getsubtype(next3) == spaceskip_code then
99                                        local width = getwidth(next3)
100                                        local space = fontspace or parameters[getfont(current)].space -- can be sped up
101                                        if width > space then -- space + extraspace
102                                            local next4 = getnext(next3)
103                                            if next4 and getid(next4) == glyph_code then
104                                                local fchar = getchar(next4)
105                                                if categories[fchar] ~= "lu" then
106                                                    -- A.B.<glue>X
107                                                    if trace then
108                                                        if inserted then
109                                                            report("reverting space at %C . [%p] %C . [%p->%p] %C",pchar,inserted,nchar,width,space,fchar)
110                                                        else
111                                                            report("reverting space at %C . %C . [%p->%p] %C",pchar,nchar,width,space,fchar)
112                                                        end
113                                                    end
114                                                    setwidth(next3,space)
115                                                else
116                                                    if trace then
117                                                        if inserted then
118                                                            report("keeping space at %C . [%p] %C . [%p] %C",pchar,inserted,nchar,width,fchar)
119                                                        else
120                                                            report("keeping space at %C . %C . [%p] %C",pchar,nchar,width,fchar)
121                                                        end
122                                                    end
123                                                end
124                                            end
125                                        end
126                                    end
127                                end
128                            end
129                        end
130                    end
131                end
132            end
133        end
134    end
135    return head
136end
137
138local enabled = false
139
140function periodkerns.set(factor)
141    factor = tonumber(factor) or 0
142    if not enabled then
143        enableaction("processors","typesetters.periodkerns.handler")
144        enabled = true
145    end
146    local a = factors[factor]
147    if not a then
148        a = #mapping + 1
149        factors[factors], mapping[a] = a, factor
150    end
151    factor = a
152    texsetattribute(a_periodkern,factor)
153    return factor
154end
155
156-- interface
157
158interfaces.implement {
159    name      = "setperiodkerning",
160    actions   = periodkerns.set,
161    arguments = "string"
162}
163
164
165