summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/context/base/math-noa.lua
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/tex/context/base/math-noa.lua')
-rw-r--r--Master/texmf-dist/tex/context/base/math-noa.lua1304
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
-}