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