diff options
Diffstat (limited to 'Master/texmf-dist/tex/context/base/mkiv/math-vfu.lua')
-rw-r--r-- | Master/texmf-dist/tex/context/base/mkiv/math-vfu.lua | 1107 |
1 files changed, 1107 insertions, 0 deletions
diff --git a/Master/texmf-dist/tex/context/base/mkiv/math-vfu.lua b/Master/texmf-dist/tex/context/base/mkiv/math-vfu.lua new file mode 100644 index 00000000000..a683e02cfdc --- /dev/null +++ b/Master/texmf-dist/tex/context/base/mkiv/math-vfu.lua @@ -0,0 +1,1107 @@ +if not modules then modules = { } end modules ['math-vfu'] = { + version = 1.001, + comment = "companion to math-ini.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +-- All these math vectors .. thanks to Aditya and Mojca they become +-- better and better. If you have problems with math fonts or miss +-- characters report it to the ConTeXt mailing list. Also thanks to +-- Boguslaw for finding a couple of errors. +-- +-- This mechanism will stay around. Even when we've switched to the +-- real fonts, one can still say: +-- +-- \enablemode[lmmath,pxmath,txmath] +-- +-- to get the virtual counterparts. There are still areas where the +-- virtuals are better. + +-- 20D6 -> 2190 +-- 20D7 -> 2192 + +local type, next = type, next +local max = math.max +local format = string.format +local utfchar = utf.char +local fastcopy = table.copy + +local fonts, nodes, mathematics = fonts, nodes, mathematics + +local trace_virtual = false trackers.register("math.virtual", function(v) trace_virtual = v end) +local trace_timings = false trackers.register("math.timings", function(v) trace_timings = v end) + +local add_optional = false directives.register("math.virtual.optional",function(v) add_optional = v end) + +local report_virtual = logs.reporter("fonts","virtual math") + +local allocate = utilities.storage.allocate +local setmetatableindex = table.setmetatableindex +local formatters = string.formatters + +local chardata = characters.data + +local mathencodings = allocate() +fonts.encodings.math = mathencodings -- better is then: fonts.encodings.vectors +local vfmath = allocate() +fonts.handlers.vf.math = vfmath + +local shared = { } + +-- local push, pop, back = { "push" }, { "pop" }, { "slot", 1, 0x2215 } +-- +-- local function negate(main,characters,id,size,unicode,basecode) +-- if not characters[unicode] then +-- local basechar = characters[basecode] +-- if basechar then +-- local ht, wd = basechar.height, basechar.width +-- characters[unicode] = { +-- width = wd, +-- height = ht, +-- depth = basechar.depth, +-- italic = basechar.italic, +-- kerns = basechar.kerns, +-- commands = { +-- { "slot", 1, basecode }, +-- push, +-- { "down", ht/5}, +-- { "right", - wd/2}, +-- back, +-- push, +-- } +-- } +-- end +-- end +-- end +-- +-- \Umathchardef\braceld="0 "1 "FF07A +-- \Umathchardef\bracerd="0 "1 "FF07B +-- \Umathchardef\bracelu="0 "1 "FF07C +-- \Umathchardef\braceru="0 "1 "FF07D + +local function brace(main,characters,id,size,unicode,first,rule,left,right,rule,last) + if not characters[unicode] then + characters[unicode] = { + horiz_variants = { + { extender = 0, glyph = first }, + { extender = 1, glyph = rule }, + { extender = 0, glyph = left }, + { extender = 0, glyph = right }, + { extender = 1, glyph = rule }, + { extender = 0, glyph = last }, + } + } + end +end + +local function extension(main,characters,id,size,unicode,first,middle,last) + local chr = characters[unicode] + if not chr then + return -- skip + end + local fw = characters[first] + if not fw then + return + end + local mw = characters[middle] + if not mw then + return + end + local lw = characters[last] + if not lw then + return + end + fw = fw.width + mw = mw.width + lw = lw.width + if fw == 0 then + fw = 1 + end + if lw == 0 then + lw = 1 + end + chr.horiz_variants = { + { extender = 0, glyph = first, ["end"] = fw/2, start = 0, advance = fw }, + { extender = 1, glyph = middle, ["end"] = mw/2, start = mw/2, advance = mw }, + { extender = 0, glyph = last, ["end"] = 0, start = lw/2, advance = lw }, + } +end + +local function parent(main,characters,id,size,unicode,first,rule,last) + if not characters[unicode] then + characters[unicode] = { + horiz_variants = { + { extender = 0, glyph = first }, + { extender = 1, glyph = rule }, + { extender = 0, glyph = last }, + } + } + end +end + +local push, pop, step = { "push" }, { "pop" }, 0.2 -- 0.1 is nicer but gives larger files + +local function make(main,characters,id,size,n,m) + local old = 0xFF000 + n + local c = characters[old] + if c then + local upslot, dnslot, uprule, dnrule = 0xFF100 + n, 0xFF200 + n, 0xFF300 + m, 0xFF400 + m + local xu = main.parameters.x_height + 0.3*size + local xd = 0.3*size + local w, h, d = c.width, c.height, c.depth + local thickness = h - d + local rulewidth = step*size -- we could use an overlap + local slot = { "slot", id, old } + local rule = { "rule", thickness, rulewidth } + local up = { "down", -xu } + local dn = { "down", xd } + local ht, dp = xu + 3*thickness, 0 + if not characters[uprule] then + characters[uprule] = { width = rulewidth, height = ht, depth = dp, commands = { push, up, rule, pop } } + end + characters[upslot] = { width = w, height = ht, depth = dp, commands = { push, up, slot, pop } } + local ht, dp = 0, xd + 3*thickness + if not characters[dnrule] then + characters[dnrule] = { width = rulewidth, height = ht, depth = dp, commands = { push, dn, rule, pop } } + end + characters[dnslot] = { width = w, height = ht, depth = dp, commands = { push, dn, slot, pop } } + end +end + +local function clipped(main,characters,id,size,unicode,original) -- push/pop needed? + local minus = characters[original] + if minus then + local mu = size/18 + local step = 3*mu + local width = minus.width + if width > step then + width = width - step + step = step / 2 + else + width = width / 2 + step = width + end + characters[unicode] = { + width = width, + height = minus.height, + depth = minus.depth, + commands = { push, { "right", -step }, { "slot", id, original }, pop } + } + end +end + +-- fails: pdf:page: pdf:direct: ... some funny displacement + +-- this does not yet work ... { "scale", 2, 0, 0, 3 } .. commented code +-- +-- this does not work ... no interpretation going on here +-- +-- local nodeinjections = backends.nodeinjections +-- { "node", nodeinjections.save() }, +-- { "node", nodeinjections.transform(.7,0,0,.7) }, +-- commands[#commands+1] = { "node", nodeinjections.restore() } + +-- local done = { } +-- +-- local function raise(main,characters,id,size,unicode,private,n,id_of_smaller) -- this is a real fake mess +-- local raised = characters[private] +-- if raised then +-- if not done[unicode] then +-- report_virtual("temporary too large %U due to issues in luatex backend",unicode) +-- done[unicode] = true +-- end +-- local up = 0.85 * main.parameters.x_height +-- local slot = { "slot", id, private } +-- local commands = { +-- push, +-- { "down", - up }, +-- -- { "scale", .7, 0, 0, .7 }, +-- slot, +-- } +-- for i=2,n do +-- commands[#commands+1] = slot +-- end +-- commands[#commands+1] = pop +-- characters[unicode] = { +-- width = .7 * n * raised.width, +-- height = .7 * (raised.height + up), +-- depth = .7 * (raised.depth - up), +-- commands = commands, +-- } +-- end +-- end + +local function raise(main,characters,id,size,unicode,private,n,id_of_smaller) -- this is a real fake mess + local raised = fonts.hashes.characters[main.fonts[id_of_smaller].id][private] -- characters[private] + if raised then + local up = 0.85 * main.parameters.x_height + local slot = { "slot", id_of_smaller, private } + local commands = { + push, + { "down", - up }, + slot, + } + for i=2,n do + commands[#commands+1] = slot + end + commands[#commands+1] = pop + characters[unicode] = { + width = n * raised.width, + height = (raised.height or 0) + up, + depth = (raised.depth or 0) - up, + italic = raised.italic, + commands = commands, + } + end +end + +local function dots(main,characters,id,size,unicode) + local c = characters[0x002E] + if c then + local w, h, d = c.width, c.height, c.depth + local mu = size/18 + local right3mu = { "right", 3*mu } + local right1mu = { "right", 1*mu } + local up1size = { "down", -.1*size } + local up4size = { "down", -.4*size } + local up7size = { "down", -.7*size } + local right2muw = { "right", 2*mu + w } + local slot = { "slot", id, 0x002E } + if unicode == 0x22EF then + local c = characters[0x022C5] + if c then + local w, h, d = c.width, c.height, c.depth + local slot = { "slot", id, 0x022C5 } + characters[unicode] = { + width = 3*w + 2*3*mu, height = h, depth = d, + commands = { push, slot, right3mu, slot, right3mu, slot, pop } + } + end + elseif unicode == 0x22EE then + -- weird height ! + characters[unicode] = { + width = w, height = h+(1.4)*size, depth = 0, + commands = { push, push, slot, pop, up4size, push, slot, pop, up4size, slot, pop } + } + elseif unicode == 0x22F1 then + characters[unicode] = { + width = 3*w + 6*size/18, height = 1.5*size, depth = 0, + commands = { + push, + right1mu, + push, up7size, slot, pop, + right2muw, + push, up4size, slot, pop, + right2muw, + push, up1size, slot, pop, + right1mu, + pop + } + } + elseif unicode == 0x22F0 then + characters[unicode] = { + width = 3*w + 6*size/18, height = 1.5*size, depth = 0, + commands = { + push, + right1mu, + push, up1size, slot, pop, + right2muw, + push, up4size, slot, pop, + right2muw, + push, up7size, slot, pop, + right1mu, + pop + } + } + else + characters[unicode] = { + width = 3*w + 2*3*mu, height = h, depth = d, + commands = { push, slot, right3mu, slot, right3mu, slot, pop } + } + end + end +end + +local function vertbar(main,characters,id,size,parent,scale,unicode) + local cp = characters[parent] + if cp then + local sc = scale * size + local pc = { "slot", id, parent } + characters[unicode] = { + width = cp.width, + height = cp.height + sc, + depth = cp.depth + sc, + commands = { + push, { "down", -sc }, pc, pop, + push, { "down", sc }, pc, pop, + pc, + }, + next = cp.next -- can be extensible + } + cp.next = unicode + end +end + +local function jointwo(main,characters,id,size,unicode,u1,d12,u2,what) + local c1, c2 = characters[u1], characters[u2] + if c1 and c2 then + local w1, w2 = c1.width, c2.width + local mu = size/18 + characters[unicode] = { + width = w1 + w2 - d12 * mu, + height = max(c1.height or 0, c2.height or 0), + depth = max(c1.depth or 0, c2.depth or 0), + commands = { + { "slot", id, u1 }, + { "right", -d12*mu } , + { "slot", id, u2 }, + }, + } + end +end + +local function jointhree(main,characters,id,size,unicode,u1,d12,u2,d23,u3) + local c1, c2, c3 = characters[u1], characters[u2], characters[u3] + if c1 and c2 and c3 then + local w1, w2, w3 = c1.width, c2.width, c3.width + local mu = size/18 + characters[unicode] = { + width = w1 + w2 + w3 - d12*mu - d23*mu, + height = max(c1.height or 0, c2.height or 0, c3.height or 0), + depth = max(c1.depth or 0, c2.depth or 0, c3.depth or 0), + commands = { + { "slot", id, u1 }, + { "right", - d12*mu } , + { "slot", id, u2 }, + { "right", - d23*mu }, + { "slot", id, u3 }, + } + } + end +end + +local function stack(main,characters,id,size,unicode,u1,d12,u2) + local c1, c2 = characters[u1], characters[u2] + if c1 and c2 then + local w1, w2 = c1.width, c2.width + local h1, h2 = c1.height, c2.height + local d1, d2 = c1.depth, c2.depth + local mu = size/18 + characters[unicode] = { + width = w1, + height = h1 + h2 + d12, + depth = d1, + commands = { + { "slot", id, u1 }, + { "right", - w1/2 - w2/2 } , + { "down", -h1 + d2 -d12*mu } , + { "slot", id, u2 }, + } + } + end +end + +local function repeated(main,characters,id,size,unicode,u,n,private,fraction) -- math-fbk.lua + local c = characters[u] + if c then + local width = c.width + local italic = fraction*width -- c.italic or 0 -- larger ones have funny italics + local tc = { "slot", id, u } + local tr = { "right", -italic } -- see hack elsewhere + local commands = { } + for i=1,n-1 do + commands[#commands+1] = tc + commands[#commands+1] = tr + end + commands[#commands+1] = tc +-- inspect(c) +-- inspect(commands) + local next = c.next + if next then + repeated(main,characters,id,size,private,next,n,private+1,fraction) + next = private + end + characters[unicode] = { + width = width + (n-1)*(width-italic), + height = c.height, + depth = c.depth, + italic = italic, + commands = commands, + next = next, + } + end +end + +local function cloned(main,characters,id,size,source,target) + local data = characters[source] + if data then + characters[target] = data + return true + end +end + +-- we use the fact that context defines the smallest sizes first .. a real dirty and ugly hack + +local data_of_smaller = nil +local size_of_smaller = 0 + +function vfmath.addmissing(main,id,size) + + local id_of_smaller = nil + + if size < size_of_smaller or size_of_smaller == 0 then + data_of_smaller = main.fonts[id] + id_of_smaller = id + else + id_of_smaller = #main.fonts + 1 + main.fonts[id_of_smaller] = data_of_smaller + end + + -- here id is the index in fonts (normally 14 or so) and that slot points to self + + local characters = main.characters + local shared = main.shared + local variables = main.goodies.mathematics and main.goodies.mathematics.variables or { } + local joinrelfactor = variables.joinrelfactor or 3 + + for i=0x7A,0x7D do + make(main,characters,id,size,i,1) + end + + brace (main,characters,id,size,0x23DE,0xFF17A,0xFF301,0xFF17D,0xFF17C,0xFF301,0xFF17B) + brace (main,characters,id,size,0x23DF,0xFF27C,0xFF401,0xFF27B,0xFF27A,0xFF401,0xFF27D) + + parent (main,characters,id,size,0x23DC,0xFF17A,0xFF301,0xFF17B) + parent (main,characters,id,size,0x23DD,0xFF27C,0xFF401,0xFF27D) + + -- negate (main,characters,id,size,0x2260,0x003D) + dots (main,characters,id,size,0x2026) -- ldots + dots (main,characters,id,size,0x22EE) -- vdots + dots (main,characters,id,size,0x22EF) -- cdots + dots (main,characters,id,size,0x22F1) -- ddots + dots (main,characters,id,size,0x22F0) -- udots + + vertbar (main,characters,id,size,0x0007C,0.10,0xFF601) -- big : 0.85 bodyfontsize + vertbar (main,characters,id,size,0xFF601,0.30,0xFF602) -- Big : 1.15 bodyfontsize + vertbar (main,characters,id,size,0xFF602,0.30,0xFF603) -- bigg : 1.45 bodyfontsize + vertbar (main,characters,id,size,0xFF603,0.30,0xFF604) -- Bigg : 1.75 bodyfontsize + vertbar (main,characters,id,size,0x02016,0.10,0xFF605) + vertbar (main,characters,id,size,0xFF605,0.30,0xFF606) + vertbar (main,characters,id,size,0xFF606,0.30,0xFF607) + vertbar (main,characters,id,size,0xFF607,0.30,0xFF608) + + clipped (main,characters,id,size,0xFF501,0x0002D) -- minus + clipped (main,characters,id,size,0xFF502,0x02190) -- lefthead + clipped (main,characters,id,size,0xFF503,0x02192) -- righthead + clipped (main,characters,id,size,0xFF504,0xFE321) -- mapsto + clipped (main,characters,id,size,0xFF505,0xFE322) -- lhook + clipped (main,characters,id,size,0xFF506,0xFE323) -- rhook + clipped (main,characters,id,size,0xFF507,0xFE324) -- mapsfrom + clipped (main,characters,id,size,0xFF508,0x021D0) -- double lefthead + clipped (main,characters,id,size,0xFF509,0x021D2) -- double righthead + clipped (main,characters,id,size,0xFF50A,0x0003D) -- equal + clipped (main,characters,id,size,0xFF50B,0x0219E) -- lefttwohead + clipped (main,characters,id,size,0xFF50C,0x021A0) -- righttwohead + clipped (main,characters,id,size,0xFF50D,0xFF350) -- lr arrow combi snippet + clipped (main,characters,id,size,0xFF50E,0xFF351) -- lr arrow combi snippet + clipped (main,characters,id,size,0xFF50F,0xFF352) -- lr arrow combi snippet + clipped (main,characters,id,size,0xFF510,0x02261) -- equiv + + extension(main,characters,id,size,0x2190,0xFF502,0xFF501,0xFF501) -- \leftarrow + extension(main,characters,id,size,0x2192,0xFF501,0xFF501,0xFF503) -- \rightarrow + + extension(main,characters,id,size,0x002D,0xFF501,0xFF501,0xFF501) -- \rel + extension(main,characters,id,size,0x003D,0xFF50A,0xFF50A,0xFF50A) -- \equal + extension(main,characters,id,size,0x2261,0xFF510,0xFF510,0xFF510) -- \equiv + + jointwo (main,characters,id,size,0x21A6,0xFE321,0,0x02192) -- \mapstochar\rightarrow + jointwo (main,characters,id,size,0x21A9,0x02190,joinrelfactor,0xFE323) -- \leftarrow\joinrel\rhook + jointwo (main,characters,id,size,0x21AA,0xFE322,joinrelfactor,0x02192) -- \lhook\joinrel\rightarrow + jointwo (main,characters,id,size,0x27F5,0x02190,joinrelfactor,0x0002D) -- \leftarrow\joinrel\relbar + jointwo (main,characters,id,size,0x27F6,0x0002D,joinrelfactor,0x02192,2) -- \relbar\joinrel\rightarrow + jointwo (main,characters,id,size,0x27F7,0x02190,joinrelfactor,0x02192) -- \leftarrow\joinrel\rightarrow + jointwo (main,characters,id,size,0x27F8,0x021D0,joinrelfactor,0x0003D) -- \Leftarrow\joinrel\Relbar + jointwo (main,characters,id,size,0x27F9,0x0003D,joinrelfactor,0x021D2) -- \Relbar\joinrel\Rightarrow + jointwo (main,characters,id,size,0x27FA,0x021D0,joinrelfactor,0x021D2) -- \Leftarrow\joinrel\Rightarrow + jointhree(main,characters,id,size,0x27FB,0x02190,joinrelfactor,0x0002D,0,0xFE324) -- \leftarrow\joinrel\relbar\mapsfromchar + jointhree(main,characters,id,size,0x27FC,0xFE321,0,0x0002D,joinrelfactor,0x02192) -- \mapstochar\relbar\joinrel\rightarrow + + extension(main,characters,id,size,0x21A6,0xFF504,0xFF501,0xFF503) -- \mapstochar\rightarrow + extension(main,characters,id,size,0x21A9,0xFF502,0xFF501,0xFF506) -- \leftarrow\joinrel\rhook + extension(main,characters,id,size,0x21AA,0xFF505,0xFF501,0xFF503) -- \lhook\joinrel\rightarrow + extension(main,characters,id,size,0x27F5,0xFF502,0xFF501,0xFF501) -- \leftarrow\joinrel\relbar + extension(main,characters,id,size,0x27F6,0xFF501,0xFF501,0xFF503) -- \relbar\joinrel\rightarrow + extension(main,characters,id,size,0x27F7,0xFF502,0xFF501,0xFF503) -- \leftarrow\joinrel\rightarrow + extension(main,characters,id,size,0x27F8,0xFF508,0xFF50A,0xFF50A) -- \Leftarrow\joinrel\Relbar + extension(main,characters,id,size,0x27F9,0xFF50A,0xFF50A,0xFF509) -- \Relbar\joinrel\Rightarrow + extension(main,characters,id,size,0x27FA,0xFF508,0xFF50A,0xFF509) -- \Leftarrow\joinrel\Rightarrow + extension(main,characters,id,size,0x27FB,0xFF502,0xFF501,0xFF507) -- \leftarrow\joinrel\relbar\mapsfromchar + extension(main,characters,id,size,0x27FC,0xFF504,0xFF501,0xFF503) -- \mapstochar\relbar\joinrel\rightarrow + + extension(main,characters,id,size,0x219E,0xFF50B,0xFF501,0xFF501) -- \twoheadleftarrow\joinrel\relbar + extension(main,characters,id,size,0x21A0,0xFF501,0xFF501,0xFF50C) -- \relbar\joinrel\twoheadrightarrow + extension(main,characters,id,size,0x21C4,0xFF50D,0xFF50E,0xFF50F) -- leftoverright + + -- 21CB leftrightharpoon + -- 21CC rightleftharpoon + + stack(main,characters,id,size,0x2259,0x0003D,3,0x02227) -- \buildrel\wedge\over= + + jointwo(main,characters,id,size,0x22C8,0x022B3,joinrelfactor,0x022B2) -- \mathrel\triangleright\joinrel\mathrel\triangleleft (4 looks better than 3) + jointwo(main,characters,id,size,0x22A7,0x0007C,joinrelfactor,0x0003D) -- \mathrel|\joinrel= + jointwo(main,characters,id,size,0x2260,0x00338,0,0x0003D) -- \not\equal + jointwo(main,characters,id,size,0x2284,0x00338,0,0x02282) -- \not\subset + jointwo(main,characters,id,size,0x2285,0x00338,0,0x02283) -- \not\supset + jointwo(main,characters,id,size,0x2209,0x00338,0,0x02208) -- \not\in + jointwo(main,characters,id,size,0x2254,0x03A,0,0x03D) -- := (≔) + + repeated(main,characters,id,size,0x222C,0x222B,2,0xFF800,1/3) + repeated(main,characters,id,size,0x222D,0x222B,3,0xFF810,1/3) + + if cloned(main,characters,id,size,0x2032,0xFE325) then + raise(main,characters,id,size,0x2032,0xFE325,1,id_of_smaller) -- prime + raise(main,characters,id,size,0x2033,0xFE325,2,id_of_smaller) -- double prime + raise(main,characters,id,size,0x2034,0xFE325,3,id_of_smaller) -- triple prime + end + + -- there are more (needs discussion first): + + -- characters[0x20D6] = characters[0x2190] + -- characters[0x20D7] = characters[0x2192] + + characters[0x02B9] = characters[0x2032] -- we're nice + + data_of_smaller = main.fonts[id] + size_of_smaller = size + +end + +local unique = 0 -- testcase: \startTEXpage \math{!\text{-}\text{-}\text{-}} \stopTEXpage + +local reported = { } +local reverse = { } -- index -> unicode + +setmetatableindex(reverse, function(t,name) + if trace_virtual then + report_virtual("initializing math vector %a",name) + end + local m, r = mathencodings[name], { } + for u, i in next, m do + r[i] = u + end + reverse[name] = r + return r +end) + +local function copy_glyph(main,target,original,unicode,slot) + local addprivate = fonts.helpers.addprivate + local olddata = original[unicode] + if olddata then + local newdata = { + width = olddata.width, + height = olddata.height, + depth = olddata.depth, + italic = olddata.italic, + kerns = olddata.kerns, + commands = { { "slot", slot, unicode } }, + } + local glyphdata = newdata + local nextglyph = olddata.next + while nextglyph do + local oldnextdata = original[nextglyph] + local newnextdata = { + commands = { { "slot", slot, nextglyph } }, + width = oldnextdata.width, + height = oldnextdata.height, + depth = oldnextdata.depth, + } + local newnextglyph = addprivate(main,formatters["M-N-%H"](nextglyph),newnextdata) + newdata.next = newnextglyph +-- report_virtual("copied next: %X",newdata.next) + local nextnextglyph = oldnextdata.next + if nextnextglyph == nextglyph then + break + else + olddata = oldnextdata + newdata = newnextdata + nextglyph = nextnextglyph + end + end + local hv = olddata.horiz_variants + if hv then + hv = fastcopy(hv) + newdata.horiz_variants = hv + for i=1,#hv do + local hvi = hv[i] + local oldglyph = hvi.glyph + local olddata = original[oldglyph] + local newdata = { + commands = { { "slot", slot, oldglyph } }, + width = olddata.width, + height = olddata.height, + depth = olddata.depth, + } + hvi.glyph = addprivate(main,formatters["M-H-%H"](oldglyph),newdata) +-- report_virtual("copied h variant: %X at index %i",hvi.glyph,i) + end + end + local vv = olddata.vert_variants + if vv then + vv = fastcopy(vv) + newdata.vert_variants = vv + for i=1,#vv do + local vvi = vv[i] + local oldglyph = vvi.glyph + local olddata = original[oldglyph] + local newdata = { + commands = { { "slot", slot, oldglyph } }, + width = olddata.width, + height = olddata.height, + depth = olddata.depth, + } + vvi.glyph = addprivate(main,formatters["M-V-%H"](oldglyph),newdata) +-- report_virtual("copied v variant: %X at index %i",vvi.glyph,i) + end + end + return newdata + end +end + +vfmath.copy_glyph = copy_glyph + +function vfmath.define(specification,set,goodies) + local name = specification.name -- symbolic name + local size = specification.size -- given size + local loaded, fontlist, names, main = { }, { }, { }, nil + local start = (trace_virtual or trace_timings) and os.clock() + local okset, n = { }, 0 + for s=1,#set do + local ss = set[s] + local ssname = ss.name + if add_optional and ss.optional then + if trace_virtual then + report_virtual("loading font %a subfont %s with name %a at %p is skipped",name,s,ssname,size) + end + else + if ss.features then + ssname = ssname .. "*" .. ss.features + end + if ss.main then + main = s + end + local alreadyloaded = names[ssname] -- for px we load one twice (saves .04 sec) + local f, id + if alreadyloaded then + f, id = alreadyloaded.f, alreadyloaded.id + if trace_virtual then + report_virtual("loading font %a subfont %s with name %a is reused",name,s,ssname) + end + else + f, id = fonts.constructors.readanddefine(ssname,size) + names[ssname] = { f = f, id = id } + end + if not f or id == 0 then + report_virtual("loading font %a subfont %s with name %a at %p is skipped, not found",name,s,ssname,size) + else + n = n + 1 + okset[n] = ss + loaded[n] = f + fontlist[n] = { id = id, size = size } + if not shared[s] then + shared[n] = { } + end + if trace_virtual then + 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) + end + if not ss.checked then + ss.checked = true + local vector = mathencodings[ss.vector] + if vector then + -- we resolve named glyphs only once as we can assume that vectors + -- are unique to a font set (when we read an afm we get those names + -- mapped onto the private area) + for unicode, index in next, vector do + if not tonumber(index) then + local u = f.unicodes + u = u and u[index] + if u then + if trace_virtual then + report_virtual("resolving name %a to %s",index,u) -- maybe more detail for u + end + else + report_virtual("unable to resolve name %a",index) + end + vector[unicode] = u + end + end + end + end + end + end + end + -- beware, loaded[1] is already passed to tex (we need to make a simple copy then .. todo) + local parent = loaded[1] or { } -- a text font + local characters = { } + local parameters = { } + local mathparameters = { } + local descriptions = { } + local metadata = { } + local properties = { } + local goodies = { } + local main = { + metadata = metadata, + properties = properties, + characters = characters, + descriptions = descriptions, + parameters = parameters, + mathparameters = mathparameters, + fonts = fontlist, + goodies = goodies, + } + -- + -- + for key, value in next, parent do + if type(value) ~= "table" then + main[key] = value + end + end + -- + if parent.characters then + for unicode, character in next, parent.characters do + characters[unicode] = character + end + else + report_virtual("font %a has no characters",name) + end + -- + if parent.parameters then + for key, value in next, parent.parameters do + parameters[key] = value + end + else + report_virtual("font %a has no parameters",name) + end + -- + local description = { name = "<unset>" } + setmetatableindex(descriptions,function() return description end) + -- + if parent.properties then + setmetatableindex(properties,parent.properties) + end + -- + if parent.goodies then + setmetatableindex(goodies,parent.goodies) + end + -- + properties.virtualized = true + properties.hasitalics = true + properties.hasmath = true + -- + local fullname = properties.fullname -- parent via mt + if fullname then + unique = unique + 1 + properties.fullname = fullname .. "-" .. unique + end + -- + -- we need to set some values in main as well (still?) + -- + main.fullname = properties.fullname + main.type = "virtual" + main.nomath = false + -- + parameters.x_height = parameters.x_height or 0 + -- + local already_reported = false + local parameters_done = false + for s=1,n do + local ss, fs = okset[s], loaded[s] + if not fs then + -- skip, error + elseif add_optional and ss.optional then + -- skip, redundant + else + local newparameters = fs.parameters + local newmathparameters = fs.mathparameters + if newmathparameters then + if not parameters_done or ss.parameters then + mathparameters = newmathparameters + parameters_done = true + end + elseif not newparameters then + report_virtual("no parameters set in font %a",name) + elseif ss.extension then + mathparameters.math_x_height = newparameters.x_height or 0 -- math_x_height : height of x + mathparameters.default_rule_thickness = newparameters[ 8] or 0 -- default_rule_thickness : thickness of \over bars + mathparameters.big_op_spacing1 = newparameters[ 9] or 0 -- big_op_spacing1 : minimum clearance above a displayed op + mathparameters.big_op_spacing2 = newparameters[10] or 0 -- big_op_spacing2 : minimum clearance below a displayed op + mathparameters.big_op_spacing3 = newparameters[11] or 0 -- big_op_spacing3 : minimum baselineskip above displayed op + mathparameters.big_op_spacing4 = newparameters[12] or 0 -- big_op_spacing4 : minimum baselineskip below displayed op + mathparameters.big_op_spacing5 = newparameters[13] or 0 -- big_op_spacing5 : padding above and below displayed limits + -- report_virtual("loading and virtualizing font %a at size %p, setting ex parameters",name,size) + elseif ss.parameters then + mathparameters.x_height = newparameters.x_height or mathparameters.x_height + mathparameters.x_height = mathparameters.x_height or fp.x_height or 0 -- x_height : height of x + mathparameters.num1 = newparameters[ 8] or 0 -- num1 : numerator shift-up in display styles + mathparameters.num2 = newparameters[ 9] or 0 -- num2 : numerator shift-up in non-display, non-\atop + mathparameters.num3 = newparameters[10] or 0 -- num3 : numerator shift-up in non-display \atop + mathparameters.denom1 = newparameters[11] or 0 -- denom1 : denominator shift-down in display styles + mathparameters.denom2 = newparameters[12] or 0 -- denom2 : denominator shift-down in non-display styles + mathparameters.sup1 = newparameters[13] or 0 -- sup1 : superscript shift-up in uncramped display style + mathparameters.sup2 = newparameters[14] or 0 -- sup2 : superscript shift-up in uncramped non-display + mathparameters.sup3 = newparameters[15] or 0 -- sup3 : superscript shift-up in cramped styles + mathparameters.sub1 = newparameters[16] or 0 -- sub1 : subscript shift-down if superscript is absent + mathparameters.sub2 = newparameters[17] or 0 -- sub2 : subscript shift-down if superscript is present + mathparameters.sup_drop = newparameters[18] or 0 -- sup_drop : superscript baseline below top of large box + mathparameters.sub_drop = newparameters[19] or 0 -- sub_drop : subscript baseline below bottom of large box + mathparameters.delim1 = newparameters[20] or 0 -- delim1 : size of \atopwithdelims delimiters in display styles + mathparameters.delim2 = newparameters[21] or 0 -- delim2 : size of \atopwithdelims delimiters in non-displays + mathparameters.axis_height = newparameters[22] or 0 -- axis_height : height of fraction lines above the baseline + -- report_virtual("loading and virtualizing font %a at size %p, setting sy parameters",name,size) + end + if ss.overlay then + local fc = fs.characters + local first = ss.first + if first then + local last = ss.last or first + for unicode = first, last do + characters[unicode] = copy_glyph(main,characters,fc,unicode,s) + end + else + for unicode, data in next, fc do + characters[unicode] = copy_glyph(main,characters,fc,unicode,s) + end + end + else + local vectorname = ss.vector + if vectorname then + local offset = 0xFF000 + local vector = mathencodings[vectorname] + local rotcev = reverse[vectorname] + local isextension = ss.extension + if vector and rotcev then + local fc, fd, si = fs.characters, fs.descriptions, shared[s] + local skewchar = ss.skewchar + for unicode, index in next, vector do + local fci = fc[index] + if not fci then + local fontname = fs.properties.name or "unknown" + local rf = reported[fontname] + if not rf then rf = { } reported[fontname] = rf end + local rv = rf[vectorname] + if not rv then rv = { } rf[vectorname] = rv end + local ru = rv[unicode] + if not ru then + if trace_virtual then + report_virtual("unicode slot %U has no index %H in vector %a for font %a (%S)",unicode,index,vectorname,fontname,chardata[unicode].description) + elseif not already_reported then + report_virtual("the mapping is incomplete for %a at %p",name,size) + already_reported = true + end + rv[unicode] = true + end + else + local ref = si[index] + if not ref then + ref = { { 'slot', s, index } } + si[index] = ref + end + local kerns = fci.kerns + local width = fci.width + local italic = fci.italic + if italic and italic > 0 then + -- int_a^b + if isextension then + width = width + italic -- for obscure reasons the integral as a width + italic correction + end + end + if kerns then + local krn = { } + for k, v in next, kerns do -- kerns is sparse + local rk = rotcev[k] + if rk then + krn[rk] = v -- kerns[k] + end + end + if not next(krn) then + krn = nil + end + local t = { + width = width, + height = fci.height, + depth = fci.depth, + italic = italic, + kerns = krn, + commands = ref, + } + if skewchar then + local k = kerns[skewchar] + if k then + t.top_accent = width/2 + k + end + end + characters[unicode] = t + else + characters[unicode] = { + width = width, + height = fci.height, + depth = fci.depth, + italic = italic, + commands = ref, + } + end + end + end + if isextension then + -- todo: if multiple ex, then 256 offsets per instance + local extension = mathencodings["large-to-small"] + local variants_done = fs.variants_done + for index, fci in next, fc do -- the raw ex file + if type(index) == "number" then + local ref = si[index] + if not ref then + ref = { { 'slot', s, index } } + si[index] = ref + end + local italic = fci.italic + local t = { + width = fci.width, + height = fci.height, + depth = fci.depth, + italic = italic, + commands = ref, + } + local n = fci.next + if n then + t.next = offset + n + elseif variants_done then + local vv = fci.vert_variants + if vv then + t.vert_variants = vv + end + local hv = fci.horiz_variants + if hv then + t.horiz_variants = hv + end + else + local vv = fci.vert_variants + if vv then + for i=1,#vv do + local vvi = vv[i] + vvi.glyph = vvi.glyph + offset + end + t.vert_variants = vv + end + local hv = fci.horiz_variants + if hv then + for i=1,#hv do + local hvi = hv[i] + hvi.glyph = hvi.glyph + offset + end + t.horiz_variants = hv + end + end + characters[offset + index] = t + end + end + fs.variants_done = true + for unicode, index in next, extension do + local cu = characters[unicode] + if cu then + cu.next = offset + index + else + local fci = fc[index] + if not fci then + -- do nothing + else + -- probably never entered + local ref = si[index] + if not ref then + ref = { { 'slot', s, index } } + si[index] = ref + end + local kerns = fci.kerns + if kerns then + local krn = { } + -- for k=1,#kerns do + -- krn[offset + k] = kerns[k] + -- end + for k, v in next, kerns do -- is kerns sparse? + krn[offset + k] = v + end + characters[unicode] = { + width = fci.width, + height = fci.height, + depth = fci.depth, + italic = fci.italic, + commands = ref, + kerns = krn, + next = offset + index, + } + else + characters[unicode] = { + width = fci.width, + height = fci.height, + depth = fci.depth, + italic = fci.italic, + commands = ref, + next = offset + index, + } + end + end + end + end + end + else + report_virtual("error in loading %a, problematic vector %a",name,vectorname) + end + end + end + mathematics.extras.copy(main) --not needed here (yet) + end + end + -- + fontlist[#fontlist+1] = { + id = font.nextid(), + size = size, + } + -- + main.mathparameters = mathparameters -- still traditional ones + vfmath.addmissing(main,#fontlist,size) + mathematics.addfallbacks(main) + -- + main.properties.math_is_scaled = true -- signal + fonts.constructors.assignmathparameters(main,main) + -- + main.MathConstants = main.mathparameters -- we directly pass it to TeX (bypasses the scaler) so this is needed + -- + if trace_virtual or trace_timings then + report_virtual("loading and virtualizing font %a at size %p took %0.3f seconds",name,size,os.clock()-start) + end + -- + return main +end + +function mathematics.makefont(name,set,goodies) + fonts.definers.methods.variants[name] = function(specification) + return vfmath.define(specification,set,goodies) + end +end + +-- helpers + +function vfmath.setletters(font_encoding, name, uppercase, lowercase) + local enc = font_encoding[name] + for i = 0,25 do + enc[uppercase+i] = i + 0x41 + enc[lowercase+i] = i + 0x61 + end +end + +function vfmath.setdigits(font_encoding, name, digits) + local enc = font_encoding[name] + for i = 0,9 do + enc[digits+i] = i + 0x30 + end +end |