summaryrefslogtreecommitdiff
path: root/tex/context/base/mkiv/math-noa.lmt
diff options
context:
space:
mode:
Diffstat (limited to 'tex/context/base/mkiv/math-noa.lmt')
-rw-r--r--tex/context/base/mkiv/math-noa.lmt2399
1 files changed, 0 insertions, 2399 deletions
diff --git a/tex/context/base/mkiv/math-noa.lmt b/tex/context/base/mkiv/math-noa.lmt
deleted file mode 100644
index 25e1823e2..000000000
--- a/tex/context/base/mkiv/math-noa.lmt
+++ /dev/null
@@ -1,2399 +0,0 @@
-if not modules then modules = { } end modules ['math-noa'] = {
- version = 1.001,
- optimize = true,
- 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 (sometime in 2015-2016 i will
--- start cleaning up as by then the bigger picture is clear and code has been used for
--- years; the main handlers will get some extensions)
---
--- 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
-
--- todo: most is mathchar_code so we can have simple dedicated loops
-
--- nota bene: uunderdelimiter uoverdelimiter etc are radicals (we have 5 types)
-
-local next, tonumber = next, tonumber
-local utfchar, utfbyte = utf.char, utf.byte
-local formatters, gmatch = string.formatters, string.gmatch
-local sortedhash = table.sortedhash
-local insert, remove = table.insert, table.remove
-local div, round = math.div, math.round
-local bor, band = bit32.bor, bit32.band
-
-local fonts = fonts
-local nodes = nodes
-local node = node
-local mathematics = mathematics
-local context = context
-
-local otf = fonts.handlers.otf
-local otffeatures = fonts.constructors.features.otf
-local registerotffeature = otffeatures.register
-
-local privateattribute = attributes.private
-local registertracker = trackers.register
-local registerdirective = directives.register
-local logreporter = logs.reporter
-local setmetatableindex = table.setmetatableindex
-
-local colortracers = nodes.tracers.colors
-
-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_fixing = false registertracker("math.fixing", function(v) trace_foxing = 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_kernpairs = false registertracker("math.kernpairs", function(v) trace_kernpairs = v end)
-local trace_domains = false registertracker("math.domains", function(v) trace_domains = v end)
-local trace_families = false registertracker("math.families", function(v) trace_families = v end)
-local trace_fences = false registertracker("math.fences", function(v) trace_fences = v end)
-local trace_unstacking = false registertracker("math.unstack", function(v) trace_unstacking = 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_fixing = logreporter("mathematics","fixing")
-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_kernpairs = logreporter("mathematics","kernpairs")
-local report_domains = logreporter("mathematics","domains")
-local report_families = logreporter("mathematics","families")
-local report_fences = logreporter("mathematics","fences")
-local report_unstacking = logreporter("mathematics","unstack")
-
-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 setfield = nuts.setfield
-local setlink = nuts.setlink
-local setlist = nuts.setlist
-local setnext = nuts.setnext
-local setprev = nuts.setprev
-local setchar = nuts.setchar
-local setfam = nuts.setfam
-local setsubtype = nuts.setsubtype
-local setattr = nuts.setattr
-local setattrlist = nuts.setattrlist
-local setwidth = nuts.setwidth
-local setheight = nuts.setheight
-local setdepth = nuts.setdepth
-
-local getfield = nuts.getfield
-local getnext = nuts.getnext
-local getprev = nuts.getprev
-local getboth = nuts.getboth
-local getid = nuts.getid
-local getsubtype = nuts.getsubtype
-local getchar = nuts.getchar
-local getfont = nuts.getfont
-local getfam = nuts.getfam
-local getattr = nuts.getattr
-local getattrs = nuts.getattrs
-local getlist = nuts.getlist
-local getwidth = nuts.getwidth
-local getheight = nuts.getheight
-local getdepth = nuts.getdepth
-
-local getnucleus = nuts.getnucleus
-local getsub = nuts.getsub
-local getsup = nuts.getsup
-local getsubpre = nuts.getsubpre
-local getsuppre = nuts.getsuppre
-
-local setnucleus = nuts.setnucleus
-local setsub = nuts.setsub
-local setsup = nuts.setsup
-local setsubpre = nuts.setsubpre
-local setsuppre = nuts.setsuppre
-
-local flush_node = nuts.flush
-local copy_node = nuts.copy
-local slide_nodes = nuts.slide
-local set_visual = nuts.setvisual
-
-local mlist_to_hlist = nuts.mlist_to_hlist
-
-local new_kern = nodepool.kern
-local new_submlist = nodepool.submlist
-local new_noad = nodepool.noad
-local new_delimiter = nodepool.delimiter
-local new_fence = nodepool.fence
-
-local fonthashes = fonts.hashes
-local fontdata = fonthashes.identifiers
-local fontcharacters = fonthashes.characters
-local fontitalics = fonthashes.italics
-
-local variables = interfaces.variables
-local texsetattribute = tex.setattribute
-local texgetattribute = tex.getattribute
-local getfontoffamily = tex.getfontoffamily
-local unsetvalue = attributes.unsetvalue
-local implement = interfaces.implement
-
-local v_reset = variables.reset
-
-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 enableaction = tasks.enableaction
-local setaction = tasks.setaction
-
-local nodecodes = nodes.nodecodes
-local noadcodes = nodes.noadcodes
-local fencecodes = nodes.fencecodes
-
-local ordnoad_code = noadcodes.ord
-local opdisplaylimitsnoad_code = noadcodes.opdisplaylimits
-local oplimitsnoad_code = noadcodes.oplimits
-local opnolimitsnoad_code = noadcodes.opnolimits
-local binnoad_code = noadcodes.bin
-local relnode_code = noadcodes.rel
-local opennoad_code = noadcodes.open
-local closenoad_code = noadcodes.close
-local punctnoad_code = noadcodes.punct
-local innernoad_code = noadcodes.inner
-local undernoad_code = noadcodes.under
-local overnoad_code = noadcodes.over
-local vcenternoad_code = noadcodes.vcenter
-local ordlimitsnoad_code = noadcodes.ordlimits or oplimitsnoad_code
-
-local noad_code = nodecodes.noad -- attr nucleus sub sup
-local accent_code = nodecodes.accent -- attr nucleus sub sup accent
-local radical_code = nodecodes.radical -- attr nucleus sub sup left degree
-local fraction_code = nodecodes.fraction -- attr nucleus sub sup left right
-local subbox_code = nodecodes.subbox -- attr list
-local submlist_code = nodecodes.submlist -- attr list
-local mathchar_code = nodecodes.mathchar -- attr fam char
-local mathtextchar_code = nodecodes.mathtextchar -- attr fam char
-local delimiter_code = nodecodes.delimiter -- attr small_fam small_char large_fam large_char
------ style_code = nodecodes.style -- attr style
------ parameter_code = nodecodes.parameter -- attr style
-local math_choice = nodecodes.choice -- attr display text script scriptscript
-local fence_code = nodecodes.fence -- attr subtype
-
-local leftfence_code = fencecodes.left
-local middlefence_code = fencecodes.middle
-local rightfence_code = fencecodes.right
-
--- local mathclasses = mathematics.classes
--- local fenceclasses = {
--- [leftfence_code] = mathclasses.open,
--- [middlefence_code] = mathclasses.middle,
--- [rightfence_code] = mathclasses.close,
--- }
-
--- this initial stuff is tricky as we can have removed and new nodes with the same address
--- the only way out is a free-per-page list of nodes (not bad anyway)
-
--- local gf = getfield local gt = setmetatableindex("number") getfield = function(n,f) gt[f] = gt[f] + 1 return gf(n,f) end mathematics.GETFIELD = gt
--- local sf = setfield local st = setmetatableindex("number") setfield = function(n,f,v) st[f] = st[f] + 1 sf(n,f,v) end mathematics.SETFIELD = st
-
-local function process(start,what,n,parent)
-
- if n then
- n = n + 1
- else
- n = 0
- end
- --
- local initial = start
- --
- slide_nodes(start) -- we still miss a prev in noads -- fences test code
- --
- while start do
- local id = getid(start)
- if trace_processing then
- if id == noad_code then
- report_processing("%w%S, class %a",n*2,nutstring(start),noadcodes[getsubtype(start)])
- elseif id == mathchar_code then
- local char = getchar(start)
- local font = getfont(start)
- local fam = getfam(start)
- 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, newinitial = proc(start,what,n,parent) -- prev is bugged: or getprev(start)
- if newinitial then
- initial = newinitial -- temp hack .. we will make all return head
- if newstart then
- start = newstart
- -- report_processing("stop processing (new start)")
- else
- -- report_processing("quit processing (done)")
- break
- end
- else
- if newstart then
- start = newstart
- -- report_processing("stop processing (new start)")
- else
- -- report_processing("stop processing")
- end
- end
- elseif id == noad_code then
- -- single characters are like this
- local noad = getnucleus(start) if noad then process(noad,what,n,start) end -- list
- noad = getsup (start) if noad then process(noad,what,n,start) end -- list
- noad = getsub (start) if noad then process(noad,what,n,start) end -- list
- if getsubpre then
- noad = getsuppre (start) if noad then process(noad,what,n,start) end -- list
- noad = getsubpre (start) if noad then process(noad,what,n,start) end -- list
- end
- elseif id == mathchar_code or id == mathtextchar_code or id == delimiter_code then
- break
- elseif id == subbox_code or id == submlist_code then
- local noad = getlist(start) if noad then process(noad,what,n,start) end -- list (not getlist !)
- elseif id == fraction_code 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 == fence_code then
- local noad = getfield(start,"delimiter") if noad then process(noad,what,n,start) end -- delimiter
- elseif id == radical_code then
- local noad = getnucleus(start) if noad then process(noad,what,n,start) end -- list
- noad = getsup (start) if noad then process(noad,what,n,start) end -- list
- noad = getsub (start) if noad then process(noad,what,n,start) end -- list
- if getsubpre then
- noad = getsuppre (start) if noad then process(noad,what,n,start) end -- list
- noad = getsubpre (start) if noad then process(noad,what,n,start) end -- list
- end
- 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 == accent_code then
- local noad = getnucleus(start) if noad then process(noad,what,n,start) end -- list
- noad = getsup (start) if noad then process(noad,what,n,start) end -- list
- noad = getsub (start) if noad then process(noad,what,n,start) end -- list
- if getsubpre then
- noad = getsuppre (start) if noad then process(noad,what,n,start) end -- list
- noad = getsubpre (start) if noad then process(noad,what,n,start) end -- list
- end
- 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 == style_code then
- -- -- has a next
- -- elseif id == parameter_code then
- -- -- has a next
- -- else
- -- -- glue, penalty, etc
- end
- start = getnext(start)
- end
- if not parent then
- return initial -- only first level -- for now
- end
-end
-
-local function processnested(current,what,n)
- local noad = nil
- local id = getid(current)
- if id == noad_code then
- noad = getnucleus(current) if noad then process(noad,what,n,current) end -- list
- noad = getsup (current) if noad then process(noad,what,n,current) end -- list
- noad = getsub (current) if noad then process(noad,what,n,current) end -- list
- if getsubpre then
- noad = getsuppre (current) if noad then process(noad,what,n,current) end -- list
- noad = getsubpre (current) if noad then process(noad,what,n,current) end -- list
- end
- elseif id == subbox_code or id == submlist_code then
- noad = getlist(current) if noad then process(noad,what,n,current) end -- list (not getlist !)
- elseif id == fraction_code then
- noad = getfield(current,"num") if noad then process(noad,what,n,current) end -- list
- noad = getfield(current,"denom") if noad then process(noad,what,n,current) end -- list
- noad = getfield(current,"left") if noad then process(noad,what,n,current) end -- delimiter
- noad = getfield(current,"right") if noad then process(noad,what,n,current) end -- delimiter
- elseif id == math_choice then
- noad = getfield(current,"display") if noad then process(noad,what,n,current) end -- list
- noad = getfield(current,"text") if noad then process(noad,what,n,current) end -- list
- noad = getfield(current,"script") if noad then process(noad,what,n,current) end -- list
- noad = getfield(current,"scriptscript") if noad then process(noad,what,n,current) end -- list
- elseif id == fence_code then
- noad = getfield(current,"delimiter") if noad then process(noad,what,n,current) end -- delimiter
- elseif id == radical_code then
- noad = getnucleus(current) if noad then process(noad,what,n,current) end -- list
- noad = getsup (current) if noad then process(noad,what,n,current) end -- list
- noad = getsub (current) if noad then process(noad,what,n,current) end -- list
- if getsubpre then
- noad = getsuppre (current) if noad then process(noad,what,n,current) end -- list
- noad = getsubpre (current) if noad then process(noad,what,n,current) end -- list
- end
- noad = getfield(current,"left") if noad then process(noad,what,n,current) end -- delimiter
- noad = getfield(current,"degree") if noad then process(noad,what,n,current) end -- list
- elseif id == accent_code then
- noad = getnucleus(current) if noad then process(noad,what,n,current) end -- list
- noad = getsup (current) if noad then process(noad,what,n,current) end -- list
- noad = getsub (current) if noad then process(noad,what,n,current) end -- list
- if getsubpre then
- noad = getsuppre (current) if noad then process(noad,what,n,current) end -- list
- noad = getsubpre (current) if noad then process(noad,what,n,current) end -- list
- end
- noad = getfield(current,"accent") if noad then process(noad,what,n,current) end -- list
- noad = getfield(current,"bot_accent") if noad then process(noad,what,n,current) end -- list
- end
-end
-
-local function processstep(current,process,n,id)
- local noad = nil
- local id = id or getid(current)
- if id == noad_code then
- noad = getnucleus(current) if noad then process(noad,n,current) end -- list
- noad = getsup (current) if noad then process(noad,n,current) end -- list
- noad = getsub (current) if noad then process(noad,n,current) end -- list
- if getsubpre then
- noad = getsuppre (current) if noad then process(noad,n,current) end -- list
- noad = getsubpre (current) if noad then process(noad,n,current) end -- list
- end
- elseif id == subbox_code or id == submlist_code then
- noad = getlist(current) if noad then process(noad,n,current) end -- list (not getlist !)
- elseif id == fraction_code then
- noad = getfield(current,"num") if noad then process(noad,n,current) end -- list
- noad = getfield(current,"denom") if noad then process(noad,n,current) end -- list
- noad = getfield(current,"left") if noad then process(noad,n,current) end -- delimiter
- noad = getfield(current,"right") if noad then process(noad,n,current) end -- delimiter
- elseif id == math_choice then
- noad = getfield(current,"display") if noad then process(noad,n,current) end -- list
- noad = getfield(current,"text") if noad then process(noad,n,current) end -- list
- noad = getfield(current,"script") if noad then process(noad,n,current) end -- list
- noad = getfield(current,"scriptscript") if noad then process(noad,n,current) end -- list
- elseif id == fence_code then
- noad = getfield(current,"delimiter") if noad then process(noad,n,current) end -- delimiter
- elseif id == radical_code then
- noad = getnucleus(current) if noad then process(noad,n,current) end -- list
- noad = getsup (current) if noad then process(noad,n,current) end -- list
- noad = getsub (current) if noad then process(noad,n,current) end -- list
- if getsubpre then
- noad = getsuppre (current) if noad then process(noad,n,current) end -- list
- noad = getsubpre (current) if noad then process(noad,n,current) end -- list
- end
- noad = getfield(current,"left") if noad then process(noad,n,current) end -- delimiter
- noad = getfield(current,"degree") if noad then process(noad,n,current) end -- list
- elseif id == accent_code then
- noad = getnucleus(current) if noad then process(noad,n,current) end -- list
- noad = getsup (current) if noad then process(noad,n,current) end -- list
- noad = getsub (current) if noad then process(noad,n,current) end -- list
- if getsubpre then
- noad = getsuppre (current) if noad then process(noad,n,current) end -- list
- noad = getsubpre (current) if noad then process(noad,n,current) end -- list
- end
- noad = getfield(current,"accent") if noad then process(noad,n,current) end -- list
- noad = getfield(current,"bot_accent") if noad then process(noad,n,current) end -- list
- end
-end
-
-local function processnoads(head,actions,banner)
- if trace_processing then
- report_processing("start %a",banner)
- head = process(head,actions)
- report_processing("stop %a",banner)
- else
- head = process(head,actions)
- end
- return head
-end
-
-noads.process = processnoads
-noads.processnested = processnested
-noads.processouter = process
-
--- experiment (when not present fall back to fam 0) -- needs documentation
-
-local unknowns = { }
-local checked = { } -- simple case
-local tracked = false trackers.register("fonts.missing", function(v) tracked = v end)
-local cached = 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
-
--- 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
-
-do
-
- local families = { }
- local a_mathfamily = privateattribute("mathfamily")
- local boldmap = mathematics.boldmap
-
- local familymap = { [0] =
- "regular",
- "regular",
- "regular",
- "bold",
- "bold",
- "bold",
- "pseudobold",
- "pseudobold",
- "pseudobold",
- }
-
- families[fraction_code] = function(pointer,what,n,parent)
- local a = getattr(pointer,a_mathfamily)
- if a and a >= 0 then
- if a > 0 then
- setattr(pointer,a_mathfamily,0)
- if a > 5 then
- a = a - 3
- end
- end
- setfam(pointer,a)
- end
- processnested(pointer,families,n+1)
- end
-
- families[noad_code] = function(pointer,what,n,parent)
- local a = getattr(pointer,a_mathfamily)
- if a and a >= 0 then
- if a > 0 then
- setattr(pointer,a_mathfamily,0)
- if a > 5 then
- a = a - 3
- end
- end
- setfam(pointer,a)
- end
- processnested(pointer,families,n+1)
- end
-
- families[mathchar_code] = function(pointer)
- if getfam(pointer) == 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
- setfam(pointer,newa)
- elseif not fontcharacters[getfontoffamily(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
- setfam(pointer,newa-3)
- end
- else
- setattr(pointer,a_exportstatus,char)
- setchar(pointer,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
- setfam(pointer,newa)
- end
- else
- local char = getchar(pointer)
- if not fontcharacters[getfontoffamily(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
- setfam(pointer,a)
- end
- end
- end
- end
- end
- families[delimiter_code] = 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[getfontoffamily(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[getfontoffamily(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
-
- -- will become:
-
- -- families[delimiter_code] = function(pointer)
- -- if getfam(pointer) == 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 = getchar(pointer)
- -- local okay = fontcharacters[getfontoffamily(a)][char]
- -- if okay then
- -- setfam(pointer,a)
- -- elseif a > 2 then
- -- setfam(pointer,a-3)
- -- end
- -- else
- -- setfam(pointer,0)
- -- end
- -- end
- -- end
-
- families[mathtextchar_code] = families[mathchar_code]
-
- function handlers.families(head,style,penalties)
- processnoads(head,families,"families")
- return true -- not needed
- end
-
-end
-
--- character remapping
-
-do
-
- local a_mathalphabet = privateattribute("mathalphabet")
- local a_mathgreek = privateattribute("mathgreek")
-
- local relocate = { }
-
- local remapalphabets = mathematics.remapalphabets
- local fallbackstyleattr = mathematics.fallbackstyleattr
- local setnodecolor = colortracers.set
-
- local function report_remap(tag,id,old,new,extra)
- report_remapping("remapping %s in font (%s,%s) from %C to %C%s",
- tag,id,fontdata[id].properties.fontname or "",old,new,extra)
- end
-
- local function checked(pointer)
- local char = getchar(pointer)
- local font = getfont(pointer)
- local data = fontcharacters[font]
- if not data[char] then
- local specials = characters.data[char].specials
- if specials and (specials[1] == "char" or specials[1] == "font") then
- local newchar = specials[#specials]
- if trace_remapping then
- report_remap("fallback",font,char,newchar)
- end
- if trace_analyzing then
- setnodecolor(pointer,"font:isol")
- end
- setattr(pointer,a_exportstatus,char) -- testcase: exponentiale
- setchar(pointer,newchar)
- return true
- end
- end
- end
-
- -- We can optimize this if we really think that math is a bottleneck which it never
- -- really is.
-
- relocate[mathchar_code] = function(pointer)
- local g = getattr(pointer,a_mathgreek) or 0
- local a = getattr(pointer,a_mathalphabet) or 0
- -- local g, a = getattrs(pointer,a_mathgreek,a_mathalphabet)
- -- if not a then a = 0 end
- -- if not g then g = 0 end
- local char = getchar(pointer)
- local font = getfont(pointer)
- local characters = fontcharacters[font]
- if a > 0 or g > 0 then
- if a > 0 then
- -- not really critital but we could use properties
- setattr(pointer,a_mathgreek,0)
- end
- if g > 0 then
- -- not really critital but we could use properties
- setattr(pointer,a_mathalphabet,0)
- end
- local newchar = remapalphabets(char,a,g)
- if newchar then
- local newchardata = characters[newchar]
- if newchardata then
- if trace_remapping then
- report_remap("char",font,char,newchar,newchardata.commands and " (virtual)" or "")
- end
- if trace_analyzing then
- setnodecolor(pointer,"font:isol")
- end
- setchar(pointer,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
- setchar(pointer,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
- elseif trace_remapping then
- local chardata = characters[char]
- if chardata and chardata.commands then
- report_remap("char",font,char,char," (virtual)")
- end
- end
- end
- if not characters[char] then
- setchar(pointer,errorchar(font,char))
- end
- if trace_analyzing then
- setnodecolor(pointer,"font:medi")
- end
- if check_coverage then
- return checked(pointer)
- end
- end
-
- relocate[mathtextchar_code] = function(pointer)
- if trace_analyzing then
- setnodecolor(pointer,"font:init")
- end
- end
-
- relocate[delimiter_code] = function(pointer)
- if trace_analyzing then
- setnodecolor(pointer,"font:fina")
- end
- end
-
- function handlers.relocate(head,style,penalties)
- processnoads(head,relocate,"relocate")
- return true -- not needed
- end
-
-end
-
--- rendering (beware, not exported)
-
-do
-
- local render = { }
-
- local rendersets = mathematics.renderings.numbers or { } -- store
-
- render[mathchar_code] = 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 font = getfont(pointer)
- local characters = fontcharacters[font]
- if characters and characters[newchar] then
- setchar(pointer,newchar)
- setattr(pointer,a_exportstatus,char)
- end
- end
- end
- end
- end
-
- function handlers.render(head,style,penalties)
- processnoads(head,render,"render")
- return true -- not needed
- end
-
-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
-
-do
-
- local a_mathsize = privateattribute("mathsize") -- this might move into other fence code
- local resize = { }
-
- resize[fence_code] = function(pointer)
- local subtype = getsubtype(pointer)
- if subtype == leftfence_code or subtype == rightfence_code then
- local a = getattr(pointer,a_mathsize)
- if a and a > 0 then
- local method = div(a,100)
- local size = a % 100
- setattr(pointer,a_mathsize,0)
- local delimiter = getfield(pointer,"delimiter")
- local chr = getchar(delimiter)
- if chr > 0 then
- local fam = getfam(delimiter)
- local id = getfontoffamily(fam)
- if id > 0 then
- local data = fontdata[id]
- local char = mathematics.big(data,chr,size,method)
- local ht = getheight(pointer)
- local dp = getdepth(pointer)
- if ht == 1 or dp == 1 then -- 1 scaled point is a signal
- local chardata = data.characters[char]
- if ht == 1 then
- setheight(pointer,chardata.height)
- end
- if dp == 1 then
- setdepth(pointer,chardata.depth)
- end
- end
- if trace_fences then
- report_fences("replacing %C by %C using method %a and size %a",chr,char,method,size)
- end
- setchar(delimiter,char)
- end
- end
- end
- end
- end
-
- function handlers.resize(head,style,penalties)
- processnoads(head,resize,"resize")
- return true -- not needed
- end
-
-end
-
--- still not perfect:
-
-do
-
- local a_autofence = privateattribute("mathautofence")
- local autofences = { }
- local dummyfencechar = 0x2E
-
- local function makefence(what,char)
- local d = new_delimiter() -- todo: attr
- local f = new_fence() -- todo: attr
- if char then
- local sym = getnucleus(char)
- local chr = getchar(sym)
- local fam = getfam(sym)
- if chr == dummyfencechar then
- chr = 0
- end
- setchar(d,chr)
- setfam(d,fam)
- flush_node(sym)
- end
- setattrlist(d,char)
- setattrlist(f,char)
- setsubtype(f,what)
- setfield(f,"delimiter",d)
- setfield(f,"class",-1) -- tex itself does this, so not fenceclasses[what]
- return f
- end
-
- local function show(where,pointer)
- print("")
- local i = 0
- for n in nuts.traverse(pointer) do
- i = i + 1
- print(i,where,nuts.tonode(n))
- end
- print("")
- end
-
- local function makelist(middle,noad,f_o,o_next,c_prev,f_c)
--- report_fences(
--- "middle %s, noad %s, open %s, opennext %s, closeprev %s, close %s",
--- middle or "?",
--- noad or "?",
--- f_o or "?",
--- o_next or "?",
--- c_prev or "?",
--- f_c or "?"
--- )
- local list = new_submlist()
- setsubtype(noad,innernoad_code)
- setnucleus(noad,list)
- setlist(list,f_o)
- setlink(f_o,o_next) -- prev of list is nil
- setlink(c_prev,f_c) -- next of list is nil
--- show("list",f_o)
- if middle and next(middle) then
- local prev = f_o
- local current = o_next
- while current ~= f_c do
- local midl = middle[current]
- local next = getnext(current)
- if midl then
- local fence = makefence(middlefence_code,current)
- setnucleus(current)
- flush_node(current)
- middle[current] = nil
- -- replace_node
- setlink(prev,fence,next)
- prev = fence
- else
- prev = current
- end
- current = next
- end
- end
- return noad
- end
-
- -- relinking is now somewhat overdone
-
- local function convert_both(open,close,middle)
- local o_next = getnext(open)
- if o_next == close then
- return close
- else
- local c_prev, c_next = getboth(close)
- local f_o = makefence(leftfence_code,open)
- local f_c = makefence(rightfence_code,close)
- makelist(middle,open,f_o,o_next,c_prev,f_c)
- setnucleus(close)
- flush_node(close)
- -- open is now a list
- setlink(open,c_next)
- return open
- end
- end
-
- local function convert_open(open,last,middle) -- last is really last (final case)
- local f_o = makefence(leftfence_code,open)
- local f_c = makefence(rightfence_code)
- local o_next = getnext(open)
- makelist(middle,open,f_o,o_next,last,nil)
- -- open is now a list
- setlink(open,l_next)
- return open
- end
-
- local function convert_close(first,close,middle)
- local f_o = makefence(leftfence_code)
- local f_c = makefence(rightfence_code,close)
- local c_prev = getprev(close)
- local f_next = getnext(first)
- makelist(middle, close, f_o,f_next,c_prev,f_c)
- -- close is now a list
- if c_prev ~= first then
- setlink(first,close)
- end
- return close
- end
-
- local stacks = setmetatableindex("table")
-
- -- 1=open 2=close 3=middle 4=both
-
- local function processfences(pointer,n,parent)
- local current = pointer
- local last = pointer
- local start = pointer
- local done = false
- local initial = pointer
- local stack = nil
- local middle = nil -- todo: use properties
- while current do
--- show("before",pointer)
- local id = getid(current)
- if id == noad_code then
- local a = getattr(current,a_autofence)
- if a and a > 0 then
- local stack = stacks[n]
- setattr(current,a_autofence,0) -- hm, better use a property
- local level = #stack
- if a == 1 then
- if trace_fences then
- report_fences("%2i: level %i, handling %s, action %s",n,level,"open","open")
- end
- insert(stack,current)
- elseif a == 2 then
- local open = remove(stack)
- if open then
- if trace_fences then
- report_fences("%2i: level %i, handling %s, action %s",n,level,"close","both")
- end
- current = convert_both(open,current,middle)
- elseif current == start then
- if trace_fences then
- report_fences("%2i: level %i, handling %s, action %s",n,level,"close","skip")
- end
- else
- if trace_fences then
- report_fences("%2i: level %i, handling %s, action %s",n,level,"close","close")
- end
- current = convert_close(initial,current,middle)
- if not parent then
- initial = current
- end
- end
- elseif a == 3 then
- if trace_fences then
- report_fences("%2i: level %i, handling %s, action %s",n,level,"middle","middle")
- end
- if middle then
- middle[current] = last
- else
- middle = { [current] = last }
- end
- elseif a == 4 then
- if not stack or #stack == 0 then
- if trace_fences then
- report_fences("%2i: level %i, handling %s, action %s",n,level,"both","open")
- end
- insert(stack,current)
- else
- local open = remove(stack)
- if open then
- if trace_fences then
- report_fences("%2i: level %i, handling %s, action %s",n,level,"both","both")
- end
- current = convert_both(open,current,middle)
- elseif current == start then
- if trace_fences then
- report_fences("%2i: level %i, handling %s, action %s",n,level,"both","skip")
- end
- else
- if trace_fences then
- report_fences("%2i: level %i, handling %s, action %s",n,level,"both","close")
- end
- current = convert_close(initial,current,middle)
- if not parent then
- initial = current
- end
- end
- end
- end
- done = true
- else
- processstep(current,processfences,n+1,id)
- end
- else
- -- next at current level
- processstep(current,processfences,n,id)
- end
--- show("after",pointer)
- last = current
- current = getnext(current)
- end
- if done then
- local stack = stacks[n]
- local s = #stack
- if s > 0 then
- for i=1,s do
- local open = remove(stack)
- if trace_fences then
- report_fences("%2i: level %i, handling %s, action %s",n,#stack,"flush","open")
- end
- last = convert_open(open,last,middle)
- end
--- show("done",pointer)
- end
- end
- end
-
- -- we can have a first changed node .. an option is to have a leading dummy node in math
- -- lists like the par node as it can save a lot of mess
-
- local enabled = false
-
- implement {
- name = "enableautofences",
- onlyonce = true,
- actions = function()
- enableaction("math","noads.handlers.autofences")
- enabled = true
- end
- }
-
- function handlers.autofences(head,style,penalties)
- if enabled then -- tex.modes.c_math_fences_auto
- -- inspect(nodes.totree(head))
- processfences(head,1)
- -- inspect(nodes.totree(head))
- end
- end
-
-end
-
--- normalize scripts
-
-do
-
- 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) == noad_code do
- local nextnucleus = getnucleus(next)
- if nextnucleus and getid(nextnucleus) == mathchar_code and not getsub(next) and not getsup(next) 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)
- setchar(nextnucleus,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)
- setchar(nextnucleus,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
- setsup(pointer,getnucleus(start_super))
- else
- local list = new_submlist() -- todo attr
- setlist(list,start_super)
- setsup(pointer,list)
- end
- if mode == "super" then
- setnext(pointer,getnext(stop_super))
- end
- setnext(stop_super)
- end
- if start_sub then
-
--- if mode == "sub" then
--- local sup = getsup(pointer)
--- if sup and not getsub(pointer) then
--- local nxt = getnext(pointer)
--- local new = new_noad(pointer)
--- setnucleus(new,new_submlist())
--- setlink(pointer,new,nxt)
--- pointer = new
--- end
--- end
-
- if start_sub == stop_sub then
- setsub(pointer,getnucleus(start_sub))
- else
- local list = new_submlist() -- todo attr
- setlist(list,start_sub)
- setsub(pointer,list)
- end
- if mode == "sub" then
- setnext(pointer,getnext(stop_sub))
- end
- setnext(stop_sub)
- end
- -- we could return stop
- end
-
- unscript[mathchar_code] = replace -- not noads as we need to recurse
-
- function handlers.unscript(head,style,penalties)
- processnoads(head,unscript,"unscript")
- return true -- not needed
- end
-
-end
-
-do
-
- local unstack = { } noads.processors.unstack = unstack
- local enabled = false
- local a_unstack = privateattribute("mathunstack")
-
- unstack[noad_code] = function(pointer)
- if getattr(pointer,a_unstack) then
- local sup = getsup(pointer)
- local sub = getsub(pointer)
- if sup and sub then
- -- if trace_unstacking then
- -- report_unstacking() -- todo ... what to show ...
- -- end
- local nxt = getnext(pointer)
- local new = new_noad(pointer)
- setnucleus(new,new_submlist())
- setsub(pointer)
- setsub(new,sub)
- setlink(pointer,new,nxt)
- end
- end
- end
-
- function handlers.unstack(head,style,penalties)
- if enabled then
- processnoads(head,unstack,"unstack")
- return true -- not needed
- end
- end
-
- implement {
- name = "enablescriptunstacking",
- onlyonce = true,
- actions = function()
- enableaction("math","noads.handlers.unstack")
- enabled = true
- end
- }
-
-end
-
-do
-
- local function collected(list)
- if list and next(list) then
- local n, t = 0, { }
- for k, v in sortedhash(list) do
- n = n + 1
- t[n] = 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)
-
-end
-
--- math alternates: (in xits lgf: $ABC$ $\cal ABC$ $\mathalternate{cal}\cal ABC$)
--- math alternates: (in lucidaot lgf: $ABC \mathalternate{italic} ABC$)
-
--- todo: set alternate for specific symbols
--- todo: no need to do this when already loaded
--- todo: use a fonts.hashes.mathalternates
-
-do
-
- local last = 0
-
- local known = setmetatableindex(function(t,k)
- local v = bor(0,2^last)
- t[k] = v
- last = last + 1
- return v
- end)
-
- local defaults = {
- dotless = { feature = 'dtls', value = 1, comment = "Mathematical Dotless Forms" },
- -- zero = { feature = 'zero', value = 1, comment = "Slashed or Dotted Zero" }, -- in no math font (yet)
- }
-
- local function initializemathalternates(tfmdata)
- local goodies = tfmdata.goodies
- local autolist = defaults -- table.copy(defaults)
-
- local function setthem(newalternates)
- local resources = tfmdata.resources -- was tfmdata.shared
- local mathalternates = resources.mathalternates
- local alternates, attributes, registered, presets
- if mathalternates then
- alternates = mathalternates.alternates
- attributes = mathalternates.attributes
- registered = mathalternates.registered
- else
- alternates, attributes, registered = { }, { }, { }
- mathalternates = {
- attributes = attributes,
- alternates = alternates,
- registered = registered,
- presets = { },
- resets = { },
- hashes = setmetatableindex("table")
- }
- resources.mathalternates = mathalternates
- end
- --
- for name, data in sortedhash(newalternates) do
- if alternates[name] then
- -- ignore
- else
- local attr = known[name]
- attributes[attr] = data
- alternates[name] = attr
- registered[#registered+1] = attr
- end
- end
- end
-
- if goodies then
- local done = { }
- 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
- for k, v in next, autolist do
- if not alternates[k] then
- alternates[k] = v
- end
- end
- setthem(alternates)
- return
- end
- end
- end
-
- if trace_goodies then
- report_goodies("loading default alternates for font %a",tfmdata.properties.name)
- end
- setthem(autolist)
-
- end
-
- registerotffeature {
- name = "mathalternates",
- description = "additional math alternative shapes",
- initializers = {
- base = initializemathalternates,
- node = initializemathalternates,
- }
- }
-
- -- local getalternate = otf.getalternate (runtime new method so ...)
-
- -- todo: not shared but copies ... one never knows
-
- local a_mathalternate = privateattribute("mathalternate")
- local alternate = { } -- processors.alternate = alternate
- local fontdata = fonts.hashes.identifiers
- local fontresources = fonts.hashes.resources
-
- local function getalternate(fam,tag,current)
- local resources = fontresources[getfontoffamily(fam)]
- local attribute = unsetvalue
- if resources then
- local mathalternates = resources.mathalternates
- if mathalternates then
- local presets = mathalternates.presets
- if presets then
- local resets = mathalternates.resets
- attribute = presets[tag]
- if not attribute then
- attribute = 0
- local alternates = mathalternates.alternates
- for s in gmatch(tag,"[^, ]+") do
- if s == v_reset then
- resets[tag] = true
- current = unsetvalue
- else
- local a = alternates[s] -- or known[s]
- if a then
- attribute = bor(attribute,a)
- end
- end
- end
- if attribute == 0 then
- attribute = unsetvalue
- end
- presets[tag] = attribute
- elseif resets[tag] then
- current = unsetvalue
- end
- end
- end
- end
- if attribute > 0 and current and current > 0 then
- return bor(current,attribute)
- else
- return attribute
- end
- end
-
- local function presetalternate(fam,tag)
- texsetattribute(a_mathalternate,getalternate(fam,tag))
- end
-
- implement {
- name = "presetmathalternate",
- actions = presetalternate,
- arguments = { "integer", "string" }
- }
-
- local function setalternate(fam,tag)
- local a = texgetattribute(a_mathalternate)
- local v = getalternate(fam,tag,a)
- texsetattribute(a_mathalternate,v)
- end
-
- implement {
- name = "setmathalternate",
- actions = setalternate,
- arguments = { "integer", "string" }
- }
-
- alternate[mathchar_code] = function(pointer) -- slow
- local a = getattr(pointer,a_mathalternate)
- if a and a > 0 then
- setattr(pointer,a_mathalternate,0)
- local fontid = getfont(pointer)
- local resources = fontresources[fontid]
- if resources then
- local mathalternates = resources.mathalternates
- if mathalternates then
- local attributes = mathalternates.attributes
- local registered = mathalternates.registered
- local hashes = mathalternates.hashes
- for i=1,#registered do
- local r = registered[i]
- if band(a,r) ~= 0 then
- local char = getchar(pointer)
- local alt = hashes[i][char]
- if alt == nil then
- local what = attributes[r]
- alt = otf.getalternate(fontdata[fontid],char,what.feature,what.value) or false
- if alt == char then
- alt = false
- end
- hashes[i][char] = alt
- end
- if alt then
- if trace_alternates then
- local what = attributes[r]
- report_alternates("alternate %a, value %a, replacing glyph %U by glyph %U",
- tostring(what.feature),tostring(what.value),getchar(pointer),alt)
- end
- setchar(pointer,alt)
- break
- end
- end
- end
- end
- end
- end
- end
-
- function handlers.alternates(head,style,penalties)
- processnoads(head,alternate,"alternate")
- return true -- not needed
- end
-
-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 (was) a mess. There are all kind of assumptions based on
--- old fonts and new fonts. 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 mixed math
--- and text. Also, for a while in context we had to deal with a mix of virtual math fonts and
--- real ones.
-
--- in opentype the italic correction of a limop is added to the width and luatex does
--- some juggling that we want to avoid but we need to do something here (in fact, we could
--- better fix the width of the character)
-
-do
-
- local a_mathitalics = privateattribute("mathitalics")
-
- local italics = { }
- local default_factor = 1/20
-
- local setcolor = colortracers.set
- local resetcolor = colortracers.reset
- local italic_kern = new_kern
-
- local c_positive_d = "trace:dg"
- local c_negative_d = "trace:dr"
-
- local function insert_kern(current,kern)
- local sub = new_submlist() -- todo: attr
- local noad = new_noad() -- todo: attr
- setlist(sub,kern)
- setnext(kern,noad)
- setnucleus(noad,current)
- return sub
- end
-
- registertracker("math.italics.visualize", function(v)
- if v then
- italic_kern = function(k)
- local n = new_kern(k) -- todo: attr
- set_visual(n,"italic")
- return n
- end
- else
- italic_kern = new_kern
- end
- end)
-
- local function getcorrection(method,font,char) -- -- or character.italic -- (this one is for tex)
-
- local visual = chardata[char].visual
-
- if method == 1 then
- -- check on state
- local italics = fontitalics[font]
- if italics then
- local character = fontcharacters[font][char]
- if character then
- local correction = character.italic
- if correction and correction ~= 0 then
- return correction, visual
- end
- end
- end
- elseif method == 2 then
- -- no check
- local character = fontcharacters[font][char]
- if character then
- local correction = character.italic
- if correction and correction ~= 0 then
- return correction, visual
- end
- end
- elseif method == 3 then
- -- check on visual
- if visual == "it" or visual == "bi" then
- local character = fontcharacters[font][char]
- if character then
- local correction = character.italic
- if correction and correction ~= 0 then
- return correction, visual
- end
- end
- end
- elseif method == 4 then
- -- combination of 1 and 3
- local italics = fontitalics[font]
- if italics and (visual == "it" or visual == "bi") then
- local character = fontcharacters[font][char]
- if character then
- local correction = character.italic
- if correction and correction ~= 0 then
- return correction, visual
- end
- end
- end
- end
-
- end
-
- italics[mathchar_code] = function(pointer,what,n,parent)
- local method = getattr(pointer,a_mathitalics)
- if method and method > 0 and method < 100 then
- local char = getchar(pointer)
- local font = getfont(pointer)
- local correction, visual = getcorrection(method,font,char)
- if correction and correction ~= 0 then
- 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, flagging italic correction %p between %C and end math",method,correction,char)
- end
- if correction > 0 then
- correction = correction + 100
- else
- correction = correction - 100
- end
- correction = round(correction)
- setattr(pointer,a_mathitalics,correction)
- setattr(parent,a_mathitalics,correction)
- return -- so no reset later on
- end
- end
- end
- end
- setattr(pointer,a_mathitalics,unsetvalue)
- end
-
- function handlers.italics(head,style,penalties)
- processnoads(head,italics,"italics")
- return true -- not needed
- end
-
- local enable = function()
- enableaction("math", "noads.handlers.italics")
- if trace_italics then
- report_italics("enabling math italics")
- end
- -- we enable math (unless already enabled elsewhere)
- typesetters.italics.enablemath()
- enable = false
- end
-
- -- best do this only on math mode (less overhead)
-
- function mathematics.setitalics(name)
- if enable then
- enable()
- end
- texsetattribute(a_mathitalics,name and name ~= v_reset and tonumber(name) or unsetvalue) -- maybe also v_none
- end
-
- function mathematics.getitalics(name)
- if enable then
- enable()
- end
- context(name and name ~= v_reset and tonumber(name) or unsetvalue)
- end
-
- function mathematics.resetitalics()
- texsetattribute(a_mathitalics,unsetvalue)
- end
-
- implement {
- name = "initializemathitalics",
- actions = enable,
- onlyonce = true,
- }
-
- implement {
- name = "setmathitalics",
- actions = mathematics.setitalics,
- arguments = "string",
- }
-
- implement {
- name = "getmathitalics",
- actions = mathematics.getitalics,
- arguments = "string",
- }
-
- implement {
- name = "resetmathitalics",
- actions = mathematics.resetitalics
- }
-
-end
-
-do
-
- -- math kerns (experiment) in goodies:
- --
- -- mathematics = {
- -- kernpairs = {
- -- [0x1D44E] = {
- -- [0x1D44F] = 400, -- 𝑎𝑏
- -- }
- -- },
- -- }
-
- local a_kernpairs = privateattribute("mathkernpairs")
- local kernpairs = { }
-
- local function enable()
- enableaction("math", "noads.handlers.kernpairs")
- if trace_kernpairs then
- report_kernpairs("enabling math kern pairs")
- end
- enable = false
- end
-
- implement {
- name = "initializemathkernpairs",
- actions = enable,
- onlyonce = true,
- }
-
- local hash = setmetatableindex(function(t,font)
- local g = fontdata[font].goodies
- local m = g and g[1] and g[1].mathematics
- local k = m and m.kernpairs
- t[font] = k
- return k
- end)
-
- -- no correction after prime because that moved to a superscript
-
- kernpairs[mathchar_code] = function(pointer,what,n,parent)
- if getattr(pointer,a_kernpairs) == 1 then
- local font = getfont(pointer)
- local list = hash[font]
- if list then
- local first = getchar(pointer)
- local found = list[first]
- if found then
- local next = getnext(parent)
- if next and getid(next) == noad_code then
- pointer = getnucleus(next)
- if pointer then
- if getfont(pointer) == font then
- local second = getchar(pointer)
- local kern = found[second]
- if kern then
- kern = kern * fonts.hashes.parameters[font].hfactor
- if trace_kernpairs then
- report_kernpairs("adding %p kerning between %C and %C",kern,first,second)
- end
- setlink(parent,new_kern(kern),getnext(parent)) -- todo: attr
- end
- end
- end
- end
- end
- end
- end
- end
-
- function handlers.kernpairs(head,style,penalties)
- processnoads(head,kernpairs,"kernpairs")
- return true -- not needed
- end
-
-end
-
--- primes and such
-
-do
-
- -- is validpair stil needed?
-
- local a_mathcollapsing = privateattribute("mathcollapsing")
- local collapse = { }
- local mathlists = characters.mathlists
- local validpair = {
- [ordnoad_code] = true,
- [opdisplaylimitsnoad_code] = true,
- [oplimitsnoad_code] = true,
- [opnolimitsnoad_code] = true,
- [binnoad_code] = true, -- new
- [relnode_code] = true,
- [opennoad_code] = true, -- new
- [closenoad_code] = true, -- new
- [punctnoad_code] = true, -- new
- [innernoad_code] = false,
- [undernoad_code] = false,
- [overnoad_code] = false,
- [vcenternoad_code] = false,
- [ordlimitsnoad_code] = true,
- }
-
- local reported = setmetatableindex("table")
-
- collapse[mathchar_code] = function(pointer,what,n,parent)
-
- if parent and mathlists[getchar(pointer)] then
- local found, last, lucleus, lsup, lsub, category
- local tree = mathlists
- local current = parent
- while current and validpair[getsubtype(current)] do
- local nucleus = getnucleus(current) -- == pointer
- local sub = getsub(current)
- local sup = getsup(current)
- local char = getchar(nucleus)
- if char then
- local match = tree[char]
- if match then
- local method = getattr(current,a_mathcollapsing)
- if method and method > 0 and method <= 3 then
- local specials = match.specials
- local mathlist = match.mathlist
- local ligature
- if method == 1 then
- ligature = specials
- elseif method == 2 then
- ligature = specials or mathlist
- else -- 3
- ligature = mathlist or specials
- end
- if ligature then
- category = mathlist and "mathlist" or "specials"
- found = ligature
- last = current
- lucleus = nucleus
- lsup = sup
- lsub = sub
- end
- tree = match
- if sub or sup then
- break
- else
- current = getnext(current)
- end
- else
- break
- end
- else
- break
- end
- else
- break
- end
- end
- if found and last and lucleus then
- local id = getfont(lucleus)
- local characters = fontcharacters[id]
- local replace = characters and characters[found]
- if not replace then
- if not reported[id][found] then
- reported[id][found] = true
- report_collapsing("%s ligature %C from %s","ignoring",found,category)
- end
- elseif trace_collapsing then
- report_collapsing("%s ligature %C from %s","creating",found,category)
- end
- setchar(pointer,found)
- local l = getnext(last)
- local c = getnext(parent)
- if lsub then
- setsub(parent,lsub)
- setsub(last)
- end
- if lsup then
- setsup(parent,lsup)
- setsup(last)
- end
- while c ~= l do
- local n = getnext(c)
- flush_node(c)
- c = n
- end
- setlink(parent,l)
- end
- end
- end
-
- function noads.handlers.collapse(head,style,penalties)
- processnoads(head,collapse,"collapse")
- return true -- not needed
- end
-
- local enable = function()
- enableaction("math", "noads.handlers.collapse")
- if trace_collapsing then
- report_collapsing("enabling math collapsing")
- end
- enable = false
- end
-
- implement {
- name = "initializemathcollapsing",
- actions = enable,
- onlyonce = true,
- }
-
-end
-
-do
- -- inner under over vcenter
-
- local fixscripts = { }
- local movesub = {
- -- primes
- [0x2032] = 0xFE932,
- [0x2033] = 0xFE933,
- [0x2034] = 0xFE934,
- [0x2057] = 0xFE957,
- -- reverse primes
- [0x2035] = 0xFE935,
- [0x2036] = 0xFE936,
- [0x2037] = 0xFE937,
- }
-
- mathematics.virtualize(movesub)
-
- local options_supported = tokens.defined("Unosuperscript")
-
- local function fixsupscript(parent,current,current_char,new_char)
- if new_char ~= current_char and new_char ~= true then
- setchar(current,new_char)
- if trace_fixing then
- report_fixing("fixing subscript, replacing superscript %U by %U",current_char,new_char)
- end
- else
- if trace_fixing then
- report_fixing("fixing subscript, superscript %U",current_char)
- end
- end
- if options_supported then
- setfield(parent,"options",0x08+0x22)
- end
- end
-
- -- local function movesubscript(parent,current_nucleus,oldchar,newchar)
- -- local prev = getprev(parent)
- -- if prev and getid(prev) == noad_code then
- -- local psup = getsup(prev)
- -- local psub = getsub(prev)
- -- if not psup and not psub then
- -- fixsupscript(prev,current_nucleus,oldchar,newchar)
- -- local nucleus = getnucleus(parent)
- -- local sub = getsub(parent)
- -- setsup(prev,nucleus)
- -- setsub(prev,sub)
- -- local dummy = copy_node(nucleus)
- -- setchar(dummy,0)
- -- setnucleus(parent,dummy)
- -- setsub(parent)
- -- elseif not psup then
- -- fixsupscript(prev,current_nucleus,oldchar,newchar)
- -- local nucleus = getnucleus(parent)
- -- setsup(prev,nucleus)
- -- local dummy = copy_node(nucleus)
- -- setchar(dummy,0)
- -- setnucleus(parent,dummy)
- -- end
- -- end
- -- end
-
- local function move_none_none(parent,prev,nuc,oldchar,newchar)
- fixsupscript(prev,nuc,oldchar,newchar)
- local sub = getsub(parent)
- setsup(prev,nuc)
- setsub(prev,sub)
- local dummy = copy_node(nuc)
- setchar(dummy,0)
- setnucleus(parent,dummy)
- setsub(parent)
- end
-
- local function move_none_psub(parent,prev,nuc,oldchar,newchar)
- fixsupscript(prev,nuc,oldchar,newchar)
- setsup(prev,nuc)
- local dummy = copy_node(nuc)
- setchar(dummy,0)
- setnucleus(parent,dummy)
- end
-
- fixscripts[mathchar_code] = function(pointer,what,n,parent,nested) -- todo: switch to turn in on and off
- if parent then
- local oldchar = getchar(pointer)
- local newchar = movesub[oldchar]
- if newchar then
- local nuc = getnucleus(parent)
- if pointer == nuc then
- local sub = getsub(pointer)
- local sup = getsup(pointer)
- if sub then
- if sup then
- -- print("[char] sub sup")
- else
- -- print("[char] sub ---")
- end
- elseif sup then
- -- print("[char] --- sup")
- else
- local prev = getprev(parent)
- if prev and getid(prev) == noad_code then
- local psub = getsub(prev)
- local psup = getsup(prev)
- if psub then
- if psup then
- -- print("sub sup [char] --- ---")
- else
- -- print("sub --- [char] --- ---")
- move_none_psub(parent,prev,nuc,oldchar,newchar)
- end
- elseif psup then
- -- print("--- sup [char] --- ---")
- else
- -- print("[char] --- ---")
- move_none_none(parent,prev,nuc,oldchar,newchar)
- end
- else
- -- print("no prev [char]")
- end
- end
- else
- -- print("[char]")
- end
- end
- end
- end
-
- function noads.handlers.fixscripts(head,style,penalties)
- processnoads(head,fixscripts,"fixscripts")
- return true -- not needed
- end
-
-end
-
--- variants
-
-do
-
- 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[mathchar_code] = 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) == noad_code then
- local nucleus = getnucleus(next)
- if nucleus and getid(nucleus) == mathchar_code and getchar(nucleus) == selector then
- local variant
- local tfmdata = fontdata[getfont(pointer)]
- local mathvariants = tfmdata.resources.variants -- and variantdata
- if mathvariants then
- mathvariants = mathvariants[selector]
- if mathvariants then
- variant = mathvariants[char]
- end
- end
- if variant then
- setchar(pointer,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
- setprev(next,pointer)
- setnext(parent,getnext(next))
- flush_node(next)
- end
- end
- end
- end
-
- function handlers.variants(head,style,penalties)
- processnoads(head,variants,"unicode variant")
- return true -- not needed
- end
-
-end
-
--- for manuals
-
-do
-
- local classes = { }
- local colors = {
- [relnode_code] = "trace:dr",
- [ordnoad_code] = "trace:db",
- [binnoad_code] = "trace:dg",
- [opennoad_code] = "trace:dm",
- [closenoad_code] = "trace:dm",
- [punctnoad_code] = "trace:dc",
- -- [opdisplaylimitsnoad_code] = "",
- -- [oplimitsnoad_code] = "",
- -- [opnolimitsnoad_code] = "",
- -- [ordlimitsnoad_code] = "",
- -- [innernoad_code = "",
- -- [undernoad_code] = "",
- -- [overnoad_code] = "",
- -- [vcenternoad_code] = "",
- }
-
- local setcolor = colortracers.set
- local resetcolor = colortracers.reset
-
- classes[mathchar_code] = 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 -- not needed
- end
-
- registertracker("math.classes",function(v)
- setaction("math","noads.handlers.classes",v)
- end)
-
-end
-
--- experimental
-
-do
-
- -- mathematics.registerdomain {
- -- name = "foo",
- -- parents = { "bar" },
- -- characters = {
- -- [0x123] = { char = 0x234, class = binary },
- -- },
- -- }
-
- local domains = { }
- local categories = { }
- local numbers = { }
- local a_mathdomain = privateattribute("mathdomain")
- mathematics.domains = categories
- local permitted = {
- ordinary = ordnoad_code,
- binary = binnoad_code,
- relation = relnode_code,
- punctuation = punctnoad_code,
- inner = innernoad_code,
- }
-
- function mathematics.registerdomain(data)
- local name = data.name
- if not name then
- return
- end
- local attr = #numbers + 1
- categories[name] = data
- numbers[attr] = data
- data.attribute = attr
- -- we delay hashing
- return attr
- end
-
- local enable
-
- enable = function()
- enableaction("math", "noads.handlers.domains")
- if trace_domains then
- report_domains("enabling math domains")
- end
- enable = false
- end
-
- function mathematics.setdomain(name)
- if enable then
- enable()
- end
- local data = name and name ~= v_reset and categories[name]
- texsetattribute(a_mathdomain,data and data.attribute or unsetvalue)
- end
-
- function mathematics.getdomain(name)
- if enable then
- enable()
- end
- local data = name and name ~= v_reset and categories[name]
- context(data and data.attribute or unsetvalue)
- end
-
- implement {
- name = "initializemathdomain",
- actions = enable,
- onlyonce = true,
- }
-
- implement {
- name = "setmathdomain",
- arguments = "string",
- actions = mathematics.setdomain,
- }
-
- implement {
- name = "getmathdomain",
- arguments = "string",
- actions = mathematics.getdomain,
- }
-
- local function makehash(data)
- local hash = { }
- local parents = data.parents
- if parents then
- local function merge(name)
- if name then
- local c = categories[name]
- if c then
- local hash = c.hash
- if not hash then
- hash = makehash(c)
- end
- for k, v in next, hash do
- hash[k] = v
- end
- end
- end
- end
- if type(parents) == "string" then
- merge(parents)
- elseif type(parents) == "table" then
- for i=1,#parents do
- merge(parents[i])
- end
- end
- end
- local characters = data.characters
- if characters then
- for k, v in next, characters do
- -- local chr = n.char
- local cls = v.class
- if cls then
- v.code = permitted[cls]
- else
- -- invalid class
- end
- hash[k] = v
- end
- end
- data.hash = hash
- return hash
- end
-
- domains[mathchar_code] = function(pointer,what,n,parent)
- local attr = getattr(pointer,a_mathdomain)
- if attr then
- local domain = numbers[attr]
- if domain then
- local hash = domain.hash
- if not hash then
- hash = makehash(domain)
- end
- local char = getchar(pointer)
- local okay = hash[char]
- if okay then
- local chr = okay.char
- local cls = okay.code
- if chr and chr ~= char then
- setchar(pointer,chr)
- end
- if cls and cls ~= getsubtype(parent) then
- setsubtype(parent,cls)
- end
- end
- end
- end
- end
-
- function handlers.domains(head,style,penalties)
- processnoads(head,domains,"domains")
- return true -- not needed
- end
-
-end
-
--- just for me
-
-function handlers.showtree(head,style,penalties)
- inspect(nodes.totree(tonut(head)))
-end
-
-registertracker("math.showtree",function(v)
- setaction("math","noads.handlers.showtree",v)
-end)
-
--- also for me
-
-do
-
- local applyvisuals = nuts.applyvisuals
- local visual = false
-
- function handlers.makeup(head)
- applyvisuals(head,visual)
- end
-
- registertracker("math.makeup",function(v)
- visual = v
- setaction("math","noads.handlers.makeup",v)
- end)
-
-end
-
--- the normal builder
-
-do
-
- local force_penalties = false
-
- -- registertracker("math.penalties",function(v)
- -- force_penalties = v
- -- end)
-
- function builders.kernel.mlist_to_hlist(head,style,penalties)
- return mlist_to_hlist(head,style,force_penalties or penalties)
- end
-
- -- function builders.kernel.mlist_to_hlist(head,style,penalties)
- -- local h = mlist_to_hlist(head,style,force_penalties or penalties)
- -- inspect(nodes.totree(h,true,true,true))
- -- return h
- -- end
-
- implement {
- name = "setmathpenalties",
- arguments = "integer",
- actions = function(p)
- force_penalties = p > 0
- end,
- }
-
-end
-
-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)
- head = actions(head,style,penalties)
- stoptiming(noads)
- return head
-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)