math-fnt.lmt /size: 6017 b    last modification: 2025-02-21 11:03
1if not modules then modules = { } end modules ['math-fnt'] = {
2    version   = 1.001,
3    comment   = "companion to math-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
9-- It is a pitty that we don't have a unicode character that can be used but that never
10-- gets copied when we cut and paste. Not all pdf viewers ignore 0xFFFD for instance.
11
12local round = math.round
13local setmetatableindex = table.setmetatableindex
14
15local nuts          = nodes.nuts
16local tonut         = nodes.tonut
17local tonode        = nodes.tonode
18local nodepool      = nuts.pool
19
20local vlist_code    <const> = nodes.nodecodes.vlist
21
22local new_hlist     = nodepool.hlist
23local new_vlist     = nodepool.vlist
24----- new_glyph     = nodepool.glyph
25local new_glyph     = nuts.newmathglyph
26
27local getattrlst    = nuts.getattributelist
28local setattrlst    = nuts.setattributelist
29local setwhd        = nuts.setwhd
30local getwhd        = nuts.getwhd
31local getid         = nuts.getid
32
33local chardata      = fonts.hashes.characters
34local addcharacters = font.addcharacters
35
36-- not yet ok for compact fonts .. needs checking .. or just make this non-compact only
37-- there's also an inaccuracy creeping in: \sqrt{\quad\blackrule[height=25pt,depth=25pt]}
38
39local cache = setmetatableindex(function(t,width)
40    local v = setmetatableindex(function(t,height)
41        local v = setmetatableindex(function(t,depth)
42            local v = setmetatableindex(function(t,font)
43                local v = setmetatableindex(function(t,char)
44                    t[char] = v
45                    return v
46                end)
47                t[font] = v
48                return v
49            end)
50            t[depth] = v
51            return v
52        end)
53        t[height] = v
54        return v
55    end)
56    t[width] = v
57    return v
58end)
59
60local enabled = "both"  directives.register("math.extensibles", function(v) enabled = v end) -- default per 2022-08-25
61
62-- updaters.register("tagging.state.enable", function() enabled = "both" end) -- for now
63
64local function register_extensible(font,char,style,att,box)
65    if enabled then
66        -- We don't share (yet)!
67        local fontdata = chardata[font]
68        local oldchar  = fontdata[char]
69        if oldchar and not oldchar.keepvirtual then
70            if enabled == true or enabled == "both" or oldchar.partsorientation == enabled then
71                -- we're okay
72            else
73                return
74            end
75            local bx = tonut(box)
76            -- actually we don't want colors and such so if we do finalize we
77            -- should be more selective:
78    --         updaters.apply("tagging.state.disable")
79    --         nodes.handlers.finalizelist(bx)
80    --         updaters.apply("tagging.state.enable")
81-- updaters.apply("tagging.state.disable")
82            local id = getid(bx)
83            local al = tonut(att)
84            local wd, ht, dp = getwhd(bx)
85            local unicode = oldchar.unicode or char
86            -- we cannot have self referencing t3 fonts .. see devirtualize code
87            local oldcommands = oldchar.oldcommands
88            local newcommands = oldchar.commands
89            if oldcommands then
90                oldchar.commands = oldcommands
91            end
92            -- these need to be applied here
93            local p  = fonts.hashes.parameters[font]
94            local sx = round(1000/(p.extendfactor  or 1)) or 1000
95            local sy = round(1000/(p.squeezefactor or 1)) or 1000
96--             -- we saved a scaled glyph stream so we now use an unscaled one ... horrible hack:
97--             if sx ~= 1000 then
98--                 wd = wd * 7200/7227
99--             end
100--             if sy ~= 1000 then
101--                 ht = ht * 7200/7227
102--                 dp = dp * 7200/7227
103--             end
104            --
105        --  local private = fonts.helpers.setboxdirectly(font,unicode,box) -- maybe cache in setboxdirectly
106            local private = cache[wd][ht][dp][font][unicode]
107            if private then
108nodes.flushlist(box)
109            else
110                private = fonts.helpers.setboxdirectly(font,unicode,box,true) -- expose=true so we get color
111                cache[wd][ht][dp][font][unicode] = private
112            end
113            local glyph = new_glyph(font,private,al)
114            setattrlst(glyph,al)
115            nuts.setscales(glyph,1000,sx,sy)
116            --
117         -- if fonts.hashes.properties[font].compactmath then
118         --     nuts.setscales(g,1000,1000,1000)
119         -- end
120            --
121            -- nasty, testcase: bold math sqrt extensible
122            --
123            local n = new_hlist(glyph)
124            --
125            if newcommands then
126                oldchar.commands = newcommands
127            end
128            --
129         -- local newchar = {
130         --     unicode = unicode,
131         --     width   = wd,
132         --     height  = ht,
133         --     depth  =  dp,
134         -- }
135         -- local p = oldchar.parts
136         -- if p then
137         --     local first = fontdata[p[#p].glyph]
138         --     local last  = fontdata[p[ 1].glyph]
139         --     if first then
140         --         newchar.topleft  = first.topleft
141         --         newchar.topright = first.topright
142         --     end
143         --     if last then
144         --         newchar.bottomleft  = last.bottomleft
145         --         newchar.bottomright = last.bottomright
146         --     end
147         -- end
148         -- addcharacters(font, { [private] = newchar })
149            -- so the dimensions of the box don't match the glyph scale!
150            setwhd(n,wd,ht,dp)
151            setattrlst(n,al)
152            if id == vlist_code then
153                n = new_vlist(n)
154                setwhd(n,wd,ht,dp)
155                setattrlst(n,al)
156            end
157            return tonode(n)
158        end
159    end
160end
161
162callbacks.register("register_extensible",register_extensible,"register math extensible construct")
163