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