font-hsh.lmt /size: 11 Kb    last modification: 2024-01-16 10:22
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, -- really ? maybe move to 655360 instead
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        size         = 786432,
88        slant        =      0, -- 1
89        space        = 256377, -- 2
90        spacestretch = 128188, -- 3
91        spaceshrink  =  85459, -- 4
92        xheight      = 338952, -- 5
93        quad         = 786432, -- 6
94        extraspace   =  85459, -- 7
95    },
96}
97
98fonts.nulldata = nulldata
99
100fonts.constructors.enhanceparameters(nulldata.parameters) -- official copies for us
101
102setmetatableindex(identifiers, function(t,k)
103    return k == true and identifiers[currentfont()] or nulldata
104end)
105
106if font then
107
108    -- to be used
109
110    local define  = font.define
111    local setfont = font.setfont
112    local frozen  = font.frozen
113
114    function fonts.reserveid(fontdata)
115        return define(fontdata or nulldata)
116    end
117
118    function fonts.enhanceid(id,fontdata)
119        if not frozen(id) then
120            setfont(id,fontdata)
121        end
122    end
123
124end
125
126setmetatableindex(characters, function(t,k)
127    if k == true then
128        return characters[currentfont()]
129    else
130        local characters = identifiers[k].characters
131        t[k] = characters
132        return characters
133    end
134end)
135
136setmetatableindex(descriptions, function(t,k)
137    if k == true then
138        return descriptions[currentfont()]
139    else
140        local descriptions = identifiers[k].descriptions
141        t[k] = descriptions
142        return descriptions
143    end
144end)
145
146setmetatableindex(parameters, function(t,k)
147    if k == true then
148        return parameters[currentfont()]
149    else
150        local parameters = identifiers[k].parameters
151        t[k] = parameters
152        return parameters
153    end
154end)
155
156setmetatableindex(mathparameters, function(t,k)
157    if k == true then
158        return mathparameters[currentfont()]
159    else
160        local mathparameters = identifiers[k].mathparameters
161        t[k] = mathparameters
162        return mathparameters
163    end
164end)
165
166setmetatableindex(properties, function(t,k)
167    if k == true then
168        return properties[currentfont()]
169    else
170        local properties = identifiers[k].properties
171        t[k] = properties
172        return properties
173    end
174end)
175
176setmetatableindex(resources, function(t,k)
177    if k == true then
178        return resources[currentfont()]
179    else
180        local shared    = identifiers[k].shared
181        local rawdata   = shared and shared.rawdata
182        local resources = rawdata and rawdata.resources
183        t[k] = resources or false -- better than resolving each time
184        return resources
185    end
186end)
187
188setmetatableindex(features, function(t,k)
189    if k == true then
190        return features[currentfont()]
191    else
192        local shared = identifiers[k].shared
193        local features = shared and shared.features or { }
194        t[k] = features
195        return features
196    end
197end)
198
199local nospacing = {
200    width   = 0,
201    stretch = 0,
202    shrink  = 0,
203    extra   = 0,
204}
205
206setmetatableindex(spacings, function(t,k)
207    if k == true then
208        return spacings[currentfont()]
209    else
210        local parameters = parameters[k]
211        local spacing = parameters and parameters.spacing or nospacing
212        t[k] = spacing
213        return spacing
214    end
215end)
216
217setmetatableindex(spaces, function(t,k)
218    if k == true then
219        return spaces[currentfont()]
220    else
221        local space = spacings[k].width
222        t[k] = space
223        return space
224    end
225end)
226
227setmetatableindex(marks, function(t,k)
228    if k == true then
229        return marks[currentfont()]
230    else
231        local resources = identifiers[k].resources or { }
232        local marks     = resources.marks or { }
233        t[k] = marks
234        return marks
235    end
236end)
237
238setmetatableindex(classes, function(t,k)
239    if k == true then
240        return classes[currentfont()]
241    else
242        local resources = identifiers[k].resources or { }
243        local classes   = resources.classes or { }
244        t[k] = classes
245        return classes
246    end
247end)
248
249setmetatableindex(quads, function(t,k)
250    if k == true then
251        return quads[currentfont()]
252    else
253        local parameters = rawget(parameters,k)
254        local quad
255        if parameters then
256            quad = parameters.quad
257        elseif dummyglyph then
258            dummyglyph.font = k
259            dummyglyph.char = 0x2014  -- emdash
260            quad            = dummyglyph.width -- dirty trick
261        end
262        if not quad or quad == 0 then
263            quad = 655360 -- lm 10pt
264        end
265        t[k] = quad
266        return quad
267    end
268end)
269
270setmetatableindex(xheights, function(t,k)
271    if k == true then
272        return xheights[currentfont()]
273    else
274        local parameters = rawget(parameters,k)
275        local xheight
276        if parameters then
277            xheight = parameters.xheight
278        elseif dummyglyph then
279            dummyglyph.font = k
280            dummyglyph.char = 0x78     -- x
281            xheight         = dummyglyph.height -- dirty trick
282        end
283        if not xheight or xheight == 0 then
284            xheight = 282460 -- lm 10pt
285        end
286        t[k] = xheight
287        return xheight
288    end
289end)
290
291setmetatableindex(italics, function(t,k) -- is test !
292    if k == true then
293        return italics[currentfont()]
294    else
295        local properties = identifiers[k].properties
296        local hasitalics = properties and properties.hasitalics or (properties.autoitalicamount and properties.autoitalicamount ~= 0)
297        if hasitalics then
298            hasitalics = characters[k] -- convenient return
299        else
300            hasitalics = false
301        end
302        t[k] = hasitalics
303        return hasitalics
304    end
305end)
306
307setmetatableindex(dynamics, function(t,k)
308    if k == true then
309        return dynamics[currentfont()]
310    else
311        local shared = identifiers[k].shared
312        local dynamics = shared and shared.dynamics or false
313        t[k] = dynamics
314        return dynamics
315    end
316end)
317
318setmetatableindex(unicodes, function(t,k) -- always a unicode
319    if k == true then
320        return unicodes[currentfont()]
321    else
322        local resources = resources[k]
323        local unicodes  = resources and resources.unicodes or { }
324        t[k] = unicodes
325        return unicodes
326    end
327end)
328
329setmetatableindex(originals, function(t,k) -- always a unicode
330    if k == true then
331        return originals[currentfont()]
332    else
333        local resolved = { }
334        setmetatableindex(resolved,function(t,name)
335            local u = unicodes[k][name]
336            local d = u and descriptions[k][u]
337            local v = d and d.unicode or u or 0 -- so we return notdef (at least for the moment)
338            t[name] = u
339            return v
340        end)
341        t[k] = resolved
342        return resolved
343    end
344end)
345
346setmetatableindex(unislots, function(t,k)
347    if k == true then
348        return unislots[currentfont()]
349    else
350        local characters = identifiers[k].characters
351        local resolved   = setmetatableindex(function(t,k)
352            local c = characters[k]
353            local v = c and c.unicode or 0xFFFD
354            t[k] = v
355            return v -- can be a table !
356        end)
357        t[k] = resolved
358        return resolved
359    end
360end)
361
362setmetatableindex(modes, function(t,k)
363    if k == true then
364        return modes[currentfont()]
365    else
366        local mode = properties[k].mode or "base"
367        t[k] = mode
368        return mode
369    end
370end)
371
372setmetatableindex(variants, function(t,k)
373    if k == true then
374        return variants[currentfont()]
375    else
376        local resources = resources[k]
377        if resources then
378            local variants = resources.variants
379            if variants and next(variants) then
380                t[k] = variants
381                return variants
382            end
383        end
384        t[k] = false
385        return false
386    end
387end)
388
389if font then
390
391    function font.getfont(id)
392        return identifiers[id]
393    end
394
395end
396
397-- font.setfont = currentfont -- bah, no native 'setfont' as name
398