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
288 characters[unicode] = {
289 width = w,
290 height = h+(1.4)*size,
291 depth = 0,
292 commands = {
293 push, push, slot, pop, up4size, push, slot, pop, up4size, slot, pop,
294 }
295 }
296 elseif unicode == 0x22F1 then
297 characters[unicode] = {
298 width = 3*w + 6*size/18,
299 height = 1.5*size,
300 depth = 0,
301 commands = {
302 push,
303 right1mu,
304 push, up7size, slot, pop,
305 right2muw,
306 push, up4size, slot, pop,
307 right2muw,
308 push, up1size, slot, pop,
309 right1mu,
310 pop
311 }
312 }
313 elseif unicode == 0x22F0 then
314 characters[unicode] = {
315 width = 3*w + 6*size/18,
316 height = 1.5*size,
317 depth = 0,
318 commands = {
319 push,
320 right1mu,
321 push, up1size, slot, pop,
322 right2muw,
323 push, up4size, slot, pop,
324 right2muw,
325 push, up7size, slot, pop,
326 right1mu,
327 pop
328 }
329 }
330 else
331 characters[unicode] = {
332 width = 3*w + 2*3*mu,
333 height = h,
334 depth = d,
335 commands = {
336 push, slot, right3mu, slot, right3mu, slot, pop,
337 }
338 }
339 end
340 end
341end
342
343local function vertbar(main,characters,id,size,parent,scale,unicode)
344 local cp = characters[parent]
345 if cp then
346 local sc = scale * size
347 local pc = { "slot", id, parent }
348 characters[unicode] = {
349 width = cp.width,
350 height = cp.height + sc,
351 depth = cp.depth + sc,
352 next = cp.next,
353 commands = {
354 push, upcommand [sc], pc, pop,
355 push, downcommand[sc], pc, pop,
356 pc,
357 },
358 }
359 cp.next = unicode
360 end
361end
362
363local function jointwo(main,characters,id,size,unicode,u1,d12,u2,what)
364 local c1 = characters[u1]
365 local c2 = characters[u2]
366 if c1 and c2 then
367 local w1 = c1.width
368 local w2 = c2.width
369 local mu = size/18
370 characters[unicode] = {
371 width = w1 + w2 - d12 * mu,
372 height = max(c1.height or 0, c2.height or 0),
373 depth = max(c1.depth or 0, c2.depth or 0),
374 commands = {
375 { "slot", id, u1 },
376 leftcommand[d12*mu],
377 { "slot", id, u2 },
378 },
379 }
380 end
381end
382
383local function jointhree(main,characters,id,size,unicode,u1,d12,u2,d23,u3)
384 local c1 = characters[u1]
385 local c2 = characters[u2]
386 local c3 = characters[u3]
387 if c1 and c2 and c3 then
388 local w1 = c1.width
389 local w2 = c2.width
390 local w3 = c3.width
391 local mu = size/18
392 characters[unicode] = {
393 width = w1 + w2 + w3 - d12*mu - d23*mu,
394 height = max(c1.height or 0, c2.height or 0, c3.height or 0),
395 depth = max(c1.depth or 0, c2.depth or 0, c3.depth or 0),
396 commands = {
397 { "slot", id, u1 },
398 leftcommand[d12*mu],
399 { "slot", id, u2 },
400 leftcommand[d23*mu],
401 { "slot", id, u3 },
402 }
403 }
404 end
405end
406
407local function stack(main,characters,id,size,unicode,u1,d12,u2)
408 local c1 = characters[u1]
409 if not c1 then
410 return
411 end
412 local c2 = characters[u2]
413 if not c2 then
414 return
415 end
416 local w1 = c1.width or 0
417 local h1 = c1.height or 0
418 local d1 = c1.depth or 0
419 local w2 = c2.width or 0
420 local h2 = c2.height or 0
421 local d2 = c2.depth or 0
422 local mu = size/18
423 characters[unicode] = {
424 width = w1,
425 height = h1 + h2 + d12,
426 depth = d1,
427 commands = {
428 { "slot", id, u1 },
429 leftcommand[w1/2 + w2/2],
430 downcommand[-h1 + d2 -d12*mu],
431 { "slot", id, u2 },
432 }
433 }
434end
435
436local function repeated(main,characters,id,size,unicode,u,n,private,fraction)
437 local c = characters[u]
438 if c then
439 local width = c.width
440 local italic = fraction*width
441 local tc = { "slot", id, u }
442 local tr = leftcommand[italic]
443 local commands = { }
444 for i=1,n-1 do
445 commands[#commands+1] = tc
446 commands[#commands+1] = tr
447 end
448 commands[#commands+1] = tc
449 local next = c.next
450 if next then
451 repeated(main,characters,id,size,private,next,n,private+1,fraction)
452 next = private
453 end
454 characters[unicode] = {
455 width = width + (n-1)*(width-italic),
456 height = c.height,
457 depth = c.depth,
458 italic = italic,
459 commands = commands,
460 next = next,
461 }
462 end
463end
464
465local function cloned(main,characters,id,size,source,target)
466 local data = characters[source]
467 if data then
468 characters[target] = data
469 return true
470 end
471end
472
473
474
475local data_of_smaller = nil
476local size_of_smaller = 0
477
478function vfmath.addmissing(main,id,size)
479
480 local id_of_smaller = nil
481
482 if size < size_of_smaller or size_of_smaller == 0 then
483 data_of_smaller = main.fonts[id]
484 id_of_smaller = id
485 else
486 id_of_smaller = #main.fonts + 1
487 main.fonts[id_of_smaller] = data_of_smaller
488 end
489
490
491
492 local characters = main.characters
493 local shared = main.shared
494 local variables = main.goodies.mathematics and main.goodies.mathematics.variables or { }
495 local joinrelfactor = variables.joinrelfactor or 3
496
497 for i=0x7A,0x7D do
498 make(main,characters,id,size,i,1)
499 end
500
501 brace (main,characters,id,size,0x23DE,0xFF17A,0xFF301,0xFF17D,0xFF17C,0xFF301,0xFF17B)
502 brace (main,characters,id,size,0x23DF,0xFF27C,0xFF401,0xFF27B,0xFF27A,0xFF401,0xFF27D)
503
504 parent (main,characters,id,size,0x23DC,0xFF17A,0xFF301,0xFF17B)
505 parent (main,characters,id,size,0x23DD,0xFF27C,0xFF401,0xFF27D)
506
507
508 dots (main,characters,id,size,0x2026)
509 dots (main,characters,id,size,0x22EE)
510 dots (main,characters,id,size,0x22EF)
511 dots (main,characters,id,size,0x22F1)
512 dots (main,characters,id,size,0x22F0)
513
514 vertbar (main,characters,id,size,0x0007C,0.10,0xFF601)
515 vertbar (main,characters,id,size,0xFF601,0.30,0xFF602)
516 vertbar (main,characters,id,size,0xFF602,0.30,0xFF603)
517 vertbar (main,characters,id,size,0xFF603,0.30,0xFF604)
518 vertbar (main,characters,id,size,0x02016,0.10,0xFF605)
519 vertbar (main,characters,id,size,0xFF605,0.30,0xFF606)
520 vertbar (main,characters,id,size,0xFF606,0.30,0xFF607)
521 vertbar (main,characters,id,size,0xFF607,0.30,0xFF608)
522
523 clipped (main,characters,id,size,0xFF501,0x0002D)
524 clipped (main,characters,id,size,0xFF502,0x02190)
525 clipped (main,characters,id,size,0xFF503,0x02192)
526 clipped (main,characters,id,size,0xFF504,0xFE321)
527 clipped (main,characters,id,size,0xFF505,0xFE322)
528 clipped (main,characters,id,size,0xFF506,0xFE323)
529 clipped (main,characters,id,size,0xFF507,0xFE324)
530 clipped (main,characters,id,size,0xFF508,0x021D0)
531 clipped (main,characters,id,size,0xFF509,0x021D2)
532 clipped (main,characters,id,size,0xFF50A,0x0003D)
533 clipped (main,characters,id,size,0xFF50B,0x0219E)
534 clipped (main,characters,id,size,0xFF50C,0x021A0)
535 clipped (main,characters,id,size,0xFF50D,0xFF350)
536 clipped (main,characters,id,size,0xFF50E,0xFF351)
537 clipped (main,characters,id,size,0xFF50F,0xFF352)
538 clipped (main,characters,id,size,0xFF510,0x02261)
539
540 extension(main,characters,id,size,0x2190,0xFF502,0xFF501,0xFF501)
541 extension(main,characters,id,size,0x2192,0xFF501,0xFF501,0xFF503)
542
543 extension(main,characters,id,size,0x002D,0xFF501,0xFF501,0xFF501)
544 extension(main,characters,id,size,0x003D,0xFF50A,0xFF50A,0xFF50A)
545 extension(main,characters,id,size,0x2261,0xFF510,0xFF510,0xFF510)
546
547 jointwo (main,characters,id,size,0x21A6,0xFE321,0,0x02192)
548 jointwo (main,characters,id,size,0x21A9,0x02190,joinrelfactor,0xFE323)
549 jointwo (main,characters,id,size,0x21AA,0xFE322,joinrelfactor,0x02192)
550 jointwo (main,characters,id,size,0x27F5,0x02190,joinrelfactor,0x0002D)
551 jointwo (main,characters,id,size,0x27F6,0x0002D,joinrelfactor,0x02192,2)
552 jointwo (main,characters,id,size,0x27F7,0x02190,joinrelfactor,0x02192)
553 jointwo (main,characters,id,size,0x27F8,0x021D0,joinrelfactor,0x0003D)
554 jointwo (main,characters,id,size,0x27F9,0x0003D,joinrelfactor,0x021D2)
555 jointwo (main,characters,id,size,0x27FA,0x021D0,joinrelfactor,0x021D2)
556 jointhree(main,characters,id,size,0x27FB,0x02190,joinrelfactor,0x0002D,0,0xFE324)
557 jointhree(main,characters,id,size,0x27FC,0xFE321,0,0x0002D,joinrelfactor,0x02192)
558
559 extension(main,characters,id,size,0x21A6,0xFF504,0xFF501,0xFF503)
560 extension(main,characters,id,size,0x21A9,0xFF502,0xFF501,0xFF506)
561 extension(main,characters,id,size,0x21AA,0xFF505,0xFF501,0xFF503)
562 extension(main,characters,id,size,0x27F5,0xFF502,0xFF501,0xFF501)
563 extension(main,characters,id,size,0x27F6,0xFF501,0xFF501,0xFF503)
564 extension(main,characters,id,size,0x27F7,0xFF502,0xFF501,0xFF503)
565 extension(main,characters,id,size,0x27F8,0xFF508,0xFF50A,0xFF50A)
566 extension(main,characters,id,size,0x27F9,0xFF50A,0xFF50A,0xFF509)
567 extension(main,characters,id,size,0x27FA,0xFF508,0xFF50A,0xFF509)
568 extension(main,characters,id,size,0x27FB,0xFF502,0xFF501,0xFF507)
569 extension(main,characters,id,size,0x27FC,0xFF504,0xFF501,0xFF503)
570
571 extension(main,characters,id,size,0x219E,0xFF50B,0xFF501,0xFF501)
572 extension(main,characters,id,size,0x21A0,0xFF501,0xFF501,0xFF50C)
573 extension(main,characters,id,size,0x21C4,0xFF50D,0xFF50E,0xFF50F)
574
575
576
577
578 stack(main,characters,id,size,0x2259,0x0003D,3,0x02227)
579
580 jointwo(main,characters,id,size,0x22C8,0x022B3,joinrelfactor,0x022B2)
581 jointwo(main,characters,id,size,0x22A7,0x0007C,joinrelfactor,0x0003D)
582 jointwo(main,characters,id,size,0x2260,0x00338,0,0x0003D)
583 jointwo(main,characters,id,size,0x2284,0x00338,0,0x02282)
584 jointwo(main,characters,id,size,0x2285,0x00338,0,0x02283)
585 jointwo(main,characters,id,size,0x2209,0x00338,0,0x02208)
586 jointwo(main,characters,id,size,0x2254,0x03A,0,0x03D)
587
588 repeated(main,characters,id,size,0x222C,0x222B,2,0xFF800,1/3)
589 repeated(main,characters,id,size,0x222D,0x222B,3,0xFF810,1/3)
590
591 if cloned(main,characters,id,size,0x2032,0xFE325) then
592 raise(main,characters,id,size,0x2032,0xFE325,1,id_of_smaller)
593 raise(main,characters,id,size,0x2033,0xFE325,2,id_of_smaller)
594 raise(main,characters,id,size,0x2034,0xFE325,3,id_of_smaller)
595
596 characters[0xFE932] = characters[0x2032]
597 characters[0xFE933] = characters[0x2033]
598 characters[0xFE934] = characters[0x2034]
599 end
600
601
602
603
604
605
606 characters[0x02B9] = characters[0x2032]
607
608 data_of_smaller = main.fonts[id]
609 size_of_smaller = size
610
611end
612
613local unique = 0
614
615local reported = { }
616local reverse = { }
617
618setmetatableindex(reverse, function(t,name)
619 if trace_virtual then
620 report_virtual("initializing math vector %a",name)
621 end
622 local m = mathencodings[name]
623 local r = { }
624 for u, i in next, m do
625 r[i] = u
626 end
627 reverse[name] = r
628 return r
629end)
630
631local function copy_glyph(main,target,original,unicode,slot)
632 local addprivate = fonts.helpers.addprivate
633 local olddata = original[unicode]
634 if olddata then
635 local newdata = {
636 width = olddata.width,
637 height = olddata.height,
638 depth = olddata.depth,
639 italic = olddata.italic,
640 kerns = olddata.kerns,
641 tounicode = olddata.tounicode,
642 commands = { { "slot", slot, unicode } },
643 }
644 local glyphdata = newdata
645 local nextglyph = olddata.next
646 while nextglyph do
647 local oldnextdata = original[nextglyph]
648 local newnextdata = {
649 width = oldnextdata.width,
650 height = oldnextdata.height,
651 depth = oldnextdata.depth,
652 tounicode = olddata.tounicode,
653 commands = { { "slot", slot, nextglyph } },
654 }
655 local newnextglyph = addprivate(main,formatters["M-N-%H"](nextglyph),newnextdata)
656 newdata.next = newnextglyph
657 local nextnextglyph = oldnextdata.next
658 if nextnextglyph == nextglyph then
659 break
660 else
661 olddata = oldnextdata
662 newdata = newnextdata
663 nextglyph = nextnextglyph
664 end
665 end
666 local hv = olddata.horiz_variants
667 if hv then
668 hv = fastcopy(hv)
669 newdata.horiz_variants = hv
670 for i=1,#hv do
671 local hvi = hv[i]
672 local oldglyph = hvi.glyph
673 local olddata = original[oldglyph]
674 local newdata = {
675 width = olddata.width,
676 height = olddata.height,
677 depth = olddata.depth,
678 tounicode = olddata.tounicode,
679 commands = { { "slot", slot, oldglyph } },
680 }
681 hvi.glyph = addprivate(main,formatters["M-H-%H"](oldglyph),newdata)
682 end
683 end
684 local vv = olddata.vert_variants
685 if vv then
686 vv = fastcopy(vv)
687 newdata.vert_variants = vv
688 for i=1,#vv do
689 local vvi = vv[i]
690 local oldglyph = vvi.glyph
691 local olddata = original[oldglyph]
692 local newdata = {
693 width = olddata.width,
694 height = olddata.height,
695 depth = olddata.depth,
696 tounicode = olddata.tounicode,
697 commands = { { "slot", slot, oldglyph } },
698 }
699 vvi.glyph = addprivate(main,formatters["M-V-%H"](oldglyph),newdata)
700 end
701 end
702 return newdata
703 end
704end
705
706vfmath.copy_glyph = copy_glyph
707
708function vfmath.define(specification,set,goodies)
709 local name = specification.name
710 local size = specification.size
711 local loaded = { }
712 local fontlist = { }
713 local names = { }
714 local main = nil
715 local start = (trace_virtual or trace_timings) and os.clock()
716 local okset = { }
717 local n = 0
718 for s=1,#set do
719 local ss = set[s]
720 local ssname = ss.name
721 if add_optional and ss.optional then
722 if trace_virtual then
723 report_virtual("loading font %a subfont %s with name %a at %p is skipped",name,s,ssname,size)
724 end
725 else
726 if ss.features then
727 ssname = ssname .. "*" .. ss.features
728 end
729 if ss.main then
730 main = s
731 end
732 local alreadyloaded = names[ssname]
733 local f, id
734 if alreadyloaded then
735 f, id = alreadyloaded.f, alreadyloaded.id
736 if trace_virtual then
737 report_virtual("loading font %a subfont %s with name %a is reused",name,s,ssname)
738 end
739 else
740 f, id = fonts.constructors.readanddefine(ssname,size)
741 names[ssname] = { f = f, id = id }
742 end
743 if not f or id == 0 then
744 report_virtual("loading font %a subfont %s with name %a at %p is skipped, not found",name,s,ssname,size)
745 else
746 n = n + 1
747 okset[n] = ss
748 loaded[n] = f
749 fontlist[n] = { id = id, size = size }
750 if not shared[s] then
751 shared[n] = { }
752 end
753 if trace_virtual then
754 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)
755 end
756 if not ss.checked then
757 ss.checked = true
758 local vector = mathencodings[ss.vector]
759 if vector then
760
761
762
763 for unicode, index in next, vector do
764 if not tonumber(index) then
765 local u = f.unicodes
766 u = u and u[index]
767 if u then
768 if trace_virtual then
769 report_virtual("resolving name %a to %s",index,u)
770 end
771 else
772 report_virtual("unable to resolve name %a",index)
773 end
774 vector[unicode] = u
775 end
776 end
777 end
778 end
779 end
780 end
781 end
782
783 local parent = loaded[1] or { }
784 local characters = { }
785 local parameters = { }
786 local mathparameters = { }
787 local descriptions = { }
788 local metadata = { }
789 local properties = { }
790 local goodies = { }
791 local main = {
792 metadata = metadata,
793 properties = properties,
794 characters = characters,
795 descriptions = descriptions,
796 parameters = parameters,
797 mathparameters = mathparameters,
798 fonts = fontlist,
799 goodies = goodies,
800 }
801
802
803 for key, value in next, parent do
804 if type(value) ~= "table" then
805 main[key] = value
806 end
807 end
808
809 if parent.characters then
810 for unicode, character in next, parent.characters do
811 characters[unicode] = character
812 end
813 else
814 report_virtual("font %a has no characters",name)
815 end
816
817 if parent.parameters then
818 for key, value in next, parent.parameters do
819 parameters[key] = value
820 end
821 else
822 report_virtual("font %a has no parameters",name)
823 end
824
825 local description = { name = "<unset>" }
826 setmetatableindex(descriptions,function() return description end)
827
828 if parent.properties then
829 setmetatableindex(properties,parent.properties)
830 end
831
832 if parent.goodies then
833 setmetatableindex(goodies,parent.goodies)
834 end
835
836 properties.hasitalics = true
837 properties.hasmath = true
838
839 local fullname = properties.fullname
840 if fullname then
841 unique = unique + 1
842 properties.fullname = fullname .. "-" .. unique
843 end
844
845
846
847 main.fullname = properties.fullname
848 main.nomath = false
849
850 properties.virtualized = true
851 main.type = "virtual"
852
853 parameters.x_height = parameters.x_height or 0
854
855 local already_reported = false
856 local parameters_done = false
857 for s=1,n do
858 local ss, fs = okset[s], loaded[s]
859 if not fs then
860
861 elseif add_optional and ss.optional then
862
863 else
864 local newparameters = fs.parameters
865 local newmathparameters = fs.mathparameters
866 if newmathparameters then
867 if not parameters_done or ss.parameters then
868 mathparameters = newmathparameters
869 parameters_done = true
870 end
871 elseif not newparameters then
872 report_virtual("no parameters set in font %a",name)
873 elseif ss.extension then
874 mathparameters.math_x_height = newparameters.x_height or 0
875 mathparameters.default_rule_thickness = newparameters[ 8] or 0
876 mathparameters.big_op_spacing1 = newparameters[ 9] or 0
877 mathparameters.big_op_spacing2 = newparameters[10] or 0
878 mathparameters.big_op_spacing3 = newparameters[11] or 0
879 mathparameters.big_op_spacing4 = newparameters[12] or 0
880 mathparameters.big_op_spacing5 = newparameters[13] or 0
881
882 elseif ss.parameters then
883 mathparameters.x_height = newparameters.x_height or mathparameters.x_height
884 mathparameters.x_height = mathparameters.x_height or fp.x_height or 0
885 mathparameters.num1 = newparameters[ 8] or 0
886 mathparameters.num2 = newparameters[ 9] or 0
887 mathparameters.num3 = newparameters[10] or 0
888 mathparameters.denom1 = newparameters[11] or 0
889 mathparameters.denom2 = newparameters[12] or 0
890 mathparameters.sup1 = newparameters[13] or 0
891 mathparameters.sup2 = newparameters[14] or 0
892 mathparameters.sup3 = newparameters[15] or 0
893 mathparameters.sub1 = newparameters[16] or 0
894 mathparameters.sub2 = newparameters[17] or 0
895 mathparameters.sup_drop = newparameters[18] or 0
896 mathparameters.sub_drop = newparameters[19] or 0
897 mathparameters.delim1 = newparameters[20] or 0
898 mathparameters.delim2 = newparameters[21] or 0
899 mathparameters.axis_height = newparameters[22] or 0
900
901 end
902 if ss.overlay then
903 local fc = fs.characters
904 local first = ss.first
905 if first then
906 local last = ss.last or first
907 for unicode = first, last do
908 characters[unicode] = copy_glyph(main,characters,fc,unicode,s)
909 end
910 else
911 for unicode, data in next, fc do
912 characters[unicode] = copy_glyph(main,characters,fc,unicode,s)
913 end
914 end
915 else
916 local vectorname = ss.vector
917 if vectorname then
918 local offset = 0xFF000
919 local vector = mathencodings[vectorname]
920 local rotcev = reverse[vectorname]
921 local isextension = ss.extension
922 if vector and rotcev then
923 local fc = fs.characters
924 local fd = fs.descriptions
925 local si = shared[s]
926 local fontname = fs.properties.name or "unknown"
927 local skewchar = ss.skewchar
928 for unicode, index in next, vector do
929 local fci = fc[index]
930 if not fci then
931 local rf = reported[fontname]
932 if not rf then rf = { } reported[fontname] = rf end
933 local rv = rf[vectorname]
934 if not rv then rv = { } rf[vectorname] = rv end
935 local ru = rv[unicode]
936 if not ru then
937 if trace_virtual then
938 report_virtual("unicode slot %U has no index %H in vector %a for font %a (%S)",unicode,index,vectorname,fontname,chardata[unicode].description)
939 elseif not already_reported then
940 report_virtual("the mapping is incomplete for %a at %p",name,size)
941 already_reported = true
942 end
943 rv[unicode] = true
944 end
945 else
946 local ref = si[index]
947 if not ref then
948 ref = { { 'slot', s, index } }
949 si[index] = ref
950 end
951 local kerns = fci.kerns
952 local width = fci.width
953 local italic = fci.italic
954 if italic and italic > 0 then
955
956 if isextension then
957 width = width + italic
958 end
959 end
960 if kerns then
961 local krn = { }
962 for k, v in next, kerns do
963 local rk = rotcev[k]
964 if rk then
965 krn[rk] = v
966 end
967 end
968 if not next(krn) then
969 krn = nil
970 end
971 local t = {
972 width = width,
973 height = fci.height,
974 depth = fci.depth,
975 italic = italic,
976 kerns = krn,
977 commands = ref,
978 }
979 if skewchar then
980 local k = kerns[skewchar]
981 if k then
982 t.top_accent = width/2 + k
983 end
984 end
985 characters[unicode] = t
986 else
987 characters[unicode] = {
988 width = width,
989 height = fci.height,
990 depth = fci.depth,
991 italic = italic,
992 commands = ref,
993 }
994 end
995 end
996 end
997 if isextension then
998
999 local extension = mathencodings["large-to-small"]
1000 local variants_done = fs.variants_done
1001 for index, fci in next, fc do
1002 if type(index) == "number" then
1003 local ref = si[index]
1004 if not ref then
1005 ref = { { 'slot', s, index } }
1006 si[index] = ref
1007 end
1008 local italic = fci.italic
1009 local t = {
1010 width = fci.width,
1011 height = fci.height,
1012 depth = fci.depth,
1013 italic = italic,
1014 commands = ref,
1015 }
1016 local n = fci.next
1017 if n then
1018 t.next = offset + n
1019 elseif variants_done then
1020 local vv = fci.vert_variants
1021 if vv then
1022 t.vert_variants = vv
1023 end
1024 local hv = fci.horiz_variants
1025 if hv then
1026 t.horiz_variants = hv
1027 end
1028 else
1029 local vv = fci.vert_variants
1030 if vv then
1031 for i=1,#vv do
1032 local vvi = vv[i]
1033 vvi.glyph = vvi.glyph + offset
1034 end
1035 t.vert_variants = vv
1036 end
1037 local hv = fci.horiz_variants
1038 if hv then
1039 for i=1,#hv do
1040 local hvi = hv[i]
1041 hvi.glyph = hvi.glyph + offset
1042 end
1043 t.horiz_variants = hv
1044 end
1045 end
1046 characters[offset + index] = t
1047 end
1048 end
1049 fs.variants_done = true
1050 for unicode, index in next, extension do
1051 local cu = characters[unicode]
1052 if cu then
1053 cu.next = offset + index
1054 else
1055 local fci = fc[index]
1056 if not fci then
1057
1058 else
1059
1060 local ref = si[index]
1061 if not ref then
1062 ref = { { 'slot', s, index } }
1063 si[index] = ref
1064 end
1065 local kerns = fci.kerns
1066 if kerns then
1067 local krn = { }
1068
1069
1070
1071 for k, v in next, kerns do
1072 krn[offset + k] = v
1073 end
1074 characters[unicode] = {
1075 width = fci.width,
1076 height = fci.height,
1077 depth = fci.depth,
1078 italic = fci.italic,
1079 commands = ref,
1080 kerns = krn,
1081 next = offset + index,
1082 }
1083 else
1084 characters[unicode] = {
1085 width = fci.width,
1086 height = fci.height,
1087 depth = fci.depth,
1088 italic = fci.italic,
1089 commands = ref,
1090 next = offset + index,
1091 }
1092 end
1093 end
1094 end
1095 end
1096 end
1097 else
1098 report_virtual("error in loading %a, problematic vector %a",name,vectorname)
1099 end
1100 end
1101 end
1102 mathematics.extras.copy(main)
1103 end
1104 end
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 |