font-vir.lua /size: 6793 b    last modification: 2023-12-21 09:44
1if not modules then modules = { } end modules ['font-vir'] = {
2    version   = 1.001,
3    comment   = "companion to font-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-- This is very experimental code! Not yet adapted to recent changes. This will
10-- change. Actually we moved on.
11
12-- present in the backend but unspecified:
13--
14-- vf.rule vf.special vf.right vf.push vf.down vf.char vf.node vf.fontid vf.pop vf.image vf.nop
15
16local next, setmetatable, getmetatable = next, setmetatable, getmetatable
17
18local allocate          = utilities.storage.allocate
19local setmetatableindex = table.setmetatableindex
20local fastcopy          = table.fastcopy
21
22local fonts             = fonts
23local constructors      = fonts.constructors
24local vf                = constructors.handlers.vf
25vf.version              = 1.000 -- same as tfm
26
27-- -- We overload the VF reader.:
28--
29-- general code / already frozen
30--
31-- function vf.find(name)
32--     name = file.removesuffix(file.basename(name))
33--     if constructors.resolvevirtualtoo then
34--         local format = fonts.loggers.format(name)
35--         if format == 'tfm' or format == 'ofm' then
36--             if trace_defining then
37--                 report_defining("locating vf for %a",name)
38--             end
39--             return findbinfile(name,"ovf") or ""
40--         else
41--             if trace_defining then
42--                 report_defining("vf for %a is already taken care of",name)
43--             end
44--             return ""
45--         end
46--     else
47--         if trace_defining then
48--             report_defining("locating vf for %a",name)
49--         end
50--         return findbinfile(name,"ovf") or ""
51--     end
52-- end
53--
54-- callbacks.register('find_vf_file', vf.find, "locating virtual fonts, insofar needed") -- not that relevant any more
55
56-- specific code (will move to other module)
57
58local definers     = fonts.definers
59local methods      = definers.methods
60
61local variants     = allocate()
62local combinations = { }
63local combiner     = { }
64local whatever     = allocate()
65local helpers      = allocate()
66local predefined   = fonts.helpers.commands
67
68methods.variants   = variants -- todo .. wrong namespace
69vf.combinations    = combinations
70vf.combiner        = combiner
71vf.whatever        = whatever
72vf.helpers         = helpers
73vf.predefined      = predefined
74
75setmetatableindex(whatever, function(t,k) local v = { } t[k] = v return v end)
76
77local function checkparameters(g,f)
78    if f and g and not g.parameters and #g.fonts > 0 then
79        local p = { }
80        for k,v in next, f.parameters do
81            p[k] = v
82        end
83        g.parameters = p
84        setmetatable(p, getmetatable(f.parameters))
85    end
86end
87
88function methods.install(tag, rules)
89    vf.combinations[tag] = rules
90    variants[tag] = function(specification)
91        return vf.combine(specification,tag)
92    end
93end
94
95local function combine_load(g,name)
96    return constructors.readanddefine(name or g.specification.name,g.specification.size)
97end
98
99local function combine_assign(g, name, from, to, start, force)
100    local f, id = combine_load(g,name)
101    if f and id then
102        -- optimize for whole range, then just g = f
103        if not from  then from, to = 0, 0xFF00 end
104        if not to    then to       = from      end
105        if not start then start    = from      end
106        local fc = f.characters
107        local gc = g.characters
108        local fd = f.descriptions
109        local gd = g.descriptions
110        local hn = #g.fonts+1
111        g.fonts[hn] = { id = id } -- no need to be sparse
112        for i=from,to do
113            if fc[i] and (force or not gc[i]) then
114                gc[i] = fastcopy(fc[i],true) -- can be optimized
115                gc[i].commands = { { "slot", hn, start } }
116                gd[i] = fd[i]
117            end
118            start = start + 1
119        end
120        checkparameters(g,f)
121    end
122end
123
124local function combine_process(g,list)
125    if list then
126        for _,v in next, list do
127            (combiner.commands[v[1]] or nop)(g,v)
128        end
129    end
130end
131
132local function combine_names(g,name,force)
133    local f, id = constructors.readanddefine(name,g.specification.size)
134    if f and id then
135        local fc = f.characters
136        local gc = g.characters
137        local fd = f.descriptions
138        local gd = g.descriptions
139        g.fonts[#g.fonts+1] = { id = id } -- no need to be sparse
140        local hn = #g.fonts
141        for k, v in next, fc do
142            if force or not gc[k] then
143                gc[k] = fastcopy(v,true)
144                gc[k].commands = { { "slot", hn, k } }
145                gd[i] = fd[i]
146            end
147        end
148        checkparameters(g,f)
149    end
150end
151
152local combine_feature = function(g,v)
153    local key   = v[2]
154    local value = v[3]
155    if key then
156        if value == nil then
157            value = true
158        end
159        local specification = g.specification
160        if specification then
161            local normalfeatures = specification.features.normal
162            if normalfeatures then
163                normalfeatures[key] = value -- otf?
164            end
165        end
166    end
167end
168
169--~ combiner.load    = combine_load
170--~ combiner.assign  = combine_assign
171--~ combiner.process = combine_process
172--~ combiner.names   = combine_names
173--~ combiner.feature = combine_feature
174
175combiner.commands = allocate {
176    ["initialize"]      = function(g,v) combine_assign    (g,g.properties.name) end,
177    ["include-method"]  = function(g,v) combine_process   (g,combinations[v[2]])  end, -- name
178 -- ["copy-parameters"] = function(g,v) combine_parameters(g,v[2]) end, -- name
179    ["copy-range"]      = function(g,v) combine_assign    (g,v[2],v[3],v[4],v[5],true) end, -- name, from-start, from-end, to-start
180    ["copy-char"]       = function(g,v) combine_assign    (g,v[2],v[3],v[3],v[4],true) end, -- name, from, to
181    ["fallback-range"]  = function(g,v) combine_assign    (g,v[2],v[3],v[4],v[5],false) end, -- name, from-start, from-end, to-start
182    ["fallback-char"]   = function(g,v) combine_assign    (g,v[2],v[3],v[3],v[4],false) end, -- name, from, to
183    ["copy-names"]      = function(g,v) combine_names     (g,v[2],true) end,
184    ["fallback-names"]  = function(g,v) combine_names     (g,v[2],false) end,
185    ["feature"]         =               combine_feature,
186}
187
188function vf.combine(specification,tag)
189    local g = {
190        name          = specification.name,
191        properties    = {
192            virtualized = true,
193        },
194        fonts         = {
195        },
196        characters    = {
197        },
198        descriptions  = {
199        },
200        specification = fastcopy(specification),
201    }
202    combine_process(g,combinations[tag])
203    return g
204end
205