1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
|
if not modules then modules = { } end modules ['math-act'] = {
version = 1.001,
comment = "companion to math-ini.mkiv",
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright = "PRAGMA ADE / ConTeXt Development Team",
license = "see context related readme files"
}
-- Here we tweak some font properties (if needed).
local type, next = type, next
local fastcopy = table.fastcopy
local trace_defining = false trackers.register("math.defining", function(v) trace_defining = v end)
local report_math = logs.reporter("mathematics","initializing")
local context = context
local commands = commands
local mathematics = mathematics
local texdimen = tex.dimen
local abs = math.abs
local sequencers = utilities.sequencers
local appendgroup = sequencers.appendgroup
local appendaction = sequencers.appendaction
local mathfontparameteractions = sequencers.new {
name = "mathparameters",
arguments = "target,original",
}
appendgroup("mathparameters","before") -- user
appendgroup("mathparameters","system") -- private
appendgroup("mathparameters","after" ) -- user
function fonts.constructors.assignmathparameters(original,target)
local runner = mathfontparameteractions.runner
if runner then
runner(original,target)
end
end
function mathematics.initializeparameters(target,original)
local mathparameters = original.mathparameters
if mathparameters and next(mathparameters) then
target.mathparameters = mathematics.dimensions(mathparameters)
end
end
sequencers.appendaction("mathparameters","system","mathematics.initializeparameters")
local how = {
-- RadicalKernBeforeDegree = "horizontal",
-- RadicalKernAfterDegree = "horizontal",
ScriptPercentScaleDown = "unscaled",
ScriptScriptPercentScaleDown = "unscaled",
RadicalDegreeBottomRaisePercent = "unscaled"
}
function mathematics.scaleparameters(target,original)
if not target.properties.math_is_scaled then
local mathparameters = target.mathparameters
if mathparameters and next(mathparameters) then
local parameters = target.parameters
local factor = parameters.factor
local hfactor = parameters.hfactor
local vfactor = parameters.vfactor
for name, value in next, mathparameters do
local h = how[name]
if h == "unscaled" then
-- kept
elseif h == "horizontal" then
value = value * hfactor
elseif h == "vertical"then
value = value * vfactor
else
value = value * factor
end
mathparameters[name] = value
end
end
target.properties.math_is_scaled = true
end
end
sequencers.appendaction("mathparameters","system","mathematics.scaleparameters")
function mathematics.checkaccentbaseheight(target,original)
local mathparameters = target.mathparameters
if mathparameters and mathparameters.AccentBaseHeight == 0 then
mathparameters.AccentBaseHeight = target.parameters.x_height -- needs checking
end
end
sequencers.appendaction("mathparameters","system","mathematics.checkaccentbaseheight") -- should go in lfg instead
function mathematics.checkprivateparameters(target,original)
local mathparameters = target.mathparameters
if mathparameters then
local parameters = target.parameters
if parameters then
if not mathparameters.FractionDelimiterSize then
mathparameters.FractionDelimiterSize = 1.01 * parameters.size
end
if not mathparameters.FractionDelimiterDisplayStyleSize then
mathparameters.FractionDelimiterDisplayStyleSize = 2.40 * parameters.size
end
elseif target.properties then
report_math("no parameters in font %a",target.properties.fullname or "?")
else
report_math("no parameters and properties in font")
end
end
end
sequencers.appendaction("mathparameters","system","mathematics.checkprivateparameters")
function mathematics.overloadparameters(target,original)
local mathparameters = target.mathparameters
if mathparameters and next(mathparameters) then
local goodies = target.goodies
if goodies then
for i=1,#goodies do
local goodie = goodies[i]
local mathematics = goodie.mathematics
local parameters = mathematics and mathematics.parameters
if parameters then
if trace_defining then
report_math("overloading math parameters in %a @ %p",target.properties.fullname,target.parameters.size)
end
for name, value in next, parameters do
local tvalue = type(value)
if tvalue == "string" then
report_math("comment for math parameter %a: %s",name,value)
else
local oldvalue = mathparameters[name]
local newvalue = oldvalue
if oldvalue then
if tvalue == "number" then
newvalue = value
elseif tvalue == "function" then
newvalue = value(oldvalue,target,original)
elseif not tvalue then
newvalue = nil
end
if trace_defining and oldvalue ~= newvalue then
report_math("overloading math parameter %a: %S => %S",name,oldvalue,newvalue)
end
else
report_math("invalid math parameter %a",name)
end
mathparameters[name] = newvalue
end
end
end
end
end
end
end
sequencers.appendaction("mathparameters","system","mathematics.overloadparameters")
local function applytweaks(when,target,original)
local goodies = original.goodies
if goodies then
for i=1,#goodies do
local goodie = goodies[i]
local mathematics = goodie.mathematics
local tweaks = mathematics and mathematics.tweaks
if tweaks then
tweaks = tweaks[when]
if tweaks then
if trace_defining then
report_math("tweaking math of %a @ %p (%s)",target.properties.fullname,target.parameters.size,when)
end
for i=1,#tweaks do
local tweak= tweaks[i]
local tvalue = type(tweak)
if tvalue == "function" then
tweak(target,original)
end
end
end
end
end
end
end
function mathematics.tweakbeforecopyingfont(target,original)
local mathparameters = target.mathparameters -- why not hasmath
if mathparameters then
applytweaks("beforecopying",target,original)
end
end
function mathematics.tweakaftercopyingfont(target,original)
local mathparameters = target.mathparameters -- why not hasmath
if mathparameters then
applytweaks("aftercopying",target,original)
end
end
sequencers.appendaction("beforecopyingcharacters","system","mathematics.tweakbeforecopyingfont")
sequencers.appendaction("aftercopyingcharacters", "system","mathematics.tweakaftercopyingfont")
function mathematics.overloaddimensions(target,original,set)
local goodies = target.goodies
if goodies then
for i=1,#goodies do
local goodie = goodies[i]
local mathematics = goodie.mathematics
local dimensions = mathematics and mathematics.dimensions
if dimensions then
if trace_defining then
report_math("overloading dimensions in %a @ %p",target.properties.fullname,target.parameters.size)
end
local characters = target.characters
local parameters = target.parameters
local factor = parameters.factor
local hfactor = parameters.hfactor
local vfactor = parameters.vfactor
local addprivate = fonts.helpers.addprivate
local function overload(dimensions)
for unicode, data in next, dimensions do
local character = characters[unicode]
if character then
--
local width = data.width
local height = data.height
local depth = data.depth
if trace_defining and (width or height or depth) then
report_math("overloading dimensions of %C, width %a, height %a, depth %a",unicode,width,height,depth)
end
if width then character.width = width * hfactor end
if height then character.height = height * vfactor end
if depth then character.depth = depth * vfactor end
--
local xoffset = data.xoffset
local yoffset = data.yoffset
if xoffset then
xoffset = { "right", xoffset * hfactor }
end
if yoffset then
yoffset = { "down", -yoffset * vfactor }
end
if xoffset or yoffset then
local slot = { "slot", 1, addprivate(target,nil,fastcopy(character)) }
if xoffset and yoffset then
character.commands = { xoffset, yoffset, slot }
elseif xoffset then
character.commands = { xoffset, slot }
else
character.commands = { yoffset, slot }
end
character.index = nil
end
elseif trace_defining then
report_math("no overloading dimensions of %C, not in font",unicode)
end
end
end
if set == nil then
set = { "default" }
end
if set == "all" or set == true then
for name, set in next, dimensions do
overload(set)
end
else
if type(set) == "string" then
set = utilities.parsers.settings_to_array(set)
end
if type(set) == "table" then
for i=1,#set do
local d = dimensions[set[i]]
if d then
overload(d)
end
end
end
end
end
end
end
end
sequencers.appendaction("aftercopyingcharacters", "system","mathematics.overloaddimensions")
-- a couple of predefined tewaks:
local tweaks = { }
mathematics.tweaks = tweaks
function tweaks.fixbadprime(target,original)
target.characters[0xFE325] = target.characters[0x2032]
end
-- helpers
local setmetatableindex = table.setmetatableindex
local family_font = node.family_font
local fontcharacters = fonts.hashes.characters
local extensibles = utilities.storage.allocate()
fonts.hashes.extensibles = extensibles
local chardata = characters.data
local extensibles = mathematics.extensibles
-- we use numbers at the tex end (otherwise we could stick to chars)
local e_left = extensibles.left
local e_right = extensibles.right
local e_horizontal = extensibles.horizontal
local e_vertical = extensibles.vertical
local e_mixed = extensibles.mixed
local e_unknown = extensibles.unknown
local unknown = { e_unknown, false, false }
local function extensiblecode(font,unicode)
local characters = fontcharacters[font]
local character = characters[unicode]
if not character then
return unknown
end
local code = unicode
local next = character.next
while next do
code = next
character = characters[next]
next = character.next
end
local char = chardata[unicode]
local mathextensible = char and char.mathextensible
if character.horiz_variants then
if character.vert_variants then
return { e_mixed, code, character }
else
local e = mathextensible and extensibles[mathextensible]
return e and { e, code, character } or unknown
end
elseif character.vert_variants then
local e = mathextensible and extensibles[mathextensible]
return e and { e, code, character } or unknown
else
return unknown
end
end
setmetatableindex(extensibles,function(extensibles,font)
local codes = { }
setmetatableindex(codes, function(codes,unicode)
local status = extensiblecode(font,unicode)
codes[unicode] = status
return status
end)
extensibles[font] = codes
return codes
end)
function mathematics.extensiblecode(family,unicode)
return extensibles[family_font(family or 0)][unicode][1]
end
function commands.extensiblecode(family,unicode)
context(extensibles[family_font(family or 0)][unicode][1])
end
-- left : [head] ...
-- right : ... [head]
-- horizontal : [head] ... [head]
--
-- abs(right["start"] - right["end"]) | right.advance | characters[right.glyph].width
function commands.horizontalcode(family,unicode)
local font = family_font(family or 0)
local data = extensibles[font][unicode]
local kind = data[1]
if kind == e_left then
local charlist = data[3].horiz_variants
local characters = fontcharacters[font]
local left = charlist[1]
texdimen.scratchleftoffset = abs((left["start"] or 0) - (left["end"] or 0))
texdimen.scratchrightoffset = 0
elseif kind == e_right then
local charlist = data[3].horiz_variants
local characters = fontcharacters[font]
local right = charlist[#charlist]
texdimen.scratchleftoffset = 0
texdimen.scratchrightoffset = abs((right["start"] or 0) - (right["end"] or 0))
elseif kind == e_horizontal then
local charlist = data[3].horiz_variants
local characters = fontcharacters[font]
local left = charlist[1]
local right = charlist[#charlist]
texdimen.scratchleftoffset = abs((left["start"] or 0) - (left["end"] or 0))
texdimen.scratchrightoffset = abs((right["start"] or 0) - (right["end"] or 0))
else
texdimen.scratchleftoffset = 0
texdimen.scratchrightoffset = 0
end
context(kind)
end
|