1if not modules then modules = { } end modules ['math-vfu'] = {
2 version = 1.001,
3 comment = "companion to math-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
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25local type, next, tonumber = type, next, tonumber
26local max = math.max
27local fastcopy = table.copy
28
29local fonts, nodes, mathematics = fonts, nodes, mathematics
30
31local trace_virtual = false trackers.register("math.virtual", function(v) trace_virtual = v end)
32local trace_timings = false trackers.register("math.timings", function(v) trace_timings = v end)
33
34local add_optional = false directives.register("math.virtual.optional",function(v) add_optional = v end)
35
36local report_virtual = logs.reporter("fonts","virtual math")
37
38local allocate = utilities.storage.allocate
39local setmetatableindex = table.setmetatableindex
40local formatters = string.formatters
41
42local chardata = characters.data
43
44local mathencodings = allocate()
45fonts.encodings.math = mathencodings
46local vfmath = allocate()
47fonts.handlers.vf.math = vfmath
48
49local helpers = fonts.helpers
50local vfcommands = helpers.commands
51local rightcommand = vfcommands.right
52local leftcommand = vfcommands.left
53local downcommand = vfcommands.down
54local upcommand = vfcommands.up
55local push = vfcommands.push
56local pop = vfcommands.pop
57
58local shared = { }
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
91local function brace(main,characters,id,size,unicode,first,rule,left,right,rule,last)
92 if not characters[unicode] then
93 characters[unicode] = {
94 horiz_variants = {
95 { extender = 0, glyph = first },
96 { extender = 1, glyph = rule },
97 { extender = 0, glyph = left },
98 { extender = 0, glyph = right },
99 { extender = 1, glyph = rule },
100 { extender = 0, glyph = last },
101 }
102 }
103 end
104end
105
106local function extension(main,characters,id,size,unicode,first,middle,last)
107 local chr = characters[unicode]
108 if not chr then
109 return
110 end
111 local fw = characters[first]
112 if not fw then
113 return
114 end
115 local mw = characters[middle]
116 if not mw then
117 return
118 end
119 local lw = characters[last]
120 if not lw then
121 return
122 end
123 fw = fw.width
124 mw = mw.width
125 lw = lw.width
126 if fw == 0 then
127 fw = 1
128 end
129 if lw == 0 then
130 lw = 1
131 end
132 chr.horiz_variants = {
133 { extender = 0, glyph = first, ["end"] = fw/2, start = 0, advance = fw },
134 { extender = 1, glyph = middle, ["end"] = mw/2, start = mw/2, advance = mw },
135 { extender = 0, glyph = last, ["end"] = 0, start = lw/2, advance = lw },
136 }
137end
138
139local function parent(main,characters,id,size,unicode,first,rule,last)
140 if not characters[unicode] then
141 characters[unicode] = {
142 horiz_variants = {
143 { extender = 0, glyph = first },
144 { extender = 1, glyph = rule },
145 { extender = 0, glyph = last },
146 }
147 }
148 end
149end
150
151local step = 0.2
152
153local function make(main,characters,id,size,n,m)
154 local old = 0xFF000 + n
155 local c = characters[old]
156 if c then
157 local upslot = 0xFF100 + n
158 local dnslot = 0xFF200 + n
159 local uprule = 0xFF300 + m
160 local dnrule = 0xFF400 + m
161 local xu = main.parameters.x_height + 0.3*size
162 local xd = 0.3*size
163 local w = c.width or 0
164 local h = c.height or 0
165 local d = c.depth or 0
166 local thickness = h - d
167 local rulewidth = step*size
168 local slot = { "slot", id, old }
169 local rule = { "rule", thickness, rulewidth }
170 local up = upcommand[xu]
171 local dn = downcommand[xd]
172 local ht = xu + 3*thickness
173 local dp = 0
174 if not characters[uprule] then
175 characters[uprule] = {
176 width = rulewidth,
177 height = ht,
178 depth = dp,
179 commands = { push, up, rule, pop },
180 }
181 end
182 characters[upslot] = {
183 width = w,
184 height = ht,
185 depth = dp,
186 commands = { push, up, slot, pop },
187 }
188 local ht = 0
189 local dp = xd + 3*thickness
190 if not characters[dnrule] then
191 characters[dnrule] = {
192 width = rulewidth,
193 height = ht,
194 depth = dp,
195 commands = { push, dn, rule, pop }
196 }
197 end
198 characters[dnslot] = {
199 width = w,
200 height = ht,
201 depth = dp,
202 commands = { push, dn, slot, pop },
203 }
204 end
205end
206
207local function clipped(main,characters,id,size,unicode,original)
208 local minus = characters[original]
209 if minus then
210 local mu = size/18
211 local step = 3*mu
212 local width = minus.width
213 if width > step then
214 width = width - step
215 step = step / 2
216 else
217 width = width / 2
218 step = width
219 end
220 characters[unicode] = {
221 width = width,
222 height = minus.height,
223 depth = minus.depth,
224 commands = {
225 push,
226 leftcommand[step],
227 { "slot", id, original },
228 pop,
229 }
230 }
231 end
232end
233
234local function raise(main,characters,id,size,unicode,private,n,id_of_smaller)
235 local raised = fonts.hashes.characters[main.fonts[id_of_smaller].id][private]
236 if raised then
237 local up = 0.85 * main.parameters.x_height
238 local slot = { "slot", id_of_smaller, private }
239 local commands = {
240 push, upcommand[up], slot,
241 }
242 for i=2,n do
243 commands[#commands+1] = slot
244 end
245 commands[#commands+1] = pop
246 characters[unicode] = {
247 width = n * raised.width,
248 height = (raised.height or 0) + up,
249 depth = (raised.depth or 0) - up,
250 italic = raised.italic,
251 commands = commands,
252 }
253 end
254end
255
256local function dots(main,characters,id,size,unicode)
257 local c = characters[0x002E]
258 if c then
259 local w = c.width
260 local h = c.height
261 local d = c.depth
262 local mu = size/18
263 local right3mu = rightcommand[3*mu]
264 local right1mu = rightcommand[1*mu]
265 local up1size = upcommand[.1*size]
266 local up4size = upcommand[.4*size]
267 local up7size = upcommand[.7*size]
268 local right2muw = rightcommand[2*mu + w]
269 local slot = { "slot", id, 0x002E }
270 if unicode == 0x22EF then
271 local c = characters[0x022C5]
272 if c then
273 local width = c.width
274 local height = c.height
275 local depth = c.depth
276 local slot = { "slot", id, 0x022C5 }
277 characters[unicode] = {
278 width = 3*width + 2*3*mu,
279 height = height,
280 depth = depth,
281 commands = {
282 push, slot, right3mu, slot, right3mu, slot, pop,
283 }
284 }
285 end
286 elseif unicode == 0x22EE then
287 characters[unicode] = {
288 width = w,
289 height = h+0.8*size,
290 depth = 0,
291 commands = {
292 push, push, slot, pop, up4size, push, slot, pop, up4size, slot, pop,
293 }
294 }
295 elseif unicode == 0x22F1 then
296 characters[unicode] = {
297 width = 3*w + 6*size/18,
298 height = 0.7*size,
299 depth = 0,
300 commands = {
301 push,
302 right1mu,
303 push, up7size, slot, pop,
304 right2muw,
305 push, up4size, slot, pop,
306 right2muw,
307 push, up1size, slot, pop,
308 right1mu,
309 pop
310 }
311 }
312 elseif unicode == 0x22F0 then
313 characters[unicode] = {
314 width = 3*w + 6*size/18,
315 height = 0.7*size,
316 depth = 0,
317 commands = {
318 push,
319 right1mu,
320 push, up1size, slot, pop,
321 right2muw,
322 push, up4size, slot, pop,
323 right2muw,
324 push, up7size, slot, pop,
325 right1mu,
326 pop
327 }
328 }
329 else
330 characters[unicode] = {
331 width = 3*w + 2*3*mu,
332 height = h,
333 depth = d,
334 commands = {
335 push, slot, right3mu, slot, right3mu, slot, pop,
336 }
337 }
338 end
339 end
340end
341
342local function vertbar(main,characters,id,size,parent,scale,unicode)
343 local cp = characters[parent]
344 if cp then
345 local sc = scale * size
346 local pc = { "slot", id, parent }
347 characters[unicode] = {
348 width = cp.width,
349 height = cp.height + sc,
350 depth = cp.depth + sc,
351 next = cp.next,
352 commands = {
353 push, upcommand [sc], pc, pop,
354 push, downcommand[sc], pc, pop,
355 pc,
356 },
357 }
358 cp.next = unicode
359 end
360end
361
362local function jointwo(main,characters,id,size,unicode,u1,d12,u2,what)
363 local c1 = characters[u1]
364 local c2 = characters[u2]
365 if c1 and c2 then
366 local w1 = c1.width
367 local w2 = c2.width
368 local mu = size/18
369 characters[unicode] = {
370 width = w1 + w2 - d12 * mu,
371 height = max(c1.height or 0, c2.height or 0),
372 depth = max(c1.depth or 0, c2.depth or 0),
373 commands = {
374 { "slot", id, u1 },
375 leftcommand[d12*mu],
376 { "slot", id, u2 },
377 },
378 }
379 end
380end
381
382local function jointhree(main,characters,id,size,unicode,u1,d12,u2,d23,u3)
383 local c1 = characters[u1]
384 local c2 = characters[u2]
385 local c3 = characters[u3]
386 if c1 and c2 and c3 then
387 local w1 = c1.width
388 local w2 = c2.width
389 local w3 = c3.width
390 local mu = size/18
391 characters[unicode] = {
392 width = w1 + w2 + w3 - d12*mu - d23*mu,
393 height = max(c1.height or 0, c2.height or 0, c3.height or 0),
394 depth = max(c1.depth or 0, c2.depth or 0, c3.depth or 0),
395 commands = {
396 { "slot", id, u1 },
397 leftcommand[d12*mu],
398 { "slot", id, u2 },
399 leftcommand[d23*mu],
400 { "slot", id, u3 },
401 }
402 }
403 end
404end
405
406local function stack(main,characters,id,size,unicode,u1,d12,u2)
407 local c1 = characters[u1]
408 if not c1 then
409 return
410 end
411 local c2 = characters[u2]
412 if not c2 then
413 return
414 end
415 local w1 = c1.width or 0
416 local h1 = c1.height or 0
417 local d1 = c1.depth or 0
418 local w2 = c2.width or 0
419 local h2 = c2.height or 0
420 local d2 = c2.depth or 0
421 local mu = size/18
422 characters[unicode] = {
423 width = w1,
424 height = h1 + h2 + d12*mu,
425 depth = d1,
426 commands = {
427 { "slot", id, u1 },
428 leftcommand[w1/2 + w2/2],
429 downcommand[-h1 + d2 -d12*mu],
430 { "slot", id, u2 },
431 }
432 }
433end
434
435local function repeated(main,characters,id,size,unicode,u,n,private,fraction)
436 local c = characters[u]
437 if c then
438 local width = c.width
439 local italic = fraction*width
440 local tc = { "slot", id, u }
441 local tr = leftcommand[italic]
442 local commands = { }
443 for i=1,n-1 do
444 commands[#commands+1] = tc
445 commands[#commands+1] = tr
446 end
447 commands[#commands+1] = tc
448 local next = c.next
449 if next then
450 repeated(main,characters,id,size,private,next,n,private+1,fraction)
451 next = private
452 end
453 characters[unicode] = {
454 width = width + (n-1)*(width-italic),
455 height = c.height,
456 depth = c.depth,
457 italic = italic,
458 commands = commands,
459 next = next,
460 }
461 end
462end
463
464local function cloned(main,characters,id,size,source,target)
465 local data = characters[source]
466 if data then
467 characters[target] = data
468 return true
469 end
470end
471
472
473
474local data_of_smaller = nil
475local size_of_smaller = 0
476
477function vfmath.addmissing(main,id,size)
478
479 local id_of_smaller = nil
480
481 if size < size_of_smaller or size_of_smaller == 0 then
482 data_of_smaller = main.fonts[id]
483 id_of_smaller = id
484 else
485 id_of_smaller = #main.fonts + 1
486 main.fonts[id_of_smaller] = data_of_smaller
487 end
488
489
490
491 local characters = main.characters
492 local shared = main.shared
493 local variables = main.goodies.mathematics and main.goodies.mathematics.variables or { }
494 local joinrelfactor = variables.joinrelfactor or 3
495
496 for i=0x7A,0x7D do
497 make(main,characters,id,size,i,1)
498 end
499
500 brace (main,characters,id,size,0x23DE,0xFF17A,0xFF301,0xFF17D,0xFF17C,0xFF301,0xFF17B)
501 brace (main,characters,id,size,0x23DF,0xFF27C,0xFF401,0xFF27B,0xFF27A,0xFF401,0xFF27D)
502
503 parent (main,characters,id,size,0x23DC,0xFF17A,0xFF301,0xFF17B)
504 parent (main,characters,id,size,0x23DD,0xFF27C,0xFF401,0xFF27D)
505
506
507 dots (main,characters,id,size,0x2026)
508 dots (main,characters,id,size,0x22EE)
509 dots (main,characters,id,size,0x22EF)
510 dots (main,characters,id,size,0x22F1)
511 dots (main,characters,id,size,0x22F0)
512
513 vertbar (main,characters,id,size,0x0007C,0.10,0xFF601)
514 vertbar (main,characters,id,size,0xFF601,0.30,0xFF602)
515 vertbar (main,characters,id,size,0xFF602,0.30,0xFF603)
516 vertbar (main,characters,id,size,0xFF603,0.30,0xFF604)
517 vertbar (main,characters,id,size,0x02016,0.10,0xFF605)
518 vertbar (main,characters,id,size,0xFF605,0.30,0xFF606)
519 vertbar (main,characters,id,size,0xFF606,0.30,0xFF607)
520 vertbar (main,characters,id,size,0xFF607,0.30,0xFF608)
521
522 clipped (main,characters,id,size,0xFF501,0x0002D)
523 clipped (main,characters,id,size,0xFF502,0x02190)
524 clipped (main,characters,id,size,0xFF503,0x02192)
525 clipped (main,characters,id,size,0xFF504,0xFE321)
526 clipped (main,characters,id,size,0xFF505,0xFE322)
527 clipped (main,characters,id,size,0xFF506,0xFE323)
528 clipped (main,characters,id,size,0xFF507,0xFE324)
529 clipped (main,characters,id,size,0xFF508,0x021D0)
530 clipped (main,characters,id,size,0xFF509,0x021D2)
531 clipped (main,characters,id,size,0xFF50A,0x0003D)
532 clipped (main,characters,id,size,0xFF50B,0x0219E)
533 clipped (main,characters,id,size,0xFF50C,0x021A0)
534 clipped (main,characters,id,size,0xFF50D,0xFF350)
535 clipped (main,characters,id,size,0xFF50E,0xFF351)
536 clipped (main,characters,id,size,0xFF50F,0xFF352)
537 clipped (main,characters,id,size,0xFF510,0x02261)
538
539 extension(main,characters,id,size,0x2190,0xFF502,0xFF501,0xFF501)
540 extension(main,characters,id,size,0x2192,0xFF501,0xFF501,0xFF503)
541
542 extension(main,characters,id,size,0x002D,0xFF501,0xFF501,0xFF501)
543 extension(main,characters,id,size,0x003D,0xFF50A,0xFF50A,0xFF50A)
544 extension(main,characters,id,size,0x2261,0xFF510,0xFF510,0xFF510)
545
546 jointwo (main,characters,id,size,0x21A6,0xFE321,0,0x02192)
547 jointwo (main,characters,id,size,0x21A9,0x02190,joinrelfactor,0xFE323)
548 jointwo (main,characters,id,size,0x21AA,0xFE322,joinrelfactor,0x02192)
549 jointwo (main,characters,id,size,0x27F5,0x02190,joinrelfactor,0x0002D)
550 jointwo (main,characters,id,size,0x27F6,0x0002D,joinrelfactor,0x02192,2)
551 jointwo (main,characters,id,size,0x27F7,0x02190,joinrelfactor,0x02192)
552 jointwo (main,characters,id,size,0x27F8,0x021D0,joinrelfactor,0x0003D)
553 jointwo (main,characters,id,size,0x27F9,0x0003D,joinrelfactor,0x021D2)
554 jointwo (main,characters,id,size,0x27FA,0x021D0,joinrelfactor,0x021D2)
555 jointhree(main,characters,id,size,0x27FB,0x02190,joinrelfactor,0x0002D,0,0xFE324)
556 jointhree(main,characters,id,size,0x27FC,0xFE321,0,0x0002D,joinrelfactor,0x02192)
557
558 extension(main,characters,id,size,0x21A6,0xFF504,0xFF501,0xFF503)
559 extension(main,characters,id,size,0x21A9,0xFF502,0xFF501,0xFF506)
560 extension(main,characters,id,size,0x21AA,0xFF505,0xFF501,0xFF503)
561 extension(main,characters,id,size,0x27F5,0xFF502,0xFF501,0xFF501)
562 extension(main,characters,id,size,0x27F6,0xFF501,0xFF501,0xFF503)
563 extension(main,characters,id,size,0x27F7,0xFF502,0xFF501,0xFF503)
564 extension(main,characters,id,size,0x27F8,0xFF508,0xFF50A,0xFF50A)
565 extension(main,characters,id,size,0x27F9,0xFF50A,0xFF50A,0xFF509)
566 extension(main,characters,id,size,0x27FA,0xFF508,0xFF50A,0xFF509)
567 extension(main,characters,id,size,0x27FB,0xFF502,0xFF501,0xFF507)
568 extension(main,characters,id,size,0x27FC,0xFF504,0xFF501,0xFF503)
569
570 extension(main,characters,id,size,0x219E,0xFF50B,0xFF501,0xFF501)
571 extension(main,characters,id,size,0x21A0,0xFF501,0xFF501,0xFF50C)
572 extension(main,characters,id,size,0x21C4,0xFF50D,0xFF50E,0xFF50F)
573
574
575
576
577 stack(main,characters,id,size,0x2259,0x0003D,3,0x02227)
578
579 jointwo(main,characters,id,size,0x22C8,0x022B3,joinrelfactor,0x022B2)
580 jointwo(main,characters,id,size,0x22A7,0x0007C,joinrelfactor,0x0003D)
581 jointwo(main,characters,id,size,0x2260,0x00338,0,0x0003D)
582 jointwo(main,characters,id,size,0x2284,0x00338,0,0x02282)
583 jointwo(main,characters,id,size,0x2285,0x00338,0,0x02283)
584 jointwo(main,characters,id,size,0x2209,0x00338,0,0x02208)
585 jointwo(main,characters,id,size,0x2254,0x03A,0,0x03D)
586
587 repeated(main,characters,id,size,0x222C,0x222B,2,0xFF800,1/3)
588 repeated(main,characters,id,size,0x222D,0x222B,3,0xFF810,1/3)
589
590 if cloned(main,characters,id,size,0x2032,0xFE325) then
591 raise(main,characters,id,size,0x2032,0xFE325,1,id_of_smaller)
592 raise(main,characters,id,size,0x2033,0xFE325,2,id_of_smaller)
593 raise(main,characters,id,size,0x2034,0xFE325,3,id_of_smaller)
594
595 characters[0xFE932] = characters[0x2032]
596 characters[0xFE933] = characters[0x2033]
597 characters[0xFE934] = characters[0x2034]
598 end
599
600
601
602
603
604
605 characters[0x02B9] = characters[0x2032]
606
607 data_of_smaller = main.fonts[id]
608 size_of_smaller = size
609
610end
611
612local unique = 0
613
614local reported = { }
615local reverse = { }
616
617setmetatableindex(reverse, function(t,name)
618 if trace_virtual then
619 report_virtual("initializing math vector %a",name)
620 end
621 local m = mathencodings[name]
622 local r = { }
623 if type(m) == "table" then
624 for u, i in next, m do
625 r[i] = u
626 end
627 end
628 reverse[name] = r
629 return r
630end)
631
632local function copy_glyph(main,target,original,unicode,slot)
633 local addprivate = fonts.helpers.addprivate
634 local olddata = original[unicode]
635 if olddata then
636 local newdata = {
637 width = olddata.width,
638 height = olddata.height,
639 depth = olddata.depth,
640 italic = olddata.italic,
641 kerns = olddata.kerns,
642 tounicode = olddata.tounicode,
643 commands = { { "slot", slot, unicode } },
644 }
645 local glyphdata = newdata
646 local nextglyph = olddata.next
647 while nextglyph do
648 local oldnextdata = original[nextglyph]
649 local newnextdata = {
650 width = oldnextdata.width,
651 height = oldnextdata.height,
652 depth = oldnextdata.depth,
653 tounicode = olddata.tounicode,
654 commands = { { "slot", slot, nextglyph } },
655 }
656 local newnextglyph = addprivate(main,formatters["M-N-%H"](nextglyph),newnextdata)
657 newdata.next = newnextglyph
658 local nextnextglyph = oldnextdata.next
659 if nextnextglyph == nextglyph then
660 break
661 else
662 olddata = oldnextdata
663 newdata = newnextdata
664 nextglyph = nextnextglyph
665 end
666 end
667 local hv = olddata.horiz_variants
668 if hv then
669 hv = fastcopy(hv)
670 newdata.horiz_variants = hv
671 for i=1,#hv do
672 local hvi = hv[i]
673 local oldglyph = hvi.glyph
674 local olddata = original[oldglyph]
675 local newdata = {
676 width = olddata.width,
677 height = olddata.height,
678 depth = olddata.depth,
679 tounicode = olddata.tounicode,
680 commands = { { "slot", slot, oldglyph } },
681 }
682 hvi.glyph = addprivate(main,formatters["M-H-%H"](oldglyph),newdata)
683 end
684 end
685 local vv = olddata.vert_variants
686 if vv then
687 vv = fastcopy(vv)
688 newdata.vert_variants = vv
689 for i=1,#vv do
690 local vvi = vv[i]
691 local oldglyph = vvi.glyph
692 local olddata = original[oldglyph]
693 local newdata = {
694 width = olddata.width,
695 height = olddata.height,
696 depth = olddata.depth,
697 tounicode = olddata.tounicode,
698 commands = { { "slot", slot, oldglyph } },
699 }
700 vvi.glyph = addprivate(main,formatters["M-V-%H"](oldglyph),newdata)
701 end
702 end
703 return glyphdata
704 end
705end
706
707vfmath.copy_glyph = copy_glyph
708
709function vfmath.define(specification,set,goodies)
710 local name = specification.name
711 local size = specification.size
712 local loaded = { }
713 local fontlist = { }
714 local names = { }
715 local main = nil
716 local start = (trace_virtual or trace_timings) and os.clock()
717 local okset = { }
718 local n = 0
719 local setlist = set.recipe or set
720 for s=1,#setlist do
721 local ss = setlist[s]
722 local ssname = ss.name
723 if add_optional and ss.optional then
724 if trace_virtual then
725 report_virtual("loading font %a subfont %s with name %a at %p is skipped",name,s,ssname,size)
726 end
727 else
728 if ss.features then
729 ssname = ssname .. "*" .. ss.features
730 end
731 if ss.main then
732 main = s
733 end
734 local alreadyloaded = names[ssname]
735 local f, id
736 if alreadyloaded then
737 f, id = alreadyloaded.f, alreadyloaded.id
738 if trace_virtual then
739 report_virtual("loading font %a subfont %s with name %a is reused",name,s,ssname)
740 end
741 else
742 f, id = fonts.constructors.readanddefine(ssname,size)
743 names[ssname] = { f = f, id = id }
744 end
745 if not f or id == 0 then
746 report_virtual("loading font %a subfont %s with name %a at %p is skipped, not found",name,s,ssname,size)
747 else
748 n = n + 1
749 okset[n] = ss
750 loaded[n] = f
751 fontlist[n] = { id = id, size = size }
752 if not shared[s] then
753 shared[n] = { }
754 end
755 if trace_virtual then
756 report_virtual("loading font %a subfont %s with name %a at %p as id %s using encoding %a",name,s,ssname,size,id,ss.vector)
757 end
758 if not ss.checked then
759 ss.checked = true
760 local vector = mathencodings[ss.vector]
761 if vector then
762
763
764
765 for unicode, index in next, vector do
766 if not tonumber(index) then
767 local u = f.unicodes
768 u = u and u[index]
769 if u then
770 if trace_virtual then
771 report_virtual("resolving name %a to %s",index,u)
772 end
773 else
774 report_virtual("unable to resolve name %a",index)
775 end
776 vector[unicode] = u
777 end
778 end
779 end
780 end
781 end
782 end
783 end
784
785 local parent = loaded[1] or { }
786 local characters = { }
787 local parameters = { }
788 local mathparameters = { }
789 local descriptions = { }
790 local metadata = { }
791 local properties = { }
792 local goodies = { }
793 local main = {
794 metadata = metadata,
795 properties = properties,
796 characters = characters,
797 descriptions = descriptions,
798 parameters = parameters,
799 mathparameters = mathparameters,
800 fonts = fontlist,
801 goodies = goodies,
802 }
803
804
805 for key, value in next, parent do
806 if type(value) ~= "table" then
807 main[key] = value
808 end
809 end
810
811 if parent.characters then
812 for unicode, character in next, parent.characters do
813 characters[unicode] = character
814 end
815 else
816 report_virtual("font %a has no characters",name)
817 end
818
819 if parent.parameters then
820 for key, value in next, parent.parameters do
821 parameters[key] = value
822 end
823 else
824 report_virtual("font %a has no parameters",name)
825 end
826
827 local description = { name = "<unset>" }
828 setmetatableindex(descriptions,function() return description end)
829
830 if parent.properties then
831 setmetatableindex(properties,parent.properties)
832 end
833
834 if parent.goodies then
835 setmetatableindex(goodies,parent.goodies)
836 end
837
838 properties.hasitalics = true
839 properties.hasmath = true
840
841 local fullname = properties.fullname
842 if fullname then
843 unique = unique + 1
844 properties.fullname = fullname .. "-" .. unique
845 end
846
847
848
849 main.fullname = properties.fullname
850 main.nomath = false
851
852 properties.virtualized = true
853 main.type = "virtual"
854
855 parameters.x_height = parameters.x_height or 0
856
857 local already_reported = false
858 local parameters_done = false
859 for s=1,n do
860 local ss, fs = okset[s], loaded[s]
861 if not fs then
862
863 elseif add_optional and ss.optional then
864
865 else
866 local newparameters = fs.parameters
867 local newmathparameters = fs.mathparameters
868 if newmathparameters then
869 if not parameters_done or ss.parameters then
870 mathparameters = newmathparameters
871 parameters_done = true
872 end
873 elseif not newparameters then
874 report_virtual("no parameters set in font %a",name)
875 elseif ss.extension then
876 mathparameters.math_x_height = newparameters.x_height or 0
877 mathparameters.default_rule_thickness = newparameters[ 8] or 0
878 mathparameters.big_op_spacing1 = newparameters[ 9] or 0
879 mathparameters.big_op_spacing2 = newparameters[10] or 0
880 mathparameters.big_op_spacing3 = newparameters[11] or 0
881 mathparameters.big_op_spacing4 = newparameters[12] or 0
882 mathparameters.big_op_spacing5 = newparameters[13] or 0
883
884 elseif ss.parameters then
885 mathparameters.x_height = newparameters.x_height or mathparameters.x_height
886 mathparameters.x_height = mathparameters.x_height or fp.x_height or 0
887 mathparameters.num1 = newparameters[ 8] or 0
888 mathparameters.num2 = newparameters[ 9] or 0
889 mathparameters.num3 = newparameters[10] or 0
890 mathparameters.denom1 = newparameters[11] or 0
891 mathparameters.denom2 = newparameters[12] or 0
892 mathparameters.sup1 = newparameters[13] or 0
893 mathparameters.sup2 = newparameters[14] or 0
894 mathparameters.sup3 = newparameters[15] or 0
895 mathparameters.sub1 = newparameters[16] or 0
896 mathparameters.sub2 = newparameters[17] or 0
897 mathparameters.sup_drop = newparameters[18] or 0
898 mathparameters.sub_drop = newparameters[19] or 0
899 mathparameters.delim1 = newparameters[20] or 0
900 mathparameters.delim2 = newparameters[21] or 0
901 mathparameters.axis_height = newparameters[22] or 0
902
903 end
904 if ss.overlay then
905 local fc = fs.characters
906 local first = ss.first
907 if first then
908 local last = ss.last or first
909 for unicode = first, last do
910 characters[unicode] = copy_glyph(main,characters,fc,unicode,s)
911 end
912 else
913 for unicode, data in next, fc do
914 characters[unicode] = copy_glyph(main,characters,fc,unicode,s)
915 end
916 end
917 else
918 local vectorname = ss.vector
919 if vectorname then
920 local offset = 0xFF000
921 local vector = mathencodings[vectorname]
922 local rotcev = reverse[vectorname]
923 local isextension = ss.extension
924 if vector and rotcev then
925 local fc = fs.characters
926 local fd = fs.descriptions
927 local si = shared[s]
928 local fontname = fs.properties.name or "unknown"
929 local skewchar = ss.skewchar
930 for unicode, index in next, vector do
931 local fci = fc[index]
932 if not fci then
933 local rf = reported[fontname]
934 if not rf then rf = { } reported[fontname] = rf end
935 local rv = rf[vectorname]
936 if not rv then rv = { } rf[vectorname] = rv end
937 local ru = rv[unicode]
938 if not ru then
939 if trace_virtual then
940 report_virtual("unicode slot %U has no index %H in vector %a for font %a (%S)",unicode,index,vectorname,fontname,chardata[unicode].description)
941 elseif not already_reported then
942 report_virtual("the mapping is incomplete for %a at %p",name,size)
943 already_reported = true
944 end
945 rv[unicode] = true
946 end
947 else
948 local ref = si[index]
949 if not ref then
950 ref = { { 'slot', s, index } }
951 si[index] = ref
952 end
953 local kerns = fci.kerns
954 local width = fci.width
955 local italic = fci.italic
956 if italic and italic > 0 then
957
958 if isextension then
959 width = width + italic
960 end
961 end
962 if kerns then
963 local krn = { }
964 for k, v in next, kerns do
965 local rk = rotcev[k]
966 if rk then
967 krn[rk] = v
968 end
969 end
970 if not next(krn) then
971 krn = nil
972 end
973 local t = {
974 width = width,
975 height = fci.height,
976 depth = fci.depth,
977 italic = italic,
978 kerns = krn,
979 commands = ref,
980 }
981 if skewchar then
982 local k = kerns[skewchar]
983 if k then
984 t.top_accent = width/2 + k
985 end
986 end
987 characters[unicode] = t
988 else
989 characters[unicode] = {
990 width = width,
991 height = fci.height,
992 depth = fci.depth,
993 italic = italic,
994 commands = ref,
995 }
996 end
997 end
998 end
999 if isextension then
1000
1001 local extension = mathencodings["large-to-small"]
1002 local variants_done = fs.variants_done
1003 for index, fci in next, fc do
1004 if type(index) == "number" then
1005 local ref = si[index]
1006 if not ref then
1007 ref = { { 'slot', s, index } }
1008 si[index] = ref
1009 end
1010 local italic = fci.italic
1011 local t = {
1012 width = fci.width,
1013 height = fci.height,
1014 depth = fci.depth,
1015 italic = italic,
1016 commands = ref,
1017 }
1018 local n = fci.next
1019 if n then
1020 t.next = offset + n
1021 elseif variants_done then
1022 local vv = fci.vert_variants
1023 if vv then
1024 t.vert_variants = vv
1025 end
1026 local hv = fci.horiz_variants
1027 if hv then
1028 t.horiz_variants = hv
1029 end
1030 else
1031 local vv = fci.vert_variants
1032 if vv then
1033 for i=1,#vv do
1034 local vvi = vv[i]
1035 vvi.glyph = vvi.glyph + offset
1036 end
1037 t.vert_variants = vv
1038 end
1039 local hv = fci.horiz_variants
1040 if hv then
1041 for i=1,#hv do
1042 local hvi = hv[i]
1043 hvi.glyph = hvi.glyph + offset
1044 end
1045 t.horiz_variants = hv
1046 end
1047 end
1048 characters[offset + index] = t
1049 end
1050 end
1051 fs.variants_done = true
1052 for unicode, index in next, extension do
1053 local cu = characters[unicode]
1054 if cu then
1055 cu.next = offset + index
1056 else
1057 local fci = fc[index]
1058 if not fci then
1059
1060 else
1061
1062 local ref = si[index]
1063 if not ref then
1064 ref = { { 'slot', s, index } }
1065 si[index] = ref
1066 end
1067 local kerns = fci.kerns
1068 if kerns then
1069 local krn = { }
1070
1071
1072
1073 for k, v in next, kerns do
1074 krn[offset + k] = v
1075 end
1076 characters[unicode] = {
1077 width = fci.width,
1078 height = fci.height,
1079 depth = fci.depth,
1080 italic = fci.italic,
1081 commands = ref,
1082 kerns = krn,
1083 next = offset + index,
1084 }
1085 else
1086 characters[unicode] = {
1087 width = fci.width,
1088 height = fci.height,
1089 depth = fci.depth,
1090 italic = fci.italic,
1091 commands = ref,
1092 next = offset + index,
1093 }
1094 end
1095 end
1096 end
1097 end
1098 end
1099 else
1100 report_virtual("error in loading %a, problematic vector %a",name,vectorname)
1101 end
1102 end
1103 end
1104 mathematics.extras.copy(main)
1105 end
1106 end
1107
1108 main.mathparameters = mathparameters
1109
1110
1111
1112 fontlist[#fontlist+1] = {
1113
1114 id = 0,
1115 size = size,
1116 }
1117 vfmath.addmissing(main,#fontlist,size)
1118
1119 mathematics.addfallbacks(main)
1120
1121 main.properties.math_is_scaled = true
1122 fonts.constructors.assignmathparameters(main,main)
1123
1124 main.MathConstants = main.mathparameters
1125
1126 if trace_virtual or trace_timings then
1127 report_virtual("loading and virtualizing font %a at size %p took %0.3f seconds",name,size,os.clock()-start)
1128 end
1129
1130 main.oldmath = true
1131 return main
1132end
1133
1134function mathematics.makefont(name,set,goodies)
1135 fonts.definers.methods.variants[name] = function(specification)
1136 return vfmath.define(specification,set,goodies)
1137 end
1138end
1139
1140
1141
1142function vfmath.setletters(font_encoding, name, uppercase, lowercase)
1143 local enc = font_encoding[name]
1144 for i = 0,25 do
1145 enc[uppercase+i] = i + 0x41
1146 enc[lowercase+i] = i + 0x61
1147 end
1148end
1149
1150function vfmath.setdigits(font_encoding, name, digits)
1151 local enc = font_encoding[name]
1152 for i = 0,9 do
1153 enc[digits+i] = i + 0x30
1154 end
1155end
1156 |