typo-ovl.lmt /size: 5356 b    last modification: 2025-02-21 11:03
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 glyph_code   <const> = nodes.nodecodes.glyph
24local disc_code    <const> = nodes.nodecodes.disc
25
26local getnext      = nuts.getnext
27local getid        = nuts.getid
28local getdisc      = nuts.getdisc
29local getattr      = nuts.getattr
30local setattr      = nuts.setattr
31local getattrlist  = nuts.getattrlist
32local setattrlist  = nuts.setattrlist
33local getdata      = nuts.getdata
34local setfont      = nuts.setfont
35
36local nextnode     = nuts.traversers.node
37
38local prvattribute = attributes.private
39
40local texgetbox    = tex.getbox
41local currentfont  = font.current
42
43local n_overloads  = 0
44local t_overloads  = { }
45
46local a_overloads  <const> = prvattribute("overloads")
47local unsetvalue   <const> = attributes.unsetvalue
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,true)
76    local s = { }
77    if a then
78        for index, value in next, a do
79            local o = overloaded[index]
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    end
87    return s
88end
89
90attributes.tooverloads = tooverloads
91
92function attributes.applyoverloads(specification,start,stop)
93    local start     = tonut(start)
94    local processor = specification.processor
95    local overloads = specification.processor or getattr(start,a_overloads)
96    if overloads and overloads ~= unsetvalue then
97        overloads = t_overloads[overloads]
98        if not overloads then
99            return
100        end
101    else
102        return
103    end
104
105    local last    = stop and tonut(stop)
106    local oldlist = nil
107    local newlist = nil
108    local newfont = overloads.font
109
110    local function apply(current)
111        local a = getattrlist(current)
112        if a == oldlist then
113            setattrlist(current,newlist)
114        else
115            oldlist = getattrlist(current)
116            for k, v in next, overloads do
117                if type(v) == "number" then
118                    setattr(current,k,v)
119                else
120                    -- can be: ["font"] = number
121                end
122            end
123            newlist = current -- getattrlist(current)
124        end
125        if newfont then
126            setfont(current,newfont)
127        end
128    end
129
130    for current, id in nextnode, start do
131        if id == glyph_code then
132            apply(current)
133        elseif id == disc_code then
134            apply(current)
135            if pre then
136                while pre do
137                    if getid(pre) == glyph_code then
138                        apply()
139                    end
140                    pre = getnext(pre)
141                end
142            end
143            if post then
144                while post do
145                    if getid(post) == glyph_code then
146                        apply()
147                    end
148                    post = getnext(post)
149                end
150            end
151            if replace then
152                while replace do
153                    if getid(replace) == glyph_code then
154                        apply()
155                    end
156                    replace = getnext(replace)
157                end
158            end
159        end
160        if current == last then
161            break
162        end
163    end
164end
165
166-- we assume the same highlight so we're global
167
168interfaces.implement {
169    name      = "overloadsattribute",
170    arguments = { "string", "integer", "integer" },
171    actions   = function(name,font,box)
172        local samplebox = texgetbox(box)
173        local sample    = samplebox and samplebox.list
174        local overloads = sample and tooverloads(sample)
175        if overloads then
176            overloads.font = font > 0 and font or false
177            n_overloads = n_overloads + 1
178            t_overloads[n_overloads] = overloads
179            t_overloads[name] = overloads
180            context(n_overloads)
181        else
182            context(unsetvalue)
183        end
184    end
185}
186