luatex-basics-nod.lua /size: 9 Kb    last modification: 2021-10-28 13:51
1if not modules then modules = { } end modules ['luatex-fonts-nod'] = {
2    version   = 1.001,
3    comment   = "companion to luatex-fonts.lua",
4    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
5    copyright = "PRAGMA ADE / ConTeXt Development Team",
6    license   = "see context related readme files"
7}
8
9if context then
10    os.exit()
11end
12
13-- Don't depend on code here as it is only needed to complement the font handler
14-- code. I will move some to another namespace as I don't see other macro packages
15-- use the context logic. It's a subset anyway. More will be stripped.
16
17-- Attributes:
18
19if tex.attribute[0] ~= 0 then
20
21    texio.write_nl("log","!")
22    texio.write_nl("log","! Attribute 0 is reserved for ConTeXt's font feature management and has to be")
23    texio.write_nl("log","! set to zero. Also, some attributes in the range 1-255 are used for special")
24    texio.write_nl("log","! purposes so setting them at the TeX end might break the font handler.")
25    texio.write_nl("log","!")
26
27    tex.attribute[0] = 0 -- else no features
28
29end
30
31attributes            = attributes or { }
32attributes.unsetvalue = -0x7FFFFFFF
33
34local numbers, last = { }, 127
35
36attributes.private = attributes.private or function(name)
37    local number = numbers[name]
38    if not number then
39        if last < 255 then
40            last = last + 1
41        end
42        number = last
43        numbers[name] = number
44    end
45    return number
46end
47
48-- Nodes (a subset of context so that we don't get too much unused code):
49
50nodes              = { }
51nodes.handlers     = { }
52
53local nodecodes    = { }
54local glyphcodes   = node.subtypes("glyph")
55local disccodes    = node.subtypes("disc")
56
57for k, v in next, node.types() do
58    v = string.gsub(v,"_","")
59    nodecodes[k] = v
60    nodecodes[v] = k
61end
62for k, v in next, glyphcodes do
63    glyphcodes[v] = k
64end
65for k, v in next, disccodes do
66    disccodes[v] = k
67end
68
69nodes.nodecodes  = nodecodes
70nodes.glyphcodes = glyphcodes
71nodes.disccodes  = disccodes
72nodes.dirvalues  = { lefttoright = 0, righttoleft = 1 }
73
74nodes.handlers.protectglyphs   = node.protectglyphs   or node.protect_glyphs   -- beware: nodes!
75nodes.handlers.unprotectglyphs = node.unprotectglyphs or node.unprotect_glyphs -- beware: nodes!
76
77-- in generic code, at least for some time, we stay nodes, while in context
78-- we can go nuts (e.g. experimental); this split permits us us keep code
79-- used elsewhere stable but at the same time play around in context
80
81-- much of this will go away .. it's part of the context interface and not
82-- officially in luatex-*.lua
83
84local direct       = node.direct
85local nuts         = { }
86nodes.nuts         = nuts
87
88local tonode       = direct.tonode
89local tonut        = direct.todirect
90
91nodes.tonode       = tonode
92nodes.tonut        = tonut
93
94nuts.tonode        = tonode
95nuts.tonut         = tonut
96
97nuts.getattr       = direct.get_attribute
98nuts.getboth       = direct.getboth
99nuts.getchar       = direct.getchar
100nuts.getdirection  = direct.getdirection
101nuts.getdisc       = direct.getdisc
102nuts.getreplace    = direct.getreplace
103nuts.getfield      = direct.getfield
104nuts.getfont       = direct.getfont
105nuts.getid         = direct.getid
106nuts.getkern       = direct.getkern
107nuts.getlist       = direct.getlist
108nuts.getnext       = direct.getnext
109nuts.getoffsets    = direct.getoffsets
110nuts.getoptions    = direct.getoptions or function() return 0 end
111nuts.getprev       = direct.getprev
112nuts.getsubtype    = direct.getsubtype
113nuts.getwidth      = direct.getwidth
114nuts.setattr       = direct.setfield
115nuts.setboth       = direct.setboth
116nuts.setchar       = direct.setchar
117nuts.setcomponents = direct.setcomponents
118nuts.setdirection  = direct.setdirection
119nuts.setdisc       = direct.setdisc
120nuts.setreplace    = direct.setreplace
121nuts.setfield      = direct.setfield
122nuts.setkern       = direct.setkern
123nuts.setlink       = direct.setlink
124nuts.setlist       = direct.setlist
125nuts.setnext       = direct.setnext
126nuts.setoffsets    = direct.setoffsets
127nuts.setprev       = direct.setprev
128nuts.setsplit      = direct.setsplit
129nuts.setsubtype    = direct.setsubtype
130nuts.setwidth      = direct.setwidth
131
132nuts.getglyphdata  = nuts.getattribute    or nuts.getattr
133nuts.setglyphdata  = nuts.setattribute    or nuts.setattr
134
135nuts.ischar        = direct.ischar        or direct.is_char
136nuts.isglyph       = direct.isglyph       or direct.is_glyph
137nuts.copy          = direct.copy
138nuts.copynode      = direct.copy
139nuts.copylist      = direct.copylist      or direct.copy_list
140nuts.endofmath     = direct.endofmath     or direct.end_of_math
141nuts.flush         = direct.flush
142nuts.flushlist     = direct.flushlist     or direct.flush_list
143nuts.flushnode     = direct.flushnode     or direct.flush_node
144nuts.free          = direct.free
145nuts.insertafter   = direct.insertafter   or direct.insert_after
146nuts.insertbefore  = direct.insertbefore  or direct.insert_before
147nuts.isnode        = direct.isnode        or direct.is_node
148nuts.isdirect      = direct.isdirect      or direct.is_direct
149nuts.isnut         = direct.isdirect      or direct.is_direct
150nuts.kerning       = direct.kerning
151nuts.ligaturing    = direct.ligaturing
152nuts.new           = direct.new
153nuts.remove        = direct.remove
154nuts.tail          = direct.tail
155nuts.traverse      = direct.traverse
156nuts.traversechar  = direct.traversechar  or direct.traverse_char
157nuts.traverseglyph = direct.traverseglyph or direct.traverse_glyph
158nuts.traverseid    = direct.traverseid    or direct.traverse_id
159
160-- properties as used in the (new) injector:
161
162local propertydata = (direct.getpropertiestable or direct.get_properties_table)()
163nodes.properties   = { data = propertydata }
164
165if direct.set_properties_mode then
166    direct.set_properties_mode(true,true)
167    function direct.set_properties_mode() end
168end
169
170nuts.getprop = function(n,k)
171    local p = propertydata[n]
172    if p then
173        return p[k]
174    end
175end
176
177nuts.setprop = function(n,k,v)
178    if v then
179        local p = propertydata[n]
180        if p then
181            p[k] = v
182        else
183            propertydata[n] = { [k] = v }
184        end
185    end
186end
187
188nodes.setprop = nodes.setproperty
189nodes.getprop = nodes.getproperty
190
191-- a few helpers (we need to keep 'm in sync with context) .. some day components
192-- might go so here we isolate them
193
194local setprev       = nuts.setprev
195local setnext       = nuts.setnext
196local getnext       = nuts.getnext
197local setlink       = nuts.setlink
198local getfield      = nuts.getfield
199local setfield      = nuts.setfield
200local getsubtype    = nuts.getsubtype
201local isglyph       = nuts.isglyph
202local find_tail     = nuts.tail
203local flushlist     = nuts.flushlist
204local flushnode     = nuts.flushnode
205local traverseid    = nuts.traverseid
206local copynode      = nuts.copynode
207
208local glyph_code    = nodes.nodecodes.glyph
209local ligature_code = nodes.glyphcodes.ligature
210
211do -- this is consistent with the rest of context, not that we need it
212
213    local p = nodecodes.localpar or nodecodes.local_par
214
215    if p then
216        nodecodes.par = p
217        nodecodes[p] = "par"
218        nodecodes.localpar  = p -- for old times sake
219        nodecodes.local_par = p -- for old times sake
220    end
221
222end
223
224do
225
226    local getcomponents = node.direct.getcomponents
227    local setcomponents = node.direct.setcomponents
228
229    local function copynocomponents(g,copyinjection)
230        local components = getcomponents(g)
231        if components then
232            setcomponents(g)
233            local n = copynode(g)
234            if copyinjection then
235                copyinjection(n,g)
236            end
237            setcomponents(g,components)
238            -- maybe also upgrade the subtype but we don't use it anyway
239            return n
240        else
241            local n = copynode(g)
242            if copyinjection then
243                copyinjection(n,g)
244            end
245            return n
246        end
247    end
248
249    local function copyonlyglyphs(current)
250        local head     = nil
251        local previous = nil
252        for n in traverseid(glyph_code,current) do
253            n = copynode(n)
254            if head then
255                setlink(previous,n)
256            else
257                head = n
258            end
259            previous = n
260        end
261        return head
262    end
263
264    local function countcomponents(start,marks)
265        local char = isglyph(start)
266        if char then
267            if getsubtype(start) == ligature_code then
268                local n = 0
269                local components = getcomponents(start)
270                while components do
271                    n = n + countcomponents(components,marks)
272                    components = getnext(components)
273                end
274                return n
275            elseif not marks[char] then
276                return 1
277            end
278        end
279        return 0
280    end
281
282    local function flushcomponents()
283        -- this is a no-op in mkiv / generic
284    end
285
286    nuts.components = {
287        set              = setcomponents,
288        get              = getcomponents,
289        copyonlyglyphs   = copyonlyglyphs,
290        copynocomponents = copynocomponents,
291        count            = countcomponents,
292        flush            = flushcomponents,
293    }
294
295end
296
297nuts.usesfont = direct.usesfont or direct.uses_font
298
299do
300
301    -- another poor mans substitute ... i will move these to a more protected
302    -- namespace .. experimental hack
303
304    local dummy = tonut(node.new("glyph"))
305
306    nuts.traversers = {
307        glyph    = nuts.traverseid(nodecodes.glyph,dummy),
308        glue     = nuts.traverseid(nodecodes.glue,dummy),
309        disc     = nuts.traverseid(nodecodes.disc,dummy),
310        boundary = nuts.traverseid(nodecodes.boundary,dummy),
311
312        char     = nuts.traversechar(dummy),
313
314        node     = nuts.traverse(dummy),
315    }
316
317end
318
319if not nuts.setreplace then
320
321    local getdisc  = nuts.getdisc
322    local setfield = nuts.setfield
323
324    function nuts.getreplace(n)
325        local _, _, h, _, _, t = getdisc(n,true)
326        return h, t
327    end
328
329    function nuts.setreplace(n,h)
330        setfield(n,"replace",h)
331    end
332
333end
334
335do
336
337    local getsubtype = nuts.getsubtype
338
339    function nuts.startofpar(n)
340        local s = getsubtype(n)
341        return s == 0 or s == 2 -- sorry, hardcoded, won't change anyway
342    end
343
344end
345