node-acc.lua /size: 5510 b    last modification: 2021-10-28 13:50
1if not modules then modules = { } end modules ['node-acc'] = {
2    version   = 1.001,
3    comment   = "companion to node-ini.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, node = nodes, node
10
11local tasks              = nodes.tasks
12
13local nuts               = nodes.nuts
14local tonut              = nodes.tonut
15local tonode             = nodes.tonode
16
17local getid              = nuts.getid
18local getsubtype         = nuts.getsubtype
19local getattr            = nuts.getattr
20local getlist            = nuts.getlist
21local getchar            = nuts.getchar
22local getnext            = nuts.getnext
23
24local setattr            = nuts.setattr
25local setlink            = nuts.setlink
26local setchar            = nuts.setchar
27local setsubtype         = nuts.setsubtype
28local getwidth           = nuts.getwidth
29local setwidth           = nuts.setwidth
30
31local nextglyph          = nuts.traversers.glyph
32local nextnode           = nuts.traversers.node
33
34----- copy_node          = nuts.copy
35local insertafter        = nuts.insertafter
36local copynocomponents   = nuts.components.copynocomponents
37
38local nodecodes          = nodes.nodecodes
39local gluecodes          = nodes.gluecodes
40
41local glue_code          = nodecodes.glue
42----- kern_code          = nodecodes.kern
43local glyph_code         = nodecodes.glyph
44local hlist_code         = nodecodes.hlist
45local vlist_code         = nodecodes.vlist
46
47local userskip_code      = gluecodes.user
48local spaceskip_code     = gluecodes.spaceskip
49local xspaceskip_code    = gluecodes.xspaceskip
50
51local a_characters       = attributes.private("characters")
52
53local nofreplaced        = 0
54
55-- todo: nbsp etc
56-- todo: collapse kerns (not needed, backend does this)
57-- todo: maybe cache as we now create many nodes
58-- todo: check for subtype related to spacing (13/14 but most seems to be user anyway)
59
60local trace = false   trackers.register("backend.spaces", function(v) trace = v end)
61local slot  = nil
62
63local function injectspaces(head)
64    local p, p_id
65    local n = head
66    while n do
67        local id = getid(n)
68        if id == glue_code then
69            if p and getid(p) == glyph_code then
70                local s = getsubtype(n)
71                if s == spaceskip_code or s == xspaceskip_code then
72                    -- unless we don't care about the little bit of overhead
73                    -- we can just: local g = copy_node(g)
74                    local g = copynocomponents(p)
75                    local a = getattr(n,a_characters)
76                    setchar(g,slot)
77                    setlink(p,g,n)
78                    setwidth(n,getwidth(n) - getwidth(g))
79                 -- setsubtype(n,userskip_code)
80                    if a then
81                        setattr(g,a_characters,a)
82                    end
83                    setattr(n,a_characters,0)
84                    nofreplaced = nofreplaced + 1
85                end
86            end
87        elseif id == hlist_code or id == vlist_code then
88            injectspaces(getlist(n),slot)
89        end
90        p_id = id
91        p = n
92        n = getnext(n)
93    end
94    return head
95end
96
97nodes.handlers.accessibility = function(head)
98    if trace then
99        if not slot then
100            slot = fonts.helpers.privateslot("visualspace")
101        end
102    else
103        slot = 32
104    end
105    return injectspaces(head,slot)
106end
107
108statistics.register("inserted spaces in output",function()
109    if nofreplaced > 0 then
110        return nofreplaced
111    end
112end)
113
114-- todo:
115
116-- local a_hyphenated = attributes.private('hyphenated')
117--
118-- local hyphenated, codes = { }, { }
119--
120-- local function compact(n)
121--     local t = { }
122--     for n in nextglyph, n do
123--         t[#t+1] = utfchar(getchar(n)) -- check for unicode
124--     end
125--     return concat(t,"")
126-- end
127--
128-- local function injectspans(head)
129--     local done = false
130--     for n, id in nextnode, tonuts(head) do
131--         if id == disc then
132--             local pre, post, replace = getdisc(n)
133--             if replace and pre then
134--                 local str = compact(replace)
135--                 local hsh = hyphenated[str]
136--                 if not hsh then
137--                     hsh = #codes + 1
138--                     hyphenated[str] = hsh
139--                     codes[hsh] = str
140--                 end
141--                 setattr(n,a_hyphenated,hsh)
142--                 done = true
143--             end
144--         elseif id == hlist_code or id == vlist_code then
145--             injectspans(getlist(n))
146--         end
147--     end
148--     return tonodes(head), done
149-- end
150--
151-- nodes.injectspans = injectspans
152--
153-- tasks.appendaction("processors", "words", "nodes.injectspans")
154--
155-- local pageliteral = nuts.pool.pageliteral
156--
157-- local function injectspans(head)
158--     local done = false
159--     for n, id in nextnode, tonut(head) do
160--         if id == disc then
161--             local a = getattr(n,a_hyphenated)
162--             if a then
163--                 local str = codes[a]
164--                 local b = pageliteral(format("/Span << /ActualText %s >> BDC", lpdf.tosixteen(str)))
165--                 local e = pageliteral("EMC")
166--                 insertbefore(head,n,b)
167--                 insertafter(head,n,e)
168--                 done = true
169--             end
170--         elseif id == hlist_code or id == vlist_code then
171--             injectspans(getlist(n))
172--         end
173--     end
174--     return tonodes(head), done
175-- end
176