1if not modules then modules = { } end modules ['good-mth'] = {
2 version = 1.000,
3 comment = "companion to font-lib.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 type, next, tonumber, unpack = type, next, tonumber, unpack
10local ceil = math.ceil
11local match = string.match
12
13local fonts = fonts
14
15local trace_goodies = false trackers.register("fonts.goodies", function(v) trace_goodies = v end)
16local report_goodies = logs.reporter("fonts","goodies")
17
18local registerotffeature = fonts.handlers.otf.features.register
19
20local fontgoodies = fonts.goodies or { }
21
22local fontcharacters = fonts.hashes.characters
23
24local trace_defining = false trackers.register("math.defining", function(v) trace_defining = v end)
25
26local report_math = logs.reporter("mathematics","initializing")
27
28local nuts = nodes.nuts
29
30local setlink = nuts.setlink
31
32local nodepool = nuts.pool
33
34local new_kern = nodepool.kern
35local new_glyph = nodepool.glyph
36local new_hlist = nodepool.hlist
37local new_vlist = nodepool.vlist
38
39local insertnodeafter = nuts.insertafter
40
41local helpers = fonts.helpers
42local upcommand = helpers.commands.up
43local rightcommand = helpers.commands.right
44local charcommand = helpers.commands.char
45local prependcommands = helpers.prependcommands
46
47
48
49
50local function withscriptcode(tfmdata,unicode,data,action)
51 if type(unicode) == "string" then
52 local p, u = match(unicode,"^(.-):(.-)$")
53 if u then
54 u = tonumber(u)
55 if u then
56 local slots = fonts.helpers.mathscriptslots(tfmdata,u)
57 if slots then
58 if p == "*" then
59 action(u,data)
60 for i=1,#slots do
61 action(slots[i],data)
62 end
63 else
64 p = tonumber(p)
65 if p then
66 action(slots[p],data)
67 end
68 end
69 end
70 end
71 end
72 else
73 action(unicode,data)
74 end
75end
76
77local function finalize(tfmdata,feature,value)
78
79 local goodies = tfmdata.goodies
80 if goodies then
81 local virtualized = mathematics.virtualized
82 for i=1,#goodies do
83 local goodie = goodies[i]
84 local mathematics = goodie.mathematics
85 local dimensions = mathematics and mathematics.dimensions
86 if dimensions then
87 if trace_defining then
88 report_math("overloading dimensions in %a @ %p",tfmdata.properties.fullname,tfmdata.parameters.size)
89 end
90 local characters = tfmdata.characters
91 local descriptions = tfmdata.descriptions
92 local parameters = tfmdata.parameters
93 local factor = parameters.factor
94 local hfactor = parameters.hfactor
95 local vfactor = parameters.vfactor
96 local function overloadone(unicode,data)
97 local character = characters[unicode]
98 if not character then
99 local c = virtualized[unicode]
100 if c then
101 character = characters[c]
102 end
103 end
104 if character then
105 local width = data.width
106 local height = data.height
107 local depth = data.depth
108 if trace_defining and (width or height or depth) then
109 report_math("overloading dimensions of %C, width %p, height %p, depth %p",
110 unicode,width or 0,height or 0,depth or 0)
111 end
112 if width then character.width = width * hfactor end
113 if height then character.height = height * vfactor end
114 if depth then character.depth = depth * vfactor end
115
116 local xoffset = data.xoffset
117 local yoffset = data.yoffset
118 if xoffset == "llx" then
119 local d = descriptions[unicode]
120 if d then
121 xoffset = - d.boundingbox[1] * hfactor
122 character.width = character.width + xoffset
123 xoffset = rightcommand[xoffset]
124 else
125 xoffset = nil
126 end
127 elseif xoffset and xoffset ~= 0 then
128 xoffset = rightcommand[xoffset * hfactor]
129 else
130 xoffset = nil
131 end
132 if yoffset and yoffset ~= 0 then
133 yoffset = upcommand[yoffset * vfactor]
134 else
135 yoffset = nil
136 end
137 if xoffset or yoffset then
138 local commands = character.commands
139 if commands then
140 prependcommands(commands,yoffset,xoffset)
141 else
142 local slot = charcommand[unicode]
143 if xoffset and yoffset then
144 character.commands = { xoffset, yoffset, slot }
145 elseif xoffset then
146 character.commands = { xoffset, slot }
147 else
148 character.commands = { yoffset, slot }
149 end
150 end
151 end
152 elseif trace_defining then
153 report_math("no overloading dimensions of %C, not in font",unicode)
154 end
155 end
156 local function overload(dimensions)
157 for unicode, data in next, dimensions do
158 withscriptcode(tfmdata,unicode,data,overloadone)
159 end
160 end
161 if value == nil then
162 value = { "default" }
163 end
164 if value == "all" or value == true then
165 for name, value in next, dimensions do
166 overload(value)
167 end
168 else
169 if type(value) == "string" then
170 value = utilities.parsers.settings_to_array(value)
171 end
172 if type(value) == "table" then
173 for i=1,#value do
174 local d = dimensions[value[i]]
175 if d then
176 overload(d)
177 end
178 end
179 end
180 end
181 end
182 end
183 end
184end
185
186registerotffeature {
187 name = "mathdimensions",
188 description = "manipulate math dimensions",
189
190 manipulators = {
191 base = finalize,
192 node = finalize,
193 }
194}
195
196local function initialize(goodies)
197 local mathgoodies = goodies.mathematics
198 if mathgoodies then
199 local virtuals = mathgoodies.virtuals
200 local mapfiles = mathgoodies.mapfiles
201 local maplines = mathgoodies.maplines
202 if virtuals then
203 for name, specification in next, virtuals do
204
205 mathematics.makefont(name,specification,goodies)
206 end
207 end
208 if mapfiles then
209 for i=1,#mapfiles do
210 fonts.mappings.loadfile(mapfiles[i])
211 end
212 end
213 if maplines then
214 for i=1,#maplines do
215 fonts.mappings.loadline(maplines[i])
216 end
217 end
218 end
219end
220
221fontgoodies.register("mathematics", initialize)
222
223
224
225local function initialize(tfmdata)
226
227 if tfmdata.mathparameters then
228 local goodies = tfmdata.goodies
229 if goodies then
230 local characters = tfmdata.characters
231 if characters[0x1D44E] then
232
233 for i=1,#goodies do
234 local mathgoodies = goodies[i].mathematics
235 if mathgoodies then
236 local kerns = mathgoodies.kerns
237 if kerns then
238 local function kernone(unicode,data)
239 local chardata = characters[unicode]
240 if chardata and (not chardata.mathkerns or data.force) then
241 chardata.mathkerns = data
242 end
243 end
244 for unicode, data in next, kerns do
245 withscriptcode(tfmdata,unicode,data,kernone)
246 end
247 return
248 end
249 end
250 end
251 else
252 return
253 end
254 end
255 end
256end
257
258registerotffeature {
259 name = "mathkerns",
260 description = "math kerns",
261
262 initializers = {
263 base = initialize,
264 node = initialize,
265 }
266}
267
268
269
270
271
272local function initialize(tfmdata)
273 local goodies = tfmdata.goodies
274 if goodies then
275 local shared = tfmdata.shared
276 for i=1,#goodies do
277 local mathgoodies = goodies[i].mathematics
278 if mathgoodies then
279 local mathitalics = mathgoodies.italics
280 if mathitalics then
281 local properties = tfmdata.properties
282 if properties.setitalics then
283 mathitalics = mathitalics[file.nameonly(properties.name)] or mathitalics
284 if mathitalics then
285 if trace_goodies then
286 report_goodies("loading mathitalics for font %a",properties.name)
287 end
288 local corrections = mathitalics.corrections
289 local defaultfactor = mathitalics.defaultfactor
290
291 if corrections then
292 fontgoodies.registerpostprocessor(tfmdata, function(tfmdata)
293
294 local properties = tfmdata.properties
295 local parameters = tfmdata.parameters
296 local characters = tfmdata.characters
297 properties.mathitalic_defaultfactor = defaultfactor
298 properties.mathitalic_defaultvalue = defaultfactor * parameters.quad
299 if trace_goodies then
300 report_goodies("assigning mathitalics for font %a",properties.name)
301 end
302 local quad = parameters.quad
303 local hfactor = parameters.hfactor
304 for k, v in next, corrections do
305 local c = characters[k]
306 if c then
307 if v > -1 and v < 1 then
308 c.italic = v * quad
309 else
310 c.italic = v * hfactor
311 end
312 else
313 report_goodies("invalid mathitalics entry %U for font %a",k,properties.name)
314 end
315 end
316 end)
317 end
318 return
319 end
320 end
321 end
322 end
323 end
324 end
325end
326
327registerotffeature {
328 name = "mathitalics",
329 description = "additional math italic corrections",
330
331 initializers = {
332 base = initialize,
333 node = initialize,
334 }
335}
336
337
338
339local function mathradicalaction(n,h,v,font,mchar,echar)
340 local characters = fontcharacters[font]
341 local mchardata = characters[mchar]
342 local echardata = characters[echar]
343 local ewidth = echardata.width
344 local mwidth = mchardata.width
345 local delta = h - ewidth
346 local glyph = new_glyph(font,echar)
347 local head = glyph
348 if delta > 0 then
349 local count = ceil(delta/mwidth)
350 local kern = (delta - count * mwidth) / count
351 for i=1,count do
352 local k = new_kern(kern)
353 local g = new_glyph(font,mchar)
354 setlink(k,head)
355 setlink(g,k)
356 head = g
357 end
358 end
359 local height = mchardata.height
360 local list = new_hlist(head)
361 local kern = new_kern(height-v)
362 list = setlink(kern,list)
363 local list = new_vlist(kern)
364 insertnodeafter(n,n,list)
365end
366
367local function mathhruleaction(n,h,v,font,bchar,mchar,echar)
368 local characters = fontcharacters[font]
369 local bchardata = characters[bchar]
370 local mchardata = characters[mchar]
371 local echardata = characters[echar]
372 local bwidth = bchardata.width
373 local mwidth = mchardata.width
374 local ewidth = echardata.width
375 local delta = h - ewidth - bwidth
376 local glyph = new_glyph(font,echar)
377 local head = glyph
378 if delta > 0 then
379 local count = ceil(delta/mwidth)
380 local kern = (delta - count * mwidth) / (count+1)
381 for i=1,count do
382 local k = new_kern(kern)
383 local g = new_glyph(font,mchar)
384 setlink(k,head)
385 setlink(g,k)
386 head = g
387 end
388 local k = new_kern(kern)
389 setlink(k,head)
390 head = k
391 end
392 local g = new_glyph(font,bchar)
393 setlink(g,head)
394 head = g
395 local height = mchardata.height
396 local list = new_hlist(head)
397 local kern = new_kern(height-v)
398 list = setlink(kern,list)
399 local list = new_vlist(kern)
400 insertnodeafter(n,n,list)
401end
402
403local function initialize(tfmdata)
404 local goodies = tfmdata.goodies
405 if goodies then
406 local resources = tfmdata.resources
407 local ruledata = { }
408 for i=1,#goodies do
409 local mathematics = goodies[i].mathematics
410 if mathematics then
411 local rules = mathematics.rules
412 if rules then
413 for tag, name in next, rules do
414 ruledata[tag] = name
415 end
416 end
417 end
418 end
419 if next(ruledata) then
420 local characters = tfmdata.characters
421 local unicodes = resources.unicodes
422 if characters and unicodes then
423 local mathruleactions = resources.mathruleactions
424 if not mathruleactions then
425 mathruleactions = { }
426 resources.mathruleactions = mathruleactions
427 end
428
429 local mchar = unicodes[ruledata["radical.extender"] or false]
430 local echar = unicodes[ruledata["radical.end"] or false]
431 if mchar and echar then
432 mathruleactions.radicalaction = function(n,h,v,font)
433 mathradicalaction(n,h,v,font,mchar,echar)
434 end
435 end
436
437 local bchar = unicodes[ruledata["hrule.begin"] or false]
438 local mchar = unicodes[ruledata["hrule.extender"] or false]
439 local echar = unicodes[ruledata["hrule.end"] or false]
440 if bchar and mchar and echar then
441 mathruleactions.hruleaction = function(n,h,v,font)
442 mathhruleaction(n,h,v,font,bchar,mchar,echar)
443 end
444 end
445
446
447 end
448 end
449 end
450end
451
452registerotffeature {
453 name = "mathrules",
454 description = "check math rules",
455 default = true,
456 initializers = {
457 base = initialize,
458 node = initialize,
459 }
460}
461 |