font-hsh.lua /size: 11 Kb    last modification: 2021-10-28 13:50
1if not modules then modules = { } end modules ['font-hsh'] = {
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
9local rawget = rawget
10
11local setmetatableindex = table.setmetatableindex
12local currentfont       = font and font.current -- used in the web service
13local allocate          = utilities.storage.allocate
14
15local fonts         = fonts
16local hashes        = fonts.hashes or allocate()
17fonts.hashes        = hashes
18
19-- todo: autoallocate ... just create on the fly .. use constructors.keys (problem: plurals)
20
21local identifiers    = hashes.identifiers    or allocate()
22local characters     = hashes.characters     or allocate() -- chardata
23local descriptions   = hashes.descriptions   or allocate()
24local parameters     = hashes.parameters     or allocate()
25local mathparameters = hashes.mathparameters or allocate()
26local properties     = hashes.properties     or allocate()
27local resources      = hashes.resources      or allocate()
28local spacings       = hashes.spacings       or allocate()
29local spaces         = hashes.spaces         or allocate()
30local quads          = hashes.quads          or allocate() -- maybe also spacedata
31local xheights       = hashes.xheights       or allocate()
32local csnames        = hashes.csnames        or allocate() -- namedata
33local features       = hashes.features       or allocate()
34local marks          = hashes.marks          or allocate()
35local classes        = hashes.classes        or allocate()
36local italics        = hashes.italics        or allocate()
37local lastmathids    = hashes.lastmathids    or allocate()
38local dynamics       = hashes.dynamics       or allocate()
39local unicodes       = hashes.unicodes       or allocate()
40local unislots       = hashes.unislots       or allocate()
41local originals      = hashes.originals      or allocate()
42local modes          = hashes.modes          or allocate()
43local variants       = hashes.variants       or allocate()
44
45hashes.characters     = characters
46hashes.descriptions   = descriptions
47hashes.parameters     = parameters
48hashes.mathparameters = mathparameters
49hashes.properties     = properties
50hashes.resources      = resources
51hashes.spacings       = spacings
52hashes.spaces         = spaces
53hashes.quads          = quads                 hashes.emwidths  = quads
54hashes.xheights       = xheights              hashes.exheights = xheights
55hashes.csnames        = csnames
56hashes.features       = features
57hashes.marks          = marks
58hashes.classes        = classes
59hashes.italics        = italics
60hashes.lastmathids    = lastmathids
61hashes.dynamics       = dynamics
62hashes.unicodes       = unicodes
63hashes.unislots       = unislots
64hashes.originals      = originals
65hashes.modes          = modes
66hashes.variants       = variants
67
68local nodepool   = nodes and nodes.pool
69local dummyglyph = nodepool and nodepool.register(nodepool.glyph())
70
71local nulldata = allocate {
72    name         = "nullfont",
73    characters   = { },
74    descriptions = { },
75    properties   = {
76        designsize = 786432,
77    },
78    parameters   = { -- lmromanregular @ 12pt
79        slantperpoint =      0,
80        spacing       = {
81            width   = 256377,
82            stretch = 128188,
83            shrink  = 85459,
84            extra   = 85459,
85        },
86        quad          = 786432,
87        xheight       = 338952,
88        -- compatibility:
89        slant         =      0, -- 1
90        space         = 256377, -- 2
91        space_stretch = 128188, -- 3
92        space_shrink  =  85459, -- 4
93        x_height      = 338952, -- 5
94        quad          = 786432, -- 6
95        extra_space   =  85459, -- 7
96        size          = 786432,
97    },
98}
99
100fonts.nulldata = nulldata
101
102fonts.constructors.enhanceparameters(nulldata.parameters) -- official copies for us
103
104setmetatableindex(identifiers, function(t,k)
105    return k == true and identifiers[currentfont()] or nulldata
106end)
107
108if font then
109
110    -- to be used
111
112    local define  = font.define
113    local setfont = font.setfont
114    local frozen  = font.frozen
115
116    function fonts.reserveid(fontdata)
117        return define(fontdata or nulldata)
118    end
119
120    function fonts.enhanceid(id,fontdata)
121        if not frozen(id) then
122            setfont(id,fontdata)
123        end
124    end
125
126end
127
128setmetatableindex(characters, function(t,k)
129    if k == true then
130        return characters[currentfont()]
131    else
132        local characters = identifiers[k].characters
133        t[k] = characters
134        return characters
135    end
136end)
137
138setmetatableindex(descriptions, function(t,k)
139    if k == true then
140        return descriptions[currentfont()]
141    else
142        local descriptions = identifiers[k].descriptions
143        t[k] = descriptions
144        return descriptions
145    end
146end)
147
148setmetatableindex(parameters, function(t,k)
149    if k == true then
150        return parameters[currentfont()]
151    else
152        local parameters = identifiers[k].parameters
153        t[k] = parameters
154        return parameters
155    end
156end)
157
158setmetatableindex(mathparameters, function(t,k)
159    if k == true then
160        return mathparameters[currentfont()]
161    else
162        local mathparameters = identifiers[k].mathparameters
163        t[k] = mathparameters
164        return mathparameters
165    end
166end)
167
168setmetatableindex(properties, function(t,k)
169    if k == true then
170        return properties[currentfont()]
171    else
172        local properties = identifiers[k].properties
173        t[k] = properties
174        return properties
175    end
176end)
177
178setmetatableindex(resources, function(t,k)
179    if k == true then
180        return resources[currentfont()]
181    else
182        local shared    = identifiers[k].shared
183        local rawdata   = shared and shared.rawdata
184        local resources = rawdata and rawdata.resources
185        t[k] = resources or false -- better than resolving each time
186        return resources
187    end
188end)
189
190setmetatableindex(features, function(t,k)
191    if k == true then
192        return features[currentfont()]
193    else
194        local shared = identifiers[k].shared
195        local features = shared and shared.features or { }
196        t[k] = features
197        return features
198    end
199end)
200
201local nospacing = {
202    width   = 0,
203    stretch = 0,
204    shrink  = 0,
205    extra   = 0,
206}
207
208setmetatableindex(spacings, function(t,k)
209    if k == true then
210        return spacings[currentfont()]
211    else
212        local parameters = parameters[k]
213        local spacing = parameters and parameters.spacing or nospacing
214        t[k] = spacing
215        return spacing
216    end
217end)
218
219setmetatableindex(spaces, function(t,k)
220    if k == true then
221        return spaces[currentfont()]
222    else
223        local space = spacings[k].width
224        t[k] = space
225        return space
226    end
227end)
228
229setmetatableindex(marks, function(t,k)
230    if k == true then
231        return marks[currentfont()]
232    else
233        local resources = identifiers[k].resources or { }
234        local marks     = resources.marks or { }
235        t[k] = marks
236        return marks
237    end
238end)
239
240setmetatableindex(classes, function(t,k)
241    if k == true then
242        return classes[currentfont()]
243    else
244        local resources = identifiers[k].resources or { }
245        local classes   = resources.classes or { }
246        t[k] = classes
247        return classes
248    end
249end)
250
251setmetatableindex(quads, function(t,k)
252    if k == true then
253        return quads[currentfont()]
254    else
255        local parameters = rawget(parameters,k)
256        local quad
257        if parameters then
258            quad = parameters.quad
259        elseif dummyglyph then
260            dummyglyph.font = k
261            dummyglyph.char = 0x2014  -- emdash
262            quad            = dummyglyph.width -- dirty trick
263        end
264        if not quad or quad == 0 then
265            quad = 655360 -- lm 10pt
266        end
267        t[k] = quad
268        return quad
269    end
270end)
271
272setmetatableindex(xheights, function(t,k)
273    if k == true then
274        return xheights[currentfont()]
275    else
276        local parameters = rawget(parameters,k)
277        local xheight
278        if parameters then
279            xheight = parameters.xheight
280        elseif dummyglyph then
281            dummyglyph.font = k
282            dummyglyph.char = 0x78     -- x
283            xheight         = dummyglyph.height -- dirty trick
284        end
285        if not xheight or xheight == 0 then
286            xheight = 282460 -- lm 10pt
287        end
288        t[k] = xheight
289        return xheight
290    end
291end)
292
293setmetatableindex(italics, function(t,k) -- is test !
294    if k == true then
295        return italics[currentfont()]
296    else
297        local properties = identifiers[k].properties
298        local hasitalics = properties and properties.hasitalics
299        if hasitalics then
300            hasitalics = characters[k] -- convenient return
301        else
302            hasitalics = false
303        end
304        t[k] = hasitalics
305        return hasitalics
306    end
307end)
308
309setmetatableindex(dynamics, function(t,k)
310    if k == true then
311        return dynamics[currentfont()]
312    else
313        local shared = identifiers[k].shared
314        local dynamics = shared and shared.dynamics or false
315        t[k] = dynamics
316        return dynamics
317    end
318end)
319
320setmetatableindex(unicodes, function(t,k) -- always a unicode
321    if k == true then
322        return unicodes[currentfont()]
323    else
324        local resources = resources[k]
325        local unicodes  = resources and resources.unicodes or { }
326        t[k] = unicodes
327        return unicodes
328    end
329end)
330
331setmetatableindex(originals, function(t,k) -- always a unicode
332    if k == true then
333        return originals[currentfont()]
334    else
335        local resolved = { }
336        setmetatableindex(resolved,function(t,name)
337            local u = unicodes[k][name]
338            local d = u and descriptions[k][u]
339            local v = d and d.unicode or u or 0 -- so we return notdef (at least for the moment)
340            t[name] = u
341            return v
342        end)
343        t[k] = resolved
344        return resolved
345    end
346end)
347
348setmetatableindex(unislots, function(t,k)
349    if k == true then
350        return unislots[currentfont()]
351    else
352        local characters = identifiers[k].characters
353        local resolved   = setmetatableindex(function(t,k)
354            local c = characters[k]
355            local v = c and c.unicode or 0xFFFD
356            t[k] = v
357            return v -- can be a table !
358        end)
359        t[k] = resolved
360        return resolved
361    end
362end)
363
364setmetatableindex(modes, function(t,k)
365    if k == true then
366        return modes[currentfont()]
367    else
368        local mode = properties[k].mode or "base"
369        t[k] = mode
370        return mode
371    end
372end)
373
374setmetatableindex(variants, function(t,k)
375    if k == true then
376        return variants[currentfont()]
377    else
378        local resources = resources[k]
379        if resources then
380            local variants = resources.variants
381            if variants and next(variants) then
382                t[k] = variants
383                return variants
384            end
385        end
386        t[k] = false
387        return false
388    end
389end)
390
391if font then
392
393    function font.getfont(id)
394        return identifiers[id]
395    end
396
397end
398
399-- font.setfont = currentfont -- bah, no native 'setfont' as name
400