diff options
Diffstat (limited to 'tex/context/base/mkxl/math-act.lmt')
-rw-r--r-- | tex/context/base/mkxl/math-act.lmt | 634 |
1 files changed, 541 insertions, 93 deletions
diff --git a/tex/context/base/mkxl/math-act.lmt b/tex/context/base/mkxl/math-act.lmt index 48d389bf9..7aeec184f 100644 --- a/tex/context/base/mkxl/math-act.lmt +++ b/tex/context/base/mkxl/math-act.lmt @@ -13,6 +13,7 @@ local type, next = type, next local fastcopy, insert, remove = table.fastcopy, table.insert, table.remove local formatters = string.formatters local byte = string.byte +local setmetatableindex, sortedhash = table.setmetatableindex, table.sortedhash local trace_defining = false trackers.register("math.defining", function(v) trace_defining = v end) local trace_collecting = false trackers.register("math.collecting", function(v) trace_collecting = v end) @@ -60,9 +61,26 @@ function mathematics.initializeparameters(target,original) local mathparameters = original.mathparameters if mathparameters and next(mathparameters) then mathparameters = mathematics.dimensions(mathparameters) - if not mathparameters.SpaceBeforeScript then - mathparameters.SpaceBeforeScript = mathparameters.SpaceAfterScript - end + if not mathparameters.PrimeRaisePercent then mathparameters.PrimeRaisePercent = 25 end + if not mathparameters.PrimeShiftUp then mathparameters.PrimeShiftUp = mathparameters.SuperscriptShiftUp end + if not mathparameters.PrimeBaselineDropMax then mathparameters.PrimeBaselineDropMax = mathparameters.SuperscriptBaselineDropMax end + if not mathparameters.PrimeShiftUpCramped then mathparameters.PrimeShiftUpCramped = mathparameters.SuperscriptShiftUpCramped end + if not mathparameters.PrimeSpaceAfter then mathparameters.PrimeSpaceAfter = 0 end + if not mathparameters.PrimeWidthPercent then mathparameters.PrimeWidthPercent = 50 end + if not mathparameters.SpaceBeforeScript then mathparameters.SpaceBeforeScript = mathparameters.SpaceAfterScript end + if not mathparameters.NoLimitSupFactor then mathparameters.NoLimitSupFactor = 0 end + if not mathparameters.NoLimitSubFactor then mathparameters.NoLimitSubFactor = 0 end + if not mathparameters.AccentTopShiftUp then mathparameters.AccentTopShiftUp = 0 end + if not mathparameters.AccentBottomShiftDown then mathparameters.AccentBottomShiftDown = 0 end + if not mathparameters.FlattenedAccentTopShiftUp then mathparameters.AccentTopShiftUp = 0 end + if not mathparameters.FlattenedAccentBottomShiftDown then mathparameters.AccentBottomShiftDown = 0 end + if not mathparameters.AccentBaseDepth then mathparameters.AccentBaseDepth = 0 end + if not mathparameters.AccentFlattenedBaseDepth then mathparameters.AccentFlattenedBaseDepth = 0 end + -- + -- we don't want to reset that each time .. but then we also can't show what the value was + -- + -- mathparameters.RadicalDegreeBefore = 0 + -- target.mathparameters = mathparameters end end @@ -77,6 +95,8 @@ local how = { RadicalDegreeBottomRaisePercent = "unscaled", NoLimitSupFactor = "unscaled", NoLimitSubFactor = "unscaled", + PrimeRaisePercent = "unscaled", + PrimeWidthPercent = "unscaled", } function mathematics.scaleparameters(target,original) @@ -122,12 +142,15 @@ function mathematics.checkprivateparameters(target,original) if parameters then local size = parameters.size if size then - if not mathparameters.FractionDelimiterSize then - mathparameters.FractionDelimiterSize = 1.01 * size - end - if not mathparameters.FractionDelimiterDisplayStyleSize then - mathparameters.FractionDelimiterDisplayStyleSize = 2.40 * size - end +-- if not mathparameters.FractionDelimiterSize then +-- mathparameters.FractionDelimiterSize = 1.01 * size +-- end +-- if not mathparameters.FractionDelimiterDisplayStyleSize then +-- mathparameters.FractionDelimiterDisplayStyleSize = 2.40 * size +-- end +-- if not mathparameters.PrimeSuperscriptSpace then +-- mathparameters.PrimeSuperscriptSpace = size / 20 +-- end elseif properties then report_math("invalid parameters in font %a",properties.fullname or "?") else @@ -149,34 +172,55 @@ function mathematics.overloadparameters(target,original) for i=1,#goodies do local goodie = goodies[i] local mathematics = goodie.mathematics - local parameters = mathematics and mathematics.parameters - if parameters then - if trace_defining then - report_math("overloading math parameters in %a @ %p",target.properties.fullname,target.parameters.size) - end - for name, value in next, parameters do - local tvalue = type(value) - if tvalue == "string" then - report_math("comment for math parameter %a: %s",name,value) - else + if mathematics then + local parameters = mathematics.parameters + local bigslots = mathematics.bigslots or mathematics.bigs + if parameters then + if trace_defining then + report_math("overloading math parameters in %a @ %p",target.properties.fullname,target.parameters.size) + end + for name, value in next, parameters do + local tvalue = type(value) local oldvalue = mathparameters[name] local newvalue = oldvalue - if oldvalue then - if tvalue == "number" then - newvalue = value - elseif tvalue == "function" then - newvalue = value(oldvalue,target,original) - elseif not tvalue then - newvalue = nil - end - if trace_defining and oldvalue ~= newvalue then - report_math("overloading math parameter %a: %S => %S",name,oldvalue,newvalue) - end - else - report_math("invalid math parameter %a",name) + if tvalue == "number" then + newvalue = value + elseif tvalue == "string" then + -- delay till all set + elseif tvalue == "function" then + newvalue = value(oldvalue,target,original) + elseif not tvalue then + newvalue = nil + end + if trace_defining and oldvalue ~= newvalue then + report_math("overloading math parameter %a: %S => %S",name,oldvalue or 0,newvalue) end mathparameters[name] = newvalue end + for name, value in next, parameters do + local tvalue = type(value) + if tvalue == "string" then + local newvalue = mathparameters[value] + -- if not newvalue then + -- local code = loadstring("return " .. value,"","t",mathparameters) + -- if type(code) == "function" then + -- local okay, v = pcall(code) + -- if okay then + -- newvalue = v + -- end + -- end + -- end + if newvalue then + -- split in number and string + mathparameters[name] = newvalue + elseif trace_defining then + report_math("ignoring math parameter %a: %S",name,value) + end + end + end + end + if bigslots then + target.bigslots = bigslots end end end @@ -208,34 +252,151 @@ end do local stepper = utilities.parsers.stepper + local count = 0 + + local splitter = lpeg.tsplitat(".") - local function adapt(target,original,targetcharacters,originalcharacters,k,v,compact,n) + local function adapt(list,target,original,targetcharacters,originalcharacters,k,v,compact,n) local character = targetcharacters[k] if character then - local width = character.width - local italic = character.italic - local offsetfactor = v[1] or 1 - local widthfactor = v[2] or 1 - local italicfactor = v[3] or 1 - if width then - character.advance = width -- so advance is oldwidth - character.xoffset = offsetfactor * width - character.width = widthfactor * width - end - if italic then - character.italic = italicfactor * italic - elseif width and italicfactor ~= 1 then - character.italic = italicfactor * width - end - if trace_tweaking then - report_tweak("adapting dimensions of %U ",target,original,k) - end - local smaller = originalcharacters[k].smaller - if compact and smaller and smaller ~= k then - adapt(target,original,targetcharacters,originalcharacters,smaller,v,compact,n+1) + if not character.tweaked then + local t = type(v) + if t == "number" then + v = list[v] + t = type(v) + end + if t == "table" then + local width = character.width + local height = character.height + local depth = character.depth + local italic = character.italic + local topaccent = character.topaccent + if #v > 0 then + local offsetfactor = v[1] + local widthfactor = v[2] + local italicfactor = v[3] + local anchorfactor = v[4] + if width then + character.advance = width -- so advance is oldwidth + character.xoffset = offsetfactor * width + character.width = widthfactor * width + end + if italic then + character.italic = italicfactor * italic + elseif width and italicfactor ~= 1 then + character.italic = italicfactor * width + end + if topaccent and topaccent > 0 then + if anchorfactor then + character.topaccent = anchorfactor * topaccent + elseif width then + character.topaccent = topaccent + (character.width - character.advance) / 2 + end + end + else + local widthfactor = v.width + local heightfactor = v.height + local depthfactor = v.depth + local italicfactor = v.italic + local anchorfactor = v.anchor + local advancefactor = v.advance + local xoffsetfactor = v.xoffset + local yoffsetfactor = v.yoffset + local scalefactor = v.scale + local total = (height or 0) + (depth or 0) + if scalefactor ~= 1 then + character.scale = scalefactor + end + if width and width ~= 0 then + if advancefactor then + character.advance = advancefactor * width + end + if widthfactor then + character.width = widthfactor * width + end + if xoffsetfactor then + character.xoffset = xoffsetfactor * width + end + end + if height and height ~= 0 then + if heightfactor then + character.height = heightfactor * height + end + end + if depth and depthfactor then + character.depth = depthfactor * depth + end + if yoffsetfactor then + character.yoffset = yoffsetfactor * total + end + if italic and italic ~= 0 and italicfactor then + character.italic = italicfactor * italic + end + if anchorfactor then + character.topaccent = anchorfactor * (topaccent or width) + end + end + if trace_tweaking then + report_tweak("adapting dimensions of %U ",target,original,k) + end + local smaller = originalcharacters[k].smaller + if compact and smaller and smaller ~= k then + adapt(list,target,original,targetcharacters,originalcharacters,smaller,v,compact,n+1) + end + count = count + 1 + else + report_mathtweak("invalid dimension entry %U",k) + end + character.tweaked = true + if v.all then + local nxt = character.next + if nxt then + adapt(list,target,original,targetcharacters,originalcharacters,nxt,v,compact,n) + else + local parts = character.hparts + if parts then + for i=1,#parts do + adapt(list,target,original,targetcharacters,originalcharacters,parts[i],v,compact,n) + end + end + end + end end else - report_math("no character %U",k) + report_tweak("no character %U",target,original,k) + end + end + + local function detail(characters,k) + if type(k) == "string" then + local t = lpeg.match(splitter,k) + local n = #t + if n > 0 then + local m = tonumber(t[1]) or tonumber(t[1],16) + if m then + local c = characters[m] + if c and n > 1 then + m = t[2] + if m == "parts" then + local nxt = c.next + while nxt do + c = characters[nxt] + nxt = c.next + end + c = c.hparts or c.vparts + if c and n > 2 then + m = tonumber(t[3]) + if m then + c = c[m] + if c then + return c.glyph + end + end + end + end + end + end + end end end @@ -245,14 +406,29 @@ do local targetcharacters = target.characters local originalcharacters = original.characters local compact = target.parameters.textscale and true or false - for k, v in next, list do + count = 0 + for k, v in sortedhash(list) do local t = type(k) if t == "number" then - adapt(target,original,targetcharacters,originalcharacters,k,v,compact,1) + adapt(list,target,original,targetcharacters,originalcharacters,k,v,compact,1) elseif t == "string" then - stepper(k,function(n) adapt(target,original,targetcharacters,originalcharacters,n,v,compact,1) end) + local d = detail(targetcharacters,k) + if d then + adapt(list,target,original,targetcharacters,originalcharacters,d,v,compact,1) + else + stepper(k,function(n) + adapt(list,target,original,targetcharacters,originalcharacters,n,v,compact,1) + end) + end + -- elseif t == "table" then + -- for i=1,#t do + -- adapt(list,target,original,targetcharacters,originalcharacters,t[i],v,compact,1) + -- end end end + if trace_tweaking and count > 0 then + report_mathtweak("%i dimensions adapted",count) + end end end @@ -411,6 +587,274 @@ do end +do + + function mathtweaks.fixanchors(target,original,parameters) + local factor = tonumber(parameters.factor) + if factor ~= 0 then + for k, v in next, target.characters do + local a = v.topaccent + if a and a > 0 then + v.topaccent = a * factor + end + end + end + end + +end + +do + + -- local list = { + -- [0x203E] = { factor = .4 }, -- overbar + -- [0x203E] = { factor = .7 }, -- underbar + -- [0x23DE] = { factor = .4 }, -- overbrace + -- [0x23DF] = { factor = .7 }, -- underbrace + -- [0x23DC] = { factor = .4 }, -- overparent + -- [0x23DD] = { factor = .7 }, -- underparent + -- [0x23B4] = { factor = .4 }, -- overbracket + -- [0x23B5] = { factor = .7 }, -- underbracket + -- } + + -- We can patch the dimensions in-place or we can use additional characters in + -- the private namespace. + + -- local addprivate = fonts.helpers.addprivate + -- local newnextglyph = addprivate(target,formatters["M-N-%H"](nextglyph),newnextdata) + + local over = { factor = "over" } + local under = { factor = "under" } + + local candidates = { + over = { + [0x203E] = over, -- overbar + [0x23DE] = over, -- overbrace + [0x23DC] = over, -- overparent + [0x23B4] = over, -- overbracket + }, + under = { + [0x23DF] = under, -- underbrace + [0x23DD] = under, -- underparent + [0x23B5] = under, -- underbracket + }, + accent = { + [0x0300] = over, -- widegrave + [0x0308] = over, -- wideddot + [0x0304] = over, -- widebar + [0x0301] = over, -- wideacute + [0x0302] = over, -- widehat + [0x030C] = over, -- widecheck + [0x0306] = over, -- widebreve + [0x0307] = over, -- widedot + [0x030A] = over, -- widering + [0x0303] = over, -- widetilde + [0x20DB] = over, -- widedddot + }, + } + + local function adapt(c,factor,baseheight,basedepth) + if not c.tweaked then + local height = c.height or 0 + local depth = c.depth or 0 + local yoffset = 0 + if factor == "over" then + local h = height - baseheight + yoffset = h - height + height = h + depth = depth - baseheight + elseif factor == "under" then + local d = depth - basedepth + yoffset = depth - d + depth = d + height = height - baseheight + else + if height > 0 then + local h = tonumber(factor) * height + yoffset = h - height + height = h + elseif depth > 0 then + local d = tonumber(factor) * depth + yoffset = depth - d + depth = d + end + end + c.yoffset = yoffset ~= 0 and yoffset or nil + c.height = height > 0 and height or nil + c.depth = depth > 0 and depth or nil + c.tweaked = true + end + end + + local function process(characters,list,baseheight,basedepth) + if list then + for k, v in sortedhash(list) do -- sort for tracing + local c = characters[k] + if c and not c.yoffset then + local factor = v.factor + if factor then + adapt(c,factor,baseheight,basedepth) + local nc = c.next + local nv = 0 + local ns = 0 + while nc do + local c = characters[nc] + if c then + adapt(c,factor,baseheight,basedepth) + nv = nv + 1 + nc = c.next + if not nc then + local hv = c.hparts + if hv then + for i=1,#hv do + local c = characters[hv[i].glyph] + if c then + adapt(c,factor,baseheight,basedepth) + ns = ns + 1 + end + end + end + break + end + else + break + end + end + if trace_tweaking then + report_tweak("adapting extensible (%i sizes, %i parts) %U",k,nv,ns) + end + end + end + end + end + end + + function mathtweaks.accentdimensions(target,original,parameters) + local list = parameters.list or { "over", "under" } + if list then + local characters = target.characters + local baseheight = target.mathparameters.AccentBaseHeight or 0 + local basedepth = target.mathparameters.AccentBaseDepth or 0 + for k, v in sortedhash(list) do -- sort for tracing + local t = type(v) + if t == "string" then + v = candidates[v] + t = type(v) + end + if t == "table" then + process(characters,v,baseheight,basedepth) + end + end + end + end + +end + +do + + -- function mathtweaks.addrules(target,original,parameters) + -- local characters = target.characters + -- local height = target.mathparameters.OverbarRuleThickness + -- local depth = target.mathparameters.UnderbarRuleThickness + -- local width = target.parameters.emwidth/2 + -- local step = 0.8 * width + -- characters[0x203E] = { -- over + -- width = width, + -- height = height, + -- depth = 0, + -- unicode = 0x203E, + -- commands = { { "rule", height, width } }, + -- hparts = { + -- { advance = width, ["end"] = step, glyph = 0x203E, start = 0 }, + -- { advance = width, ["end"] = 0, glyph = 0x203E, start = step, extender = 1 }, + -- } + -- } + -- characters[0x0332] = { -- under + -- width = width, + -- height = 0, + -- depth = depth, + -- yoffset = -depth, + -- unicode = 0x0332, + -- commands = { { "rule", height, width } }, + -- hparts = { + -- { advance = width, ["end"] = step, glyph = 0x0332, start = 0 }, + -- { advance = width, ["end"] = 0, glyph = 0x0332, start = step, extender = 1 }, + -- } + -- } + -- end + + function mathtweaks.addrules(target,original,parameters) + local characters = target.characters + local thickness = target.mathparameters.OverbarRuleThickness + local width = target.parameters.emwidth / 2 + local step = 0.8 * width + characters[0x203E] = { -- over + width = width, + height = thickness / 2, + depth = thickness / 2, + yoffset = - thickness / 2, + unicode = 0x203E, + commands = { { "rule", thickness, width } }, + hparts = { + { advance = width, ["end"] = step, glyph = 0x203E, start = 0 }, + { advance = width, ["end"] = 0, glyph = 0x203E, start = step, extender = 1 }, + } + } + -- + characters[0x0332] = characters[0x203E] + -- + -- lucida lacks them ... + -- + local addprivate = fonts.helpers.addprivate + -- + local half = thickness / 2 + local double = thickness * 2 + -- + if not characters[0x23B4] then + local tpiece = addprivate(target,"bracket-piece-top",{ + width = thickness, + height = half, + depth = double, + yoffset = - double, + commands = { { "rule", thickness * 2.5, thickness } }, + }) + characters[0x23B4] = { -- over + width = width, + height = half, + depth = double, + unicode = 0x23B4, + commands = { { "rule", thickness, width } }, + hparts = { + { advance = thickness, glyph = tpiece, ["end"] = 0, start = half }, + { advance = width, glyph = 0x203E, ["end"] = step, start = step, extender = 1 }, + { advance = thickness, glyph = tpiece, ["end"] = half, start = 0 }, + } + } + end + if not characters[0x23B5] then + local bpiece = addprivate(target,"bracket-piece-bottom",{ + width = thickness, + height = double, + depth = half, + yoffset = - half, + commands = { { "rule", thickness * 2.5, thickness } }, + }) + characters[0x23B5] = { -- over + width = width, + height = double, + depth = half, + unicode = 0x23B5, + commands = { { "rule", thickness, width } }, + hparts = { + { advance = thickness, glyph = bpiece, ["end"] = 0, start = half }, + { advance = width, glyph = 0x203E, ["end"] = step, start = step, extender = 1 }, + { advance = thickness, glyph = bpiece, ["end"] = half, start = 0 }, + } + } + end + end + +end + function mathtweaks.action(target,original,parameters) local action = parameters.action if type(action) == "function" then @@ -626,32 +1070,42 @@ do end +local apply_tweaks = true + +directives.register("math.applytweaks", function(v) + apply_tweaks = v; +end) + local function applytweaks(when,target,original) - local goodies = original.goodies - if goodies then - for i=1,#goodies do - local goodie = goodies[i] - local mathematics = goodie.mathematics - local tweaks = mathematics and mathematics.tweaks - if type(tweaks) == "table" then - tweaks = tweaks[when] + if apply_tweaks then + local goodies = original.goodies + if goodies then + for i=1,#goodies do + local goodie = goodies[i] + local mathematics = goodie.mathematics + local tweaks = mathematics and mathematics.tweaks if type(tweaks) == "table" then - if trace_defining then - report_math("tweaking math of %a @ %p (%s)",target.properties.fullname,target.parameters.size,when) - end - for i=1,#tweaks do - local tweak = tweaks[i] - local tvalue = type(tweak) - if type(tweak) == "table" then - local action = mathtweaks[tweak.tweak or ""] - if action then - action(target,original,tweak) + tweaks = tweaks[when] + if type(tweaks) == "table" then + if trace_defining then + report_math("tweaking math of %a @ %p (%s)",target.properties.fullname,target.parameters.size,when) + end + for i=1,#tweaks do + local tweak = tweaks[i] + local tvalue = type(tweak) + if type(tweak) == "table" then + local action = mathtweaks[tweak.tweak or ""] + if action then + action(target,original,tweak) + end end end end end end end + else + report_math("not tweaking math of %a @ %p (%s)",target.properties.fullname,target.parameters.size,when) end end @@ -669,10 +1123,10 @@ function mathematics.tweakaftercopyingfont(target,original) end end +sequencers.appendaction("mathparameters","system","mathematics.overloadparameters") sequencers.appendaction("mathparameters","system","mathematics.scaleparameters") sequencers.appendaction("mathparameters","system","mathematics.checkaccentbaseheight") -- should go in lfg instead sequencers.appendaction("mathparameters","system","mathematics.checkprivateparameters") -- after scaling ! -sequencers.appendaction("mathparameters","system","mathematics.overloadparameters") sequencers.appendaction("beforecopyingcharacters","system","mathematics.tweakbeforecopyingfont") sequencers.appendaction("aftercopyingcharacters", "system","mathematics.tweakaftercopyingfont") @@ -683,16 +1137,11 @@ sequencers.appendaction("aftercopyingcharacters", "system","mathematics.tweakaft -- helpers -local setmetatableindex = table.setmetatableindex - -local getfontoffamily = tex.getfontoffamily +local getfontoffamily = tex.getfontoffamily -local fontcharacters = fonts.hashes.characters -local extensibles = utilities.storage.allocate() -fonts.hashes.extensibles = extensibles - -local chardata = characters.data -local extensibles = mathematics.extensibles +local fontcharacters = fonts.hashes.characters +local chardata = characters.data +local extensibles = mathematics.extensibles -- we use numbers at the tex end (otherwise we could stick to chars) @@ -722,15 +1171,15 @@ local function extensiblecode(font,unicode) if not char then return unknown end - if character.hvariants then - if character.vvariants then + if character.hparts then + if character.vparts then return { e_mixed, code, character } else local m = char.mathextensible local e = m and extensibles[m] return e and { e, code, character } or unknown end - elseif character.vvariants then + elseif character.vparts then local m = char.mathextensible local e = m and extensibles[m] return e and { e, code, character } or unknown @@ -772,19 +1221,19 @@ local function horizontalcode(family,unicode) local loffset = 0 local roffset = 0 if kind == e_left then - local charlist = data[3].hvariants + local charlist = data[3].hparts if charlist then local left = charlist[1] loffset = abs((left["start"] or 0) - (left["end"] or 0)) end elseif kind == e_right then - local charlist = data[3].hvariants + local charlist = data[3].hparts if charlist then local right = charlist[#charlist] roffset = abs((right["start"] or 0) - (right["end"] or 0)) end elseif kind == e_horizontal then - local charlist = data[3].hvariants + local charlist = data[3].hparts if charlist then local left = charlist[1] local right = charlist[#charlist] @@ -815,7 +1264,6 @@ interfaces.implement { -- can be public with two times "integerargument" end } - local stack = { } function mathematics.registerfallbackid(n,id,name) |