diff options
Diffstat (limited to 'tex/context/base/mkxl/math-act.lmt')
-rw-r--r-- | tex/context/base/mkxl/math-act.lmt | 636 |
1 files changed, 444 insertions, 192 deletions
diff --git a/tex/context/base/mkxl/math-act.lmt b/tex/context/base/mkxl/math-act.lmt index 19464b522..d1a6b80e1 100644 --- a/tex/context/base/mkxl/math-act.lmt +++ b/tex/context/base/mkxl/math-act.lmt @@ -28,6 +28,9 @@ local mathematics = mathematics local texsetdimen = tex.setdimen local abs = math.abs +local blocks = characters.blocks +local stepper = utilities.parsers.stepper + local helpers = fonts.helpers local upcommand = helpers.commands.up local rightcommand = helpers.commands.right @@ -41,6 +44,10 @@ local appendaction = sequencers.appendaction local fontchars = fonts.hashes.characters local fontproperties = fonts.hashes.properties +local mathgaps = mathematics.gaps + +local use_math_goodies = true directives.register("math.nogoodies", function(v) use_math_goodies = not v end) + local mathfontparameteractions = sequencers.new { name = "mathparameters", arguments = "target,original", @@ -76,6 +83,12 @@ function mathematics.initializeparameters(target,original) 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 + if not mathparameters.AccentTopOvershoot then mathparameters.AccentTopOvershoot = 0 end + if not mathparameters.AccentBottomOvershoot then mathparameters.AccentBottomOvershoot = 0 end + if not mathparameters.AccentSuperscriptDrop then mathparameters.AccentSuperscriptDrop = 0 end + if not mathparameters.AccentSuperscriptPercent then mathparameters.AccentSuperscriptPercent = 0 end + if not mathparameters.DelimiterPercent then mathparameters.DelimiterPercent = 100 end + if not mathparameters.DelimiterShortfall then mathparameters.DelimiterShortfall = 0 end -- -- we don't want to reset that each time .. but then we also can't show what the value was -- @@ -97,6 +110,10 @@ local how = { NoLimitSubFactor = "unscaled", PrimeRaisePercent = "unscaled", PrimeWidthPercent = "unscaled", + AccentTopOvershoot = "unscaled", + AccentBottomOvershoot = "unscaled", + AccentSuperscriptPercent = "unscaled", + DelimiterPercent = "unscaled", } function mathematics.scaleparameters(target,original) @@ -157,62 +174,64 @@ end -- end function mathematics.overloadparameters(target,original) - local mathparameters = target.mathparameters - if mathparameters and next(mathparameters) then - local goodies = target.goodies - if goodies then - for i=1,#goodies do - local goodie = goodies[i] - local mathematics = goodie.mathematics - 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 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 + if use_math_goodies then + local mathparameters = target.mathparameters + if mathparameters and next(mathparameters) then + local goodies = target.goodies + if goodies then + for i=1,#goodies do + local goodie = goodies[i] + local mathematics = goodie.mathematics + 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 - if trace_defining and oldvalue ~= newvalue then - report_math("overloading math parameter %a: %S => %S",name,oldvalue or 0,newvalue) + for name, value in next, parameters do + local tvalue = type(value) + local oldvalue = mathparameters[name] + local newvalue = oldvalue + 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 - 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) + 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 - end - if bigslots then - target.bigslots = bigslots + if bigslots then + target.bigslots = bigslots + end end end end @@ -241,14 +260,31 @@ local function report_tweak(fmt,target,original,...) end end -do +-- { +-- tweak = "dimensions", +-- list = { +-- ["lowercasegreeksansserifbolditalic"] = { +-- -- delta = 0x003B1 - 0x1D7AA, +-- slant = -0.2, +-- line = 0.1, +-- mode = 1, +-- width = 0.675, +-- -- scale = 0.975, +-- squeeze = 0.975, +-- extend = .7, +-- }, +-- }, +-- }, - local stepper = utilities.parsers.stepper - local count = 0 +do + local stepper = utilities.parsers.stepper + local count = 0 local splitter = lpeg.tsplitat(".") + local toeffect = fonts.toeffect local function adapt(list,target,original,targetcharacters,originalcharacters,k,v,compact,n) + k = mathgaps[k] or k local character = targetcharacters[k] if character then if not character.tweaked then @@ -257,77 +293,81 @@ do v = list[v] t = type(v) end - if t == "table" then + if t == "table" and next(v) then + local original = v.original + if not original then + local delta = v.delta + if delta then + original = k + delta + end + end + if original then + original = mathgaps[original] or original + local data = targetcharacters[original] + if data then + data = table.copy(data) + data.unicode = original + targetcharacters[k] = data + character = data + else + report_mathtweak("no slot %U",original) + return + end + end + -- 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 + -- + 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 height and height ~= 0 then - if heightfactor then - character.height = heightfactor * height - end + if widthfactor then + character.width = widthfactor * width end - if depth and depthfactor then - character.depth = depthfactor * depth + if xoffsetfactor then + character.xoffset = xoffsetfactor * width end - if yoffsetfactor then - character.yoffset = yoffsetfactor * total + end + if height and height ~= 0 then + if heightfactor then + character.height = heightfactor * height end - if italic and italic ~= 0 and italicfactor then + end + if depth and depthfactor then + character.depth = depthfactor * depth + end + if yoffsetfactor then + character.yoffset = yoffsetfactor * total + end + if italicfactor then + if italic then character.italic = italicfactor * italic + elseif width and italicfactor ~= 1 then + character.italic = italicfactor * width end - if anchorfactor then - character.topaccent = anchorfactor * (topaccent or width) - end end + if anchorfactor then + character.topaccent = anchorfactor * (topaccent or width) + end + -- todo: check once per tweak + character.effect = toeffect(v) if trace_tweaking then report_tweak("adapting dimensions of %U ",target,original,k) end @@ -359,30 +399,60 @@ do end end + -- ["0x7C.variants.*"] = { squeeze = 0.10, height = 0.10, depth = 0.10 }, + 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] + local base = tonumber(t[1]) or tonumber(t[1],16) + if base then + local c = characters[base] if c and n > 1 then - m = t[2] - if m == "parts" then + local list = t[2] + if list == "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 + if c then + local index = t[3] + if index == "*" then + return t + else + index = tonumber(index) + if index then + c = c[index] + if c then + return c.glyph + end + end + end + end + elseif list == "variants" then + local index = t[3] + if index == "*" then + local t = { } + local nxt = c.next + while nxt do + t[#t+1] = nxt + c = characters[nxt] + nxt = c.next + end + return t + else + index = tonumber(index) + if index then + local nxt = c.next + while nxt and index > 1 do + c = characters[nxt] + nxt = c.next + index = index - 1 end + return nxt end end end @@ -405,12 +475,27 @@ do adapt(list,target,original,targetcharacters,originalcharacters,k,v,compact,1) elseif t == "string" then local d = detail(targetcharacters,k) - if d then + local t = type(d) + if t == "table" then + for i=1,#d do + adapt(list,target,original,targetcharacters,originalcharacters,d[i],v,compact,1) + end + elseif t == "number" then adapt(list,target,original,targetcharacters,originalcharacters,d,v,compact,1) + elseif d then + -- some kind of error else - stepper(k,function(n) - adapt(list,target,original,targetcharacters,originalcharacters,n,v,compact,1) - end) + local r = blocks[k] + if r then + local done = false + for i=r.first,r.last do + adapt(list,target,original,targetcharacters,originalcharacters,i,v,compact,1) + end + else + stepper(k,function(n) + adapt(list,target,original,targetcharacters,originalcharacters,n,v,compact,1) + end) + end end -- elseif t == "table" then -- for i=1,#t do @@ -428,6 +513,53 @@ end do + function mathtweaks.wipevariants(target,original,parameters) + local list = parameters.list + if list then + local targetcharacters = target.characters + -- local originalcharacters = original.characters + local count = 0 + for k, v in sortedhash(list) do + local ori = targetcharacters[k] + local nxt = ori.next + local cnt = v + if nxt then + local hpt, vpt + local lst = { } + while nxt do + local chr = targetcharacters[nxt] + lst[#lst+1] = chr + nxt = chr.next + if not nxt then + hpt = chr.hparts + vpt = chr.vparts + break + end + end + if hpt or vpt then + count = count + 1 + if cnt ~= "*" then + if #lst < cnt then + cnt = #lst + end + ori = lst[cnt] + end + ori.hparts = hpt + ori.vparts = vpt + -- ori.next = nil -- so we keep the chain + end + end + end + if trace_tweaking and count > 0 then + report_mathtweak("%i variants wiped",count) + end + end + end + +end + +do + function mathtweaks.replacements(target,original,parameters) local list = parameters.list if list then @@ -441,7 +573,7 @@ do v = unicodes[v] end if type(v) == "number" then - targetcharacters[k] = targetcharacters[v] + targetcharacters[mathgaps[k] or k] = targetcharacters[mathgaps[v] or v] count = count + 1 end end @@ -462,7 +594,7 @@ do for k, v in sortedhash(list) do local sub = getsubstitution(original,k,v,true) if sub then - targetcharacters[k] = targetcharacters[sub] + targetcharacters[mathgaps[k] or k] = targetcharacters[mathgaps[sub] or sub] count = count + 1 end end @@ -669,9 +801,10 @@ end do function mathtweaks.fixanchors(target,original,parameters) - local factor = tonumber(parameters.factor) + local targetcharacters= target.characters + local factor = tonumber(parameters.factor) or 0 if factor ~= 0 then - for k, v in next, target.characters do + for k, v in next, targetcharacters do local a = v.topaccent if a and a > 0 then v.topaccent = a * factor @@ -680,6 +813,76 @@ do end end + -- local default = { + -- "digitsnormal", + -- "lowercasedoublestruck", + -- "uppercasedoublestruck", + -- } + + local function wipe(target,original,parameters,field) + local targetcharacters = target.characters + local function step(s,l) + local done = false + while s do + local c = targetcharacters[mathgaps[s] or s] + if c then + local v = c[field] + if v then + if trace_tweaking then + if l then + report_tweak("removing %a in range %a from %C",target,original,field,l,s) + else + report_tweak("removing %a from %C",target,original,field,s) + end + end + c[field] = nil + done = true + end + s = c.smaller + else + break + end + end + return done + end + local list = parameters.list -- todo: ranges + -- if list == "default" then + -- list = default + -- else + if type(list) == "string" then + list = { list } + end + for i=1,#list do + local l = list[i] + local r = blocks[l] + if r then + local done = false + for i=r.first,r.last do + if step(i,l) then + done = true + end + end + if not done and trace_tweaking then + report_mathtweak("there is no need to remove %a range %a",field,l) + end + else + stepper(l,step) + end + end + end + + function mathtweaks.wipeanchors(target,original,parameters) + wipe(target,original,parameters,"topaccent") + end + + function mathtweaks.wipeitalics(target,original,parameters) + wipe(target,original,parameters,"italic") + end + + -- function mathtweaks.fixdigits(target,original,parameters) + -- mathtweaks.fixanchors(target,original,{ list = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 } }) + -- end + end do @@ -690,17 +893,97 @@ do local kerns = parameters.list if kerns then local characters = target.characters - local function kernone(unicode,data) - local chardata = characters[unicode] - local height = chardata.height or 0 - local depth = chardata.depth or 0 - local width = chardata.width or 0 + local function setone(unicode,data) + local chardata = characters[mathgaps[unicode] or unicode] + local width = chardata.width or 0 local k = data.topleft ; if k and k ~= 0 then chardata.topleft = k * width end local k = data.topright ; if k and k ~= 0 then chardata.topright = k * width end local k = data.bottomleft ; if k and k ~= 0 then chardata.bottomleft = k * width end local k = data.bottomright ; if k and k ~= 0 then chardata.bottomright = k * width end end for unicode, data in next, kerns do + setone(unicode,data) -- withscriptcode(tfmdata,unicode,data,kernone) + -- also smaller + end + end + end + +end + +do + + function mathtweaks.margins(target,original,parameters) + local margins = parameters.list + if margins then + local characters = target.characters + local function setone(unicode,data) + local chardata = characters[mathgaps[unicode] or unicode] + local width = chardata.width or 0 + local total = (chardata.height or 0) + (chardata.depth or 0) + local k = data.left ; if k and k ~= 0 then chardata.leftmargin = k * width end + local k = data.right ; if k and k ~= 0 then chardata.rightmargin = k * width end + local k = data.top ; if k and k ~= 0 then chardata.topmargin = k * total end + local k = data.bottom ; if k and k ~= 0 then chardata.bottommargin = k * total end + end + for unicode, data in next, margins do + setone(unicode,data) -- withscriptcode(tfmdata,unicode,data,kernone) + -- also smaller + end + end + end + +end + +do + + -- musical timestamp: June 2022, Porcupine Tree - Rats Return + + -- we can actually share these and flag them as being tweaked + + local function scale(t,width,total) + local r = { } + for i=1,#t do + local ti = t[i] + local kern = ti.kern + local height = ti.height + if kern then + kern = width * kern + end + if height then + height = total * height + end + r[i] = { + kern = kern or 0, + height = height or 0, + } + end + return r + end + + function mathtweaks.staircase(target,original,parameters) + local kerns = parameters.list + if kerns then + local characters = target.characters + local function kernone(unicode,data) + local chardata = characters[mathgaps[unicode] or unicode] + local total = (chardata.height or 0) + (chardata.depth or 0) + local width = chardata.width or 0 + if data then + local tl = data.topleft ; if tl then tl = scale(tl,width,total) end + local tr = data.topright ; if tr then tr = scale(tr,width,total) end + local bl = data.bottomleft ; if bl then bl = scale(bl,width,total) end + local br = data.bottomright ; if br then br = scale(br,width,total) end + chardata.mathkerns = { + topleft = tl, + ropright = tr, + bottomleft = bl, + bottomright = br, + } + else + chardata.mathkerns = nil + end + end + for unicode, data in next, kerns do kernone(unicode,data) -- withscriptcode(tfmdata,unicode,data,kernone) -- also smaller end @@ -773,16 +1056,14 @@ do 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 + elseif 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 c.yoffset = yoffset ~= 0 and yoffset or nil c.height = height > 0 and height or nil @@ -791,7 +1072,7 @@ do end end - local function process(characters,list,baseheight,basedepth) + local function process(target,original,characters,list,baseheight,basedepth) if list then for k, v in sortedhash(list) do -- sort for tracing local c = characters[k] @@ -826,7 +1107,7 @@ do end end if trace_tweaking then - report_tweak("adapting extensible (%i sizes, %i parts) %U",k,nv,ns) + report_tweak("adapting extensible (%i sizes, %i parts) %U",target,original,k,nv,ns) end end end @@ -847,7 +1128,7 @@ do t = type(v) end if t == "table" then - process(characters,v,baseheight,basedepth) + process(target,original,characters,v,baseheight,basedepth) end end end @@ -1075,7 +1356,7 @@ do unicode = unicode, } if trace_tweaking then - report_tweak("character %U has been wiped",unicode) + report_tweak("character %U has been wiped",target,original,unicode) end end end @@ -1134,41 +1415,6 @@ do end --- do --- --- local list = { --- { 0x00AF, 1 }, --- } --- --- local minint = -2147483647 - 1 --- --- local function fix(target,original,targetcharacters,unicode,factor) --- local chardata = targetcharacters[unicode] --- if chardata and factor then --- local accent = chardata.topaccent --- if not accent then --- local width = chardata.width or 0 --- local accent = (tonumber(factor) and factor * width) or (factor and minint) --- chardata.topaccent = accent --- if trace_tweaking then --- report_tweak("fixing accent %U",target,original,unicode) --- end --- end --- end --- end --- --- function mathtweaks.fixaccents(target,original,parameters) --- local targetcharacters = target.characters --- for i=1,#list do --- local entry = list[i] --- if entry then --- fix(target,original,targetcharacters,entry[1],entry[2]) --- end --- end --- end --- --- end - do local reported = { } @@ -1239,16 +1485,20 @@ local function applytweaks(when,target,original) end function mathematics.tweakbeforecopyingfont(target,original) - local mathparameters = target.mathparameters -- why not hasmath - if mathparameters then - applytweaks("beforecopying",target,original) + if use_math_goodies then + local mathparameters = target.mathparameters -- why not hasmath + if mathparameters then + applytweaks("beforecopying",target,original) + end end end function mathematics.tweakaftercopyingfont(target,original) - local mathparameters = target.mathparameters -- why not hasmath - if mathparameters then - applytweaks("aftercopying",target,original) + if use_math_goodies then + local mathparameters = target.mathparameters -- why not hasmath + if mathparameters then + applytweaks("aftercopying",target,original) + end end end @@ -1282,6 +1532,8 @@ local e_unknown = extensibles.unknown local unknown = { e_unknown, false, false } +-- top curly bracket: 23DE + local function extensiblecode(font,unicode) local characters = fontcharacters[font] local character = characters[unicode] |