diff options
Diffstat (limited to 'Master/texmf-dist/tex/context/base/math-noa.lua')
-rw-r--r-- | Master/texmf-dist/tex/context/base/math-noa.lua | 1304 |
1 files changed, 0 insertions, 1304 deletions
diff --git a/Master/texmf-dist/tex/context/base/math-noa.lua b/Master/texmf-dist/tex/context/base/math-noa.lua deleted file mode 100644 index cdbbe36c377..00000000000 --- a/Master/texmf-dist/tex/context/base/math-noa.lua +++ /dev/null @@ -1,1304 +0,0 @@ -if not modules then modules = { } end modules ['math-noa'] = { - 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" -} - --- beware: this is experimental code and there will be a more --- generic (attribute value driven) interface too but for the --- moment this is ok --- --- we will also make dedicated processors (faster) --- --- beware: names will change as we wil make noads.xxx.handler i.e. xxx --- subnamespaces - --- 20D6 -> 2190 --- 20D7 -> 2192 - -local utfchar, utfbyte = utf.char, utf.byte -local formatters = string.formatters -local div = math.div - -local fonts, nodes, node, mathematics = fonts, nodes, node, mathematics - -local otf = fonts.handlers.otf -local otffeatures = fonts.constructors.newfeatures("otf") -local registerotffeature = otffeatures.register - -local privateattribute = attributes.private -local registertracker = trackers.register -local registerdirective = directives.register -local logreporter = logs.reporter - -local trace_remapping = false registertracker("math.remapping", function(v) trace_remapping = v end) -local trace_processing = false registertracker("math.processing", function(v) trace_processing = v end) -local trace_analyzing = false registertracker("math.analyzing", function(v) trace_analyzing = v end) -local trace_normalizing = false registertracker("math.normalizing", function(v) trace_normalizing = v end) -local trace_collapsing = false registertracker("math.collapsing", function(v) trace_collapsing = v end) -local trace_patching = false registertracker("math.patching", function(v) trace_patching = v end) -local trace_goodies = false registertracker("math.goodies", function(v) trace_goodies = v end) -local trace_variants = false registertracker("math.variants", function(v) trace_variants = v end) -local trace_alternates = false registertracker("math.alternates", function(v) trace_alternates = v end) -local trace_italics = false registertracker("math.italics", function(v) trace_italics = v end) -local trace_families = false registertracker("math.families", function(v) trace_families = v end) - -local check_coverage = true registerdirective("math.checkcoverage", function(v) check_coverage = v end) - -local report_processing = logreporter("mathematics","processing") -local report_remapping = logreporter("mathematics","remapping") -local report_normalizing = logreporter("mathematics","normalizing") -local report_collapsing = logreporter("mathematics","collapsing") -local report_patching = logreporter("mathematics","patching") -local report_goodies = logreporter("mathematics","goodies") -local report_variants = logreporter("mathematics","variants") -local report_alternates = logreporter("mathematics","alternates") -local report_italics = logreporter("mathematics","italics") -local report_families = logreporter("mathematics","families") - -local a_mathrendering = privateattribute("mathrendering") -local a_exportstatus = privateattribute("exportstatus") - -local nuts = nodes.nuts -local nodepool = nuts.pool -local tonut = nuts.tonut -local nutstring = nuts.tostring - -local getfield = nuts.getfield -local setfield = nuts.setfield -local getnext = nuts.getnext -local getprev = nuts.getprev -local getid = nuts.getid -local getfont = nuts.getfont -local getsubtype = nuts.getsubtype -local getchar = nuts.getchar -local getattr = nuts.getattr -local setattr = nuts.setattr - -local insert_node_after = nuts.insert_after -local insert_node_before = nuts.insert_before -local free_node = nuts.free -local new_node = nuts.new -- todo: pool: math_noad math_sub -local copy_node = nuts.copy - -local mlist_to_hlist = nodes.mlist_to_hlist - -local font_of_family = node.family_font - -local new_kern = nodepool.kern -local new_rule = nodepool.rule - -local fonthashes = fonts.hashes -local fontdata = fonthashes.identifiers -local fontcharacters = fonthashes.characters -local fontproperties = fonthashes.properties -local fontitalics = fonthashes.italics -local fontemwidths = fonthashes.emwidths -local fontexheights = fonthashes.exheights - -local variables = interfaces.variables -local texsetattribute = tex.setattribute -local texgetattribute = tex.getattribute -local unsetvalue = attributes.unsetvalue - -local chardata = characters.data - -noads = noads or { } -- todo: only here -local noads = noads - -noads.processors = noads.processors or { } -local processors = noads.processors - -noads.handlers = noads.handlers or { } -local handlers = noads.handlers - -local tasks = nodes.tasks - -local nodecodes = nodes.nodecodes -local noadcodes = nodes.noadcodes - -local noad_ord = noadcodes.ord -local noad_rel = noadcodes.rel -local noad_punct = noadcodes.punct -local noad_opdisplaylimits= noadcodes.opdisplaylimits -local noad_oplimits = noadcodes.oplimits -local noad_opnolimits = noadcodes.opnolimits - -local math_noad = nodecodes.noad -- attr nucleus sub sup -local math_accent = nodecodes.accent -- attr nucleus sub sup accent -local math_radical = nodecodes.radical -- attr nucleus sub sup left degree -local math_fraction = nodecodes.fraction -- attr nucleus sub sup left right -local math_box = nodecodes.subbox -- attr list -local math_sub = nodecodes.submlist -- attr list -local math_char = nodecodes.mathchar -- attr fam char -local math_textchar = nodecodes.mathtextchar -- attr fam char -local math_delim = nodecodes.delim -- attr small_fam small_char large_fam large_char -local math_style = nodecodes.style -- attr style -local math_choice = nodecodes.choice -- attr display text script scriptscript -local math_fence = nodecodes.fence -- attr subtype - -local hlist_code = nodecodes.hlist -local glyph_code = nodecodes.glyph - -local left_fence_code = 1 -local right_fence_code = 3 - -local function process(start,what,n,parent) - if n then n = n + 1 else n = 0 end - local prev = nil - while start do - local id = getid(start) - if trace_processing then - if id == math_noad then - report_processing("%w%S, class %a",n*2,nutstring(start),noadcodes[getsubtype(start)]) - elseif id == math_char then - local char = getchar(start) - local fam = getfield(start,"fam") - local font = font_of_family(fam) - report_processing("%w%S, family %a, font %a, char %a, shape %c",n*2,nutstring(start),fam,font,char,char) - else - report_processing("%w%S",n*2,nutstring(start)) - end - end - local proc = what[id] - if proc then - -- report_processing("start processing") - local done, newstart = proc(start,what,n,parent) -- prev is bugged: or getprev(start) - if newstart then - start = newstart - -- report_processing("stop processing (new start)") - else - -- report_processing("stop processing") - end - elseif id == math_char or id == math_textchar or id == math_delim then - break - elseif id == math_noad then -if prev then - -- we have no proper prev in math nodes yet - setfield(start,"prev",prev) -end - - local noad = getfield(start,"nucleus") if noad then process(noad,what,n,start) end -- list - noad = getfield(start,"sup") if noad then process(noad,what,n,start) end -- list - noad = getfield(start,"sub") if noad then process(noad,what,n,start) end -- list - elseif id == math_box or id == math_sub then - local noad = getfield(start,"list") if noad then process(noad,what,n,start) end -- list (not getlist !) - elseif id == math_fraction then - local noad = getfield(start,"num") if noad then process(noad,what,n,start) end -- list - noad = getfield(start,"denom") if noad then process(noad,what,n,start) end -- list - noad = getfield(start,"left") if noad then process(noad,what,n,start) end -- delimiter - noad = getfield(start,"right") if noad then process(noad,what,n,start) end -- delimiter - elseif id == math_choice then - local noad = getfield(start,"display") if noad then process(noad,what,n,start) end -- list - noad = getfield(start,"text") if noad then process(noad,what,n,start) end -- list - noad = getfield(start,"script") if noad then process(noad,what,n,start) end -- list - noad = getfield(start,"scriptscript") if noad then process(noad,what,n,start) end -- list - elseif id == math_fence then - local noad = getfield(start,"delim") if noad then process(noad,what,n,start) end -- delimiter - elseif id == math_radical then - local noad = getfield(start,"nucleus") if noad then process(noad,what,n,start) end -- list - noad = getfield(start,"sup") if noad then process(noad,what,n,start) end -- list - noad = getfield(start,"sub") if noad then process(noad,what,n,start) end -- list - noad = getfield(start,"left") if noad then process(noad,what,n,start) end -- delimiter - noad = getfield(start,"degree") if noad then process(noad,what,n,start) end -- list - elseif id == math_accent then - local noad = getfield(start,"nucleus") if noad then process(noad,what,n,start) end -- list - noad = getfield(start,"sup") if noad then process(noad,what,n,start) end -- list - noad = getfield(start,"sub") if noad then process(noad,what,n,start) end -- list - noad = getfield(start,"accent") if noad then process(noad,what,n,start) end -- list - noad = getfield(start,"bot_accent") if noad then process(noad,what,n,start) end -- list - elseif id == math_style then - -- has a next - else - -- glue, penalty, etc - end -prev = start - start = getnext(start) - end -end - -local function processnoads(head,actions,banner) - if trace_processing then - report_processing("start %a",banner) - process(tonut(head),actions) - report_processing("stop %a",banner) - else - process(tonut(head),actions) - end -end - -noads.process = processnoads - --- - -local unknowns = { } -local checked = { } -- simple case -local tracked = false trackers.register("fonts.missing", function(v) tracked = v end) -local cached = table.setmetatableindex("table") -- complex case - -local function errorchar(font,char) - local done = unknowns[char] - if done then - unknowns[char] = done + 1 - else - unknowns[char] = 1 - end - if tracked then - -- slower as we check each font too and we always replace as math has - -- more demands than text - local fake = cached[font][char] - if fake then - return fake - else - local kind, fake = fonts.checkers.placeholder(font,char) - if not fake or kind ~= "char" then - fake = 0x3F - end - cached[font][char] = fake - return fake - end - else - -- only simple checking, report at the end so one should take - -- action anyway ... we can miss a few checks but that is ok - -- as there is at least one reported - if not checked[char] then - if trace_normalizing then - report_normalizing("character %C is not available",char) - end - checked[char] = true - end - return 0x3F - end -end - --- experiment (when not present fall back to fam 0) -- needs documentation - --- 0-2 regular --- 3-5 bold --- 6-8 pseudobold - --- this could best be integrated in the remapper, and if we run into problems, we --- might as well do this - -local families = { } -local a_mathfamily = privateattribute("mathfamily") -local boldmap = mathematics.boldmap - -local familymap = { [0] = - "regular", - "regular", - "regular", - "bold", - "bold", - "bold", - "pseudobold", - "pseudobold", - "pseudobold", -} - -families[math_char] = function(pointer) - if getfield(pointer,"fam") == 0 then - local a = getattr(pointer,a_mathfamily) - if a and a > 0 then - setattr(pointer,a_mathfamily,0) - if a > 5 then - local char = getchar(pointer) - local bold = boldmap[char] - local newa = a - 3 - if not bold then - if trace_families then - report_families("no bold replacement for %C, family %s with remap %s becomes %s with remap %s",char,a,familymap[a],newa,familymap[newa]) - end - setfield(pointer,"fam",newa) - elseif not fontcharacters[font_of_family(newa)][bold] then - if trace_families then - report_families("no bold character for %C, family %s with remap %s becomes %s with remap %s",char,a,familymap[a],newa,familymap[newa]) - end - if newa > 3 then - setfield(pointer,"fam",newa-3) - end - else - setattr(pointer,a_exportstatus,char) - setfield(pointer,"char",bold) - if trace_families then - report_families("replacing %C by bold %C, family %s with remap %s becomes %s with remap %s",char,bold,a,familymap[a],newa,familymap[newa]) - end - setfield(pointer,"fam",newa) - end - else - local char = getchar(pointer) - if not fontcharacters[font_of_family(a)][char] then - if trace_families then - report_families("no bold replacement for %C",char) - end - else - if trace_families then - report_families("family of %C becomes %s with remap %s",char,a,familymap[a]) - end - setfield(pointer,"fam",a) - end - end - end - end -end - -families[math_delim] = function(pointer) - if getfield(pointer,"small_fam") == 0 then - local a = getattr(pointer,a_mathfamily) - if a and a > 0 then - setattr(pointer,a_mathfamily,0) - if a > 5 then - -- no bold delimiters in unicode - a = a - 3 - end - local char = getfield(pointer,"small_char") - local okay = fontcharacters[font_of_family(a)][char] - if okay then - setfield(pointer,"small_fam",a) - elseif a > 2 then - setfield(pointer,"small_fam",a-3) - end - local char = getfield(pointer,"large_char") - local okay = fontcharacters[font_of_family(a)][char] - if okay then - setfield(pointer,"large_fam",a) - elseif a > 2 then - setfield(pointer,"large_fam",a-3) - end - else - setfield(pointer,"small_fam",0) - setfield(pointer,"large_fam",0) - end - end -end - -families[math_textchar] = families[math_char] - -function handlers.families(head,style,penalties) - processnoads(head,families,"families") - return true -end - --- character remapping - -local a_mathalphabet = privateattribute("mathalphabet") -local a_mathgreek = privateattribute("mathgreek") - -processors.relocate = { } - -local function report_remap(tag,id,old,new,extra) - report_remapping("remapping %s in font %s from %C to %C%s",tag,id,old,new,extra) -end - -local remapalphabets = mathematics.remapalphabets -local fallbackstyleattr = mathematics.fallbackstyleattr -local setnodecolor = nodes.tracers.colors.set - -local function checked(pointer) - local char = getchar(pointer) - local fam = getfield(pointer,"fam") - local id = font_of_family(fam) - local tc = fontcharacters[id] - if not tc[char] then - local specials = characters.data[char].specials - if specials and (specials[1] == "char" or specials[1] == "font") then - newchar = specials[#specials] - if trace_remapping then - report_remap("fallback",id,char,newchar) - end - if trace_analyzing then - setnodecolor(pointer,"font:isol") - end - setattr(pointer,a_exportstatus,char) -- testcase: exponentiale - setfield(pointer,"char",newchar) - return true - end - end -end - -processors.relocate[math_char] = function(pointer) - local g = getattr(pointer,a_mathgreek) or 0 - local a = getattr(pointer,a_mathalphabet) or 0 - local char = getchar(pointer) - local fam = getfield(pointer,"fam") - local font = font_of_family(fam) - local characters = fontcharacters[font] - if a > 0 or g > 0 then - if a > 0 then - setattr(pointer,a_mathgreek,0) - end - if g > 0 then - setattr(pointer,a_mathalphabet,0) - end - local newchar = remapalphabets(char,a,g) - if newchar then - if characters[newchar] then - if trace_remapping then - report_remap("char",font,char,newchar) - end - if trace_analyzing then - setnodecolor(pointer,"font:isol") - end - setfield(pointer,"char",newchar) - return true - else - local fallback = fallbackstyleattr(a) - if fallback then - local newchar = remapalphabets(char,fallback,g) - if newchar then - if characters[newchar] then - if trace_remapping then - report_remap("char",font,char,newchar," (fallback remapping used)") - end - if trace_analyzing then - setnodecolor(pointer,"font:isol") - end - setfield(pointer,"char",newchar) - return true - elseif trace_remapping then - report_remap("char",font,char,newchar," fails (no fallback character)") - end - elseif trace_remapping then - report_remap("char",font,char,newchar," fails (no fallback remap character)") - end - elseif trace_remapping then - report_remap("char",font,char,newchar," fails (no fallback style)") - end - end - end - end - if not characters[char] then - setfield(pointer,"char",errorchar(font,char)) - end - if trace_analyzing then - setnodecolor(pointer,"font:medi") - end - if check_coverage then - return checked(pointer) - end -end - -processors.relocate[math_textchar] = function(pointer) - if trace_analyzing then - setnodecolor(pointer,"font:init") - end -end - -processors.relocate[math_delim] = function(pointer) - if trace_analyzing then - setnodecolor(pointer,"font:fina") - end -end - -function handlers.relocate(head,style,penalties) - processnoads(head,processors.relocate,"relocate") - return true -end - --- rendering (beware, not exported) - -processors.render = { } - -local rendersets = mathematics.renderings.numbers or { } -- store - -processors.render[math_char] = function(pointer) - local attr = getattr(pointer,a_mathrendering) - if attr and attr > 0 then - local char = getchar(pointer) - local renderset = rendersets[attr] - if renderset then - local newchar = renderset[char] - if newchar then - local fam = getfield(pointer,"fam") - local font = font_of_family(fam) - local characters = fontcharacters[font] - if characters and characters[newchar] then - setfield(pointer,"char",newchar) - setattr(pointer,a_exportstatus,char) - end - end - end - end -end - -function handlers.render(head,style,penalties) - processnoads(head,processors.render,"render") - return true -end - --- some resize options (this works ok because the content is --- empty and no larger next will be forced) --- --- beware: we don't use \delcode but \Udelcode and as such have --- no large_fam; also, we need to check for subtype and/or --- small_fam not being 0 because \. sits in 0,0 by default --- --- todo: just replace the character by an ord noad --- and remove the right delimiter as well - -local mathsize = privateattribute("mathsize") - -local resize = { } processors.resize = resize - -resize[math_fence] = function(pointer) - local subtype = getsubtype(pointer) - if subtype == left_fence_code or subtype == right_fence_code then - local a = getattr(pointer,mathsize) - if a and a > 0 then - local method, size = div(a,100), a % 100 - setattr(pointer,mathsize,0) - local delimiter = getfield(pointer,"delim") - local chr = getfield(delimiter,"small_char") - if chr > 0 then - local fam = getfield(delimiter,"small_fam") - local id = font_of_family(fam) - if id > 0 then - setfield(delimiter,"small_char",mathematics.big(fontdata[id],chr,size,method)) - end - end - end - end -end - -function handlers.resize(head,style,penalties) - processnoads(head,resize,"resize") - return true -end - --- normalize scripts - -local unscript = { } noads.processors.unscript = unscript -local superscripts = characters.superscripts -local subscripts = characters.subscripts -local fractions = characters.fractions -local replaced = { } - -local function replace(pointer,what,n,parent) - pointer = parent -- we're following the parent list (chars trigger this) - local next = getnext(pointer) - local start_super, stop_super, start_sub, stop_sub - local mode = "unset" - while next and getid(next) == math_noad do - local nextnucleus = getfield(next,"nucleus") - if nextnucleus and getid(nextnucleus) == math_char and not getfield(next,"sub") and not getfield(next,"sup") then - local char = getchar(nextnucleus) - local s = superscripts[char] - if s then - if not start_super then - start_super = next - mode = "super" - elseif mode == "sub" then - break - end - stop_super = next - next = getnext(next) - setfield(nextnucleus,"char",s) - replaced[char] = (replaced[char] or 0) + 1 - if trace_normalizing then - report_normalizing("superscript %C becomes %C",char,s) - end - else - local s = subscripts[char] - if s then - if not start_sub then - start_sub = next - mode = "sub" - elseif mode == "super" then - break - end - stop_sub = next - next = getnext(next) - setfield(nextnucleus,"char",s) - replaced[char] = (replaced[char] or 0) + 1 - if trace_normalizing then - report_normalizing("subscript %C becomes %C",char,s) - end - else - break - end - end - else - break - end - end - if start_super then - if start_super == stop_super then - setfield(pointer,"sup",getfield(start_super,"nucleus")) - else - local list = new_node(math_sub) -- todo attr - setfield(list,"list",start_super) - setfield(pointer,"sup",list) - end - if mode == "super" then - setfield(pointer,"next",getnext(stop_super)) - end - setfield(stop_super,"next",nil) - end - if start_sub then - if start_sub == stop_sub then - setfield(pointer,"sub",getfield(start_sub,"nucleus")) - else - local list = new_node(math_sub) -- todo attr - setfield(list,"list",start_sub) - setfield(pointer,"sub",list) - end - if mode == "sub" then - setfield(pointer,"next",getnext(stop_sub)) - end - setfield(stop_sub,"next",nil) - end - -- we could return stop -end - -unscript[math_char] = replace -- not noads as we need to recurse - -function handlers.unscript(head,style,penalties) - processnoads(head,unscript,"unscript") --- processnoads(head,checkers,"checkers") - return true -end - -local function collected(list) - if list and next(list) then - local n, t = 0, { } - for k, v in table.sortedpairs(list) do - n = n + v - t[#t+1] = formatters["%C"](k) - end - return formatters["% t (n=%s)"](t,n) - end -end - -statistics.register("math script replacements", function() - return collected(replaced) -end) - -statistics.register("unknown math characters", function() - return collected(unknowns) -end) - --- math alternates: (in xits lgf: $ABC$ $\cal ABC$ $\mathalternate{cal}\cal ABC$) --- math alternates: (in lucidanova lgf: $ABC \mathalternate{italic} ABC$) - --- todo: set alternate for specific symbols - -local function initializemathalternates(tfmdata) - local goodies = tfmdata.goodies - if goodies then - local shared = tfmdata.shared - for i=1,#goodies do - -- first one counts - -- we can consider sharing the attributes ... todo (only once scan) - local mathgoodies = goodies[i].mathematics - local alternates = mathgoodies and mathgoodies.alternates - if alternates then - if trace_goodies then - report_goodies("loading alternates for font %a",tfmdata.properties.name) - end - local lastattribute, attributes = 0, { } - for k, v in next, alternates do - lastattribute = lastattribute + 1 - v.attribute = lastattribute - attributes[lastattribute] = v - end - shared.mathalternates = alternates -- to be checked if shared is ok here - shared.mathalternatesattributes = attributes -- to be checked if shared is ok here - return - end - end - end -end - -registerotffeature { - name = "mathalternates", - description = "additional math alternative shapes", - initializers = { - base = initializemathalternates, - node = initializemathalternates, - } -} - -local getalternate = otf.getalternate - -local a_mathalternate = privateattribute("mathalternate") - -local alternate = { } -- processors.alternate = alternate - -function mathematics.setalternate(fam,tag) - local id = font_of_family(fam) - local tfmdata = fontdata[id] - local mathalternates = tfmdata.shared and tfmdata.shared.mathalternates - if mathalternates then - local m = mathalternates[tag] - texsetattribute(a_mathalternate,m and m.attribute or unsetvalue) - end -end - -alternate[math_char] = function(pointer) - local a = getattr(pointer,a_mathalternate) - if a and a > 0 then - setattr(pointer,a_mathalternate,0) - local tfmdata = fontdata[font_of_family(getfield(pointer,"fam"))] -- we can also have a famdata - local mathalternatesattributes = tfmdata.shared.mathalternatesattributes - if mathalternatesattributes then - local what = mathalternatesattributes[a] - local alt = getalternate(tfmdata,getchar(pointer),what.feature,what.value) - if alt then - if trace_alternates then - report_alternates("alternate %a, value %a, replacing glyph %U by glyph %U", - tostring(what.feature),tostring(what.value),getchar(pointer),alt) - end - setfield(pointer,"char",alt) - end - end - end -end - -function handlers.check(head,style,penalties) - processnoads(head,alternate,"check") - return true -end - --- italics: we assume that only characters matter --- --- = we check for correction first because accessing nodes is slower --- = the actual glyph is not that important (we can control it with numbers) - --- Italic correction in luatex math is a mess. There are all kind of assumptions based on --- old fonts and new font. Eventually there should be a flag that can signal to ignore all --- those heuristics. We want to deal with it ourselves also in the perspective of mxed math --- and text. - -local a_mathitalics = privateattribute("mathitalics") - -local italics = { } -local default_factor = 1/20 - -local function getcorrection(method,font,char) -- -- or character.italic -- (this one is for tex) - - local correction, fromvisual - - if method == 1 then - -- only font data triggered by fontitalics - local italics = fontitalics[font] - if italics then - local character = fontcharacters[font][char] - if character then - correction = character.italic_correction - if correction and correction ~= 0 then - return correction, false - end - end - end - elseif method == 2 then - -- only font data triggered by fontdata - local character = fontcharacters[font][char] - if character then - correction = character.italic_correction - if correction and correction ~= 0 then - return correction, false - end - end - elseif method == 3 then - -- only quad based by selective - local visual = chardata[char].visual - if not visual then - -- skip - elseif visual == "it" or visual == "bi" then - correction = fontproperties[font].mathitalic_defaultvalue or default_factor*fontemwidths[font] - if correction and correction ~= 0 then - return correction, true - end - end - elseif method == 4 then - -- combination of 1 and 3 - local italics = fontitalics[font] - if italics then - local character = fontcharacters[font][char] - if character then - correction = character.italic_correction - if correction and correction ~= 0 then - return correction, false - end - end - end - if not correction then - local visual = chardata[char].visual - if not visual then - -- skip - elseif visual == "it" or visual == "bi" then - correction = fontproperties[font].mathitalic_defaultvalue or default_factor*fontemwidths[font] - if correction and correction ~= 0 then - return correction, true - end - end - end - end - -end - -local setcolor = nodes.tracers.colors.set -local resetcolor = nodes.tracers.colors.reset -local italic_kern = new_kern -local c_positive_d = "trace:db" -local c_negative_d = "trace:dr" - -local function insert_kern(current,kern) - local sub = new_node(math_sub) -- todo: pool - local noad = new_node(math_noad) -- todo: pool - setfield(sub,"list",kern) - setfield(kern,"next",noad) - setfield(noad,"nucleus",current) - return sub -end - -registertracker("math.italics.visualize", function(v) - if v then - italic_kern = function(k,font) - local ex = 1.5 * fontexheights[font] - if k > 0 then - return setcolor(new_rule(k,ex,ex),c_positive_d) - else - -- influences un* - return old_kern(k) .. setcolor(new_rule(-k,ex,ex),c_negative_d) .. old_kern(k) - end - end - else - italic_kern = new_kern - end -end) - -italics[math_char] = function(pointer,what,n,parent) - local method = getattr(pointer,a_mathitalics) - if method and method > 0 then - local char = getchar(pointer) - local font = font_of_family(getfield(pointer,"fam")) -- todo: table - local correction, visual = getcorrection(method,font,char) - if correction then - local pid = getid(parent) - local sub, sup - if pid == math_noad then - sup = getfield(parent,"sup") - sub = getfield(parent,"sub") - end - if sup or sub then - local subtype = getsubtype(parent) - if subtype == noad_oplimits then - if sup then - setfield(parent,"sup",insert_kern(sup,italic_kern(correction,font))) - if trace_italics then - report_italics("method %a, adding %p italic correction for upper limit of %C",method,correction,char) - end - end - if sub then - local correction = - correction - setfield(parent,"sub",insert_kern(sub,italic_kern(correction,font))) - if trace_italics then - report_italics("method %a, adding %p italic correction for lower limit of %C",method,correction,char) - end - end - elseif sup then - if pointer ~= sub then - setfield(parent,"sup",insert_kern(sup,italic_kern(correction,font))) - if trace_italics then - report_italics("method %a, adding %p italic correction before superscript after %C",method,correction,char) - end - else - -- otherwise we inject twice - end - end - else - local next_noad = getnext(parent) - if not next_noad then - if n== 1 then -- only at the outer level .. will become an option (always,endonly,none) - if trace_italics then - report_italics("method %a, adding %p italic correction between %C and end math",method,correctio,char) - end - insert_node_after(parent,parent,italic_kern(correction,font)) - end - elseif getid(next_noad) == math_noad then - local next_subtype = getsubtype(next_noad) - if next_subtype == noad_punct or next_subtype == noad_ord then - local next_nucleus = getfield(next_noad,"nucleus") - if getid(next_nucleus) == math_char then - local next_char = getchar(next_nucleus) - local next_data = chardata[next_char] - local visual = next_data.visual - if visual == "it" or visual == "bi" then - -- if trace_italics then - -- report_italics("method %a, skipping %p italic correction between italic %C and italic %C",method,correction,char,next_char) - -- end - else - local category = next_data.category - if category == "nd" or category == "ll" or category == "lu" then - if trace_italics then - report_italics("method %a, adding %p italic correction between italic %C and non italic %C",method,correction,char,next_char) - end - insert_node_after(parent,parent,italic_kern(correction,font)) - -- elseif next_data.height > (fontexheights[font]/2) then - -- if trace_italics then - -- report_italics("method %a, adding %p italic correction between %C and ascending %C",method,correction,char,next_char) - -- end - -- insert_node_after(parent,parent,italic_kern(correction,font)) - -- elseif trace_italics then - -- -- report_italics("method %a, skipping %p italic correction between %C and %C",method,correction,char,next_char) - end - end - end - end - end - end - end - end -end - -function handlers.italics(head,style,penalties) - processnoads(head,italics,"italics") - return true -end - -local enable - -enable = function() - tasks.enableaction("math", "noads.handlers.italics") - if trace_italics then - report_italics("enabling math italics") - end - enable = false -end - --- best do this only on math mode (less overhead) - -function mathematics.setitalics(n) - if enable then - enable() - end - if n == variables.reset then - texsetattribute(a_mathitalics,unsetvalue) - else - texsetattribute(a_mathitalics,tonumber(n) or unsetvalue) - end -end - -function mathematics.resetitalics() - texsetattribute(a_mathitalics,unsetvalue) -end - --- primes and such - -local collapse = { } processors.collapse = collapse - -local mathpairs = characters.mathpairs - -mathpairs[0x2032] = { [0x2032] = 0x2033, [0x2033] = 0x2034, [0x2034] = 0x2057 } -- (prime,prime) (prime,doubleprime) (prime,tripleprime) -mathpairs[0x2033] = { [0x2032] = 0x2034, [0x2033] = 0x2057 } -- (doubleprime,prime) (doubleprime,doubleprime) -mathpairs[0x2034] = { [0x2032] = 0x2057 } -- (tripleprime,prime) - -mathpairs[0x2035] = { [0x2035] = 0x2036, [0x2036] = 0x2037 } -- (reversedprime,reversedprime) (reversedprime,doublereversedprime) -mathpairs[0x2036] = { [0x2035] = 0x2037 } -- (doublereversedprime,reversedprime) - -mathpairs[0x222B] = { [0x222B] = 0x222C, [0x222C] = 0x222D } -mathpairs[0x222C] = { [0x222B] = 0x222D } - -mathpairs[0x007C] = { [0x007C] = 0x2016, [0x2016] = 0x2980 } -- bar+bar=double bar+double=triple -mathpairs[0x2016] = { [0x007C] = 0x2980 } -- double+bar=triple - -local movesub = { - -- primes - [0x2032] = 0xFE932, - [0x2033] = 0xFE933, - [0x2034] = 0xFE934, - [0x2057] = 0xFE957, - -- reverse primes - [0x2035] = 0xFE935, - [0x2036] = 0xFE936, - [0x2037] = 0xFE937, -} - -local validpair = { - [noad_rel] = true, - [noad_ord] = true, - [noad_opdisplaylimits] = true, - [noad_oplimits] = true, - [noad_opnolimits] = true, -} - -local function movesubscript(parent,current_nucleus,current_char) - local prev = getfield(parent,"prev") - if prev and getid(prev) == math_noad then - if not getfield(prev,"sup") and not getfield(prev,"sub") then - -- {f} {'}_n => f_n^' - setfield(current_nucleus,"char",movesub[current_char or getchar(current_nucleus)]) - local nucleus = getfield(parent,"nucleus") - local sub = getfield(parent,"sub") - local sup = getfield(parent,"sup") - setfield(prev,"sup",nucleus) - setfield(prev,"sub",sub) - local dummy = copy_node(nucleus) - setfield(dummy,"char",0) - setfield(parent,"nucleus",dummy) - setfield(parent,"sub",nil) - if trace_collapsing then - report_collapsing("fixing subscript") - end - elseif not getfield(prev,"sup") then - -- {f} {'}_n => f_n^' - setfield(current_nucleus,"char",movesub[current_char or getchar(current_nucleus)]) - local nucleus = getfield(parent,"nucleus") - local sup = getfield(parent,"sup") - setfield(prev,"sup",nucleus) - local dummy = copy_node(nucleus) - setfield(dummy,"char",0) - setfield(parent,"nucleus",dummy) - if trace_collapsing then - report_collapsing("fixing subscript") - end - end - end -end - -local function collapsepair(pointer,what,n,parent,nested) -- todo: switch to turn in on and off - if parent then - if validpair[getsubtype(parent)] then - local current_nucleus = getfield(parent,"nucleus") - if getid(current_nucleus) == math_char then - local current_char = getchar(current_nucleus) - if not getfield(parent,"sub") and not getfield(parent,"sup") then - local mathpair = mathpairs[current_char] - if mathpair then - local next_noad = getnext(parent) - if next_noad and getid(next_noad) == math_noad then - if validpair[getsubtype(next_noad)] then - local next_nucleus = getfield(next_noad,"nucleus") - local next_char = getchar(next_nucleus) - if getid(next_nucleus) == math_char then - local newchar = mathpair[next_char] - if newchar then - local fam = getfield(current_nucleus,"fam") - local id = font_of_family(fam) - local characters = fontcharacters[id] - if characters and characters[newchar] then - if trace_collapsing then - report_collapsing("%U + %U => %U",current_char,next_char,newchar) - end - setfield(current_nucleus,"char",newchar) - local next_next_noad = getnext(next_noad) - if next_next_noad then - setfield(parent,"next",next_next_noad) - setfield(next_next_noad,"prev",parent) - else - setfield(parent,"next",nil) - end - setfield(parent,"sup",getfield(next_noad,"sup")) - setfield(parent,"sub",getfield(next_noad,"sub")) - setfield(next_noad,"sup",nil) - setfield(next_noad,"sub",nil) - free_node(next_noad) - collapsepair(pointer,what,n,parent,true) - -- if not nested and movesub[current_char] then - -- movesubscript(parent,current_nucleus,current_char) - -- end - end - elseif not nested and movesub[current_char] then - movesubscript(parent,current_nucleus,current_char) - end - end - end - elseif not nested and movesub[current_char] then - movesubscript(parent,current_nucleus,current_char) - end - elseif not nested and movesub[current_char] then - movesubscript(parent,current_nucleus,current_char) - end - elseif not nested and movesub[current_char] then - movesubscript(parent,current_nucleus,current_char) - end - end - end - end -end - -collapse[math_char] = collapsepair - -function noads.handlers.collapse(head,style,penalties) - processnoads(head,collapse,"collapse") - return true -end - --- variants - -local variants = { } - -local validvariants = { -- fast check on valid - [0x2229] = 0xFE00, [0x222A] = 0xFE00, - [0x2268] = 0xFE00, [0x2269] = 0xFE00, - [0x2272] = 0xFE00, [0x2273] = 0xFE00, - [0x228A] = 0xFE00, [0x228B] = 0xFE00, - [0x2293] = 0xFE00, [0x2294] = 0xFE00, - [0x2295] = 0xFE00, - [0x2297] = 0xFE00, - [0x229C] = 0xFE00, - [0x22DA] = 0xFE00, [0x22DB] = 0xFE00, - [0x2A3C] = 0xFE00, [0x2A3D] = 0xFE00, - [0x2A9D] = 0xFE00, [0x2A9E] = 0xFE00, - [0x2AAC] = 0xFE00, [0x2AAD] = 0xFE00, - [0x2ACB] = 0xFE00, [0x2ACC] = 0xFE00, -} - -variants[math_char] = function(pointer,what,n,parent) -- also set export value - local char = getchar(pointer) - local selector = validvariants[char] - if selector then - local next = getnext(parent) - if next and getid(next) == math_noad then - local nucleus = getfield(next,"nucleus") - if nucleus and getid(nucleus) == math_char and getchar(nucleus) == selector then - local variant - local tfmdata = fontdata[font_of_family(getfield(pointer,"fam"))] -- we can also have a famdata - local mathvariants = tfmdata.resources.variants -- and variantdata - if mathvariants then - mathvariants = mathvariants[selector] - if mathvariants then - variant = mathvariants[char] - end - end - if variant then - setfield(pointer,"char",variant) - setattr(pointer,a_exportstatus,char) -- we don't export the variant as it's visual markup - if trace_variants then - report_variants("variant (%U,%U) replaced by %U",char,selector,variant) - end - else - if trace_variants then - report_variants("no variant (%U,%U)",char,selector) - end - end - setfield(next,"prev",pointer) - setfield(parent,"next",getnext(next)) - free_node(next) - end - end - end -end - -function handlers.variants(head,style,penalties) - processnoads(head,variants,"unicode variant") - return true -end - --- for manuals - -local classes = { } - -local colors = { - [noadcodes.rel] = "trace:dr", - [noadcodes.ord] = "trace:db", - [noadcodes.bin] = "trace:dg", - [noadcodes.open] = "trace:dm", - [noadcodes.close] = "trace:dm", - [noadcodes.punct] = "trace:dc", - -- [noadcodes.opdisplaylimits] = "", - -- [noadcodes.oplimits] = "", - -- [noadcodes.opnolimits] = "", - -- [noadcodes.inner = "", - -- [noadcodes.under = "", - -- [noadcodes.over = "", - -- [noadcodes.vcenter = "", -} - -classes[math_char] = function(pointer,what,n,parent) - local color = colors[getsubtype(parent)] - if color then - setcolor(pointer,color) - else - resetcolor(pointer) - end -end - -function handlers.classes(head,style,penalties) - processnoads(head,classes,"classes") - return true -end - -registertracker("math.classes",function(v) tasks.setaction("math","noads.handlers.classes",v) end) - --- just for me - -function handlers.showtree(head,style,penalties) - inspect(nodes.totree(head)) -end - -registertracker("math.showtree",function(v) tasks.setaction("math","noads.handlers.showtree",v) end) - --- the normal builder - -function builders.kernel.mlist_to_hlist(head,style,penalties) - return mlist_to_hlist(head,style,penalties), true -end - --- function builders.kernel.mlist_to_hlist(head,style,penalties) --- print("!!!!!!! BEFORE",penalties) --- for n in node.traverse(head) do print(n) end --- print("!!!!!!!") --- head = mlist_to_hlist(head,style,penalties) --- print("!!!!!!! AFTER") --- for n in node.traverse(head) do print(n) end --- print("!!!!!!!") --- return head, true --- end - -tasks.new { - name = "math", - arguments = 2, - processor = utilities.sequencers.nodeprocessor, - sequence = { - "before", - "normalizers", - "builders", - "after", - }, -} - -tasks.freezegroup("math", "normalizers") -- experimental -tasks.freezegroup("math", "builders") -- experimental - -local actions = tasks.actions("math") -- head, style, penalties - -local starttiming, stoptiming = statistics.starttiming, statistics.stoptiming - -function processors.mlist_to_hlist(head,style,penalties) - starttiming(noads) - local head, done = actions(head,style,penalties) - stoptiming(noads) - return head, done -end - -callbacks.register('mlist_to_hlist',processors.mlist_to_hlist,"preprocessing math list") - --- tracing - -statistics.register("math processing time", function() - return statistics.elapsedseconds(noads) -end) - --- interface - -local implement = interfaces.implement - -implement { - name = "setmathalternate", - actions = mathematics.setalternate, - arguments = { "integer", "string" } -} - -implement { - name = "setmathitalics", - actions = mathematics.setitalics -} - -implement { - name = "resetmathitalics", - actions = mathematics.resetitalics -} |