typo-ovl.lmt /size: 5311 b    last modification: 2021-10-28 13:51
1if not modules then modules = { } end modules ['typo-ovl'] = {
2    version   = 1.001,
3    comment   = "companion to typo-ovl.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
9-- This is dubious code. If you needed it your source is probably bad. We only used
10-- in when we had to mark bad content but when cleaning up some project code I decided
11-- that it is easier to maintain in the distribution then in a project style. After all,
12-- we have hardly any private code. For convenience I hooked it into the existing
13-- replacement module (as it used the same code anyway). I did some cleanup.
14
15local next, type = next, type
16
17local context      = context
18
19local nuts         = nodes.nuts
20local tonut        = nodes.tonut
21local tonode       = nodes.tonode
22
23local nodecodes    = nodes.nodecodes
24local glyph_code   = nodecodes.glyph
25local disc_code    = nodecodes.disc
26
27local getnext      = nuts.getnext
28local getid        = nuts.getid
29local getdisc      = nuts.getdisc
30local getattr      = nuts.getattr
31local setattr      = nuts.setattr
32local getattrlist  = nuts.getattrlist
33local setattrlist  = nuts.setattrlist
34local getdata      = nuts.getdata
35local setfont      = nuts.setfont
36
37local nextnode     = nuts.traversers.node
38
39local unsetvalue   = attributes.unsetvalue
40local prvattribute = attributes.private
41
42local texgetbox    = tex.getbox
43local currentfont  = font.current
44
45local a_overloads  = attributes.private("overloads")
46local n_overloads  = 0
47local t_overloads  = { }
48
49local overloaded   = { }
50
51local function markasoverload(a)
52    local n = prvattribute(a)
53    if n then
54        overloaded[n] = a
55    end
56end
57
58attributes.markasoverload = markasoverload
59
60markasoverload("color")
61markasoverload("colormodel")
62markasoverload("transparency")
63markasoverload("case")
64markasoverload("negative")
65markasoverload("effect")
66markasoverload("ruled")
67markasoverload("shifted")
68markasoverload("kernchars")
69markasoverload("kern")
70markasoverload("noligature")
71markasoverload("viewerlayer")
72
73local function tooverloads(n)
74    local current = tonut(n)
75    local a = getattrlist(current)
76    local s = { }
77    while a do
78        local index, value = getdata(a)
79        local o = overloaded[n]
80        if o and value ~= unsetvalue then
81            -- It is actually very unlikely that we have unsetvalue.
82            s[index] = value
83        end
84        a = getnext(a)
85    end
86    return s
87end
88
89attributes.tooverloads = tooverloads
90
91function attributes.applyoverloads(specification,start,stop)
92    local start     = tonut(start)
93    local processor = specification.processor
94    local overloads = specification.processor or getattr(start,a_overloads)
95    if overloads and overloads ~= unsetvalue then
96        overloads = t_overloads[overloads]
97        if not overloads then
98            return
99        end
100    else
101        return
102    end
103
104    local last    = stop and tonut(stop)
105    local oldlist = nil
106    local newlist = nil
107    local newfont = overloads.font
108
109    local function apply(current)
110        local a = getattrlist(current)
111        if a == oldlist then
112            setattrlist(current,newlist)
113        else
114            oldlist = getattrlist(current)
115            for k, v in next, overloads do
116                if type(v) == "number" then
117                    setattr(current,k,v)
118                else
119                    -- can be: ["font"] = number
120                end
121            end
122            newlist = current -- getattrlist(current)
123        end
124        if newfont then
125            setfont(current,newfont)
126        end
127    end
128
129    for current, id in nextnode, start do
130        if id == glyph_code then
131            apply(current)
132        elseif id == disc_code then
133            apply(current)
134            if pre then
135                while pre do
136                    if getid(pre) == glyph_code then
137                        apply()
138                    end
139                    pre = getnext(pre)
140                end
141            end
142            if post then
143                while post do
144                    if getid(post) == glyph_code then
145                        apply()
146                    end
147                    post = getnext(post)
148                end
149            end
150            if replace then
151                while replace do
152                    if getid(replace) == glyph_code then
153                        apply()
154                    end
155                    replace = getnext(replace)
156                end
157            end
158        end
159        if current == last then
160            break
161        end
162    end
163end
164
165-- we assume the same highlight so we're global
166
167interfaces.implement {
168    name      = "overloadsattribute",
169    arguments = { "string", "integer", "integer" },
170    actions   = function(name,font,box)
171        local samplebox = texgetbox(box)
172        local sample    = samplebox and samplebox.list
173        local overloads = sample and tooverloads(sample)
174        if overloads then
175            overloads.font = font > 0 and font or false
176            n_overloads = n_overloads + 1
177            t_overloads[n_overloads] = overloads
178            t_overloads[name] = overloads
179            context(n_overloads)
180        else
181            context(unsetvalue)
182        end
183    end
184}
185