diff options
author | Mojca Miklavec <mojca.miklavec@gmail.com> | 2012-05-14 17:38:55 +0000 |
---|---|---|
committer | Mojca Miklavec <mojca.miklavec@gmail.com> | 2012-05-14 17:38:55 +0000 |
commit | 15995e10bfc68edf79970c4ea4fbb6678566c46e (patch) | |
tree | 2de7ca2a83f2d37ef043ad7429a5cb945bb79ddb /Master/texmf-dist/tex/context/base/math-noa.lua | |
parent | c9a39f716f1e5ec820ed3aab2c9aef25c5a9d730 (diff) |
ConTeXt 2012.05.14 16:00
git-svn-id: svn://tug.org/texlive/trunk@26371 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/tex/context/base/math-noa.lua')
-rw-r--r-- | Master/texmf-dist/tex/context/base/math-noa.lua | 533 |
1 files changed, 439 insertions, 94 deletions
diff --git a/Master/texmf-dist/tex/context/base/math-noa.lua b/Master/texmf-dist/tex/context/base/math-noa.lua index c298a8068ae..8caf21cc2cf 100644 --- a/Master/texmf-dist/tex/context/base/math-noa.lua +++ b/Master/texmf-dist/tex/context/base/math-noa.lua @@ -15,6 +15,9 @@ if not modules then modules = { } end modules ['math-noa'] = { -- beware: names will change as we wil make noads.xxx.handler i.e. xxx -- subnamespaces +-- 20D6 -> 2190 +-- 20D7 -> 2192 + local utf = unicode.utf8 local utfchar, utfbyte = utf.char, utf.byte @@ -31,18 +34,43 @@ local trace_remapping = false trackers.register("math.remapping", functio local trace_processing = false trackers.register("math.processing", function(v) trace_processing = v end) local trace_analyzing = false trackers.register("math.analyzing", function(v) trace_analyzing = v end) local trace_normalizing = false trackers.register("math.normalizing", function(v) trace_normalizing = v end) +local trace_collapsing = false trackers.register("math.collapsing", function(v) trace_collapsing = v end) +local trace_goodies = false trackers.register("math.goodies", function(v) trace_goodies = v end) +local trace_variants = false trackers.register("math.variants", function(v) trace_variants = v end) +local trace_italics = false trackers.register("math.italics", function(v) trace_italics = v end) +local trace_families = false trackers.register("math.families", function(v) trace_families = v end) + +local check_coverage = true directives.register("math.checkcoverage", function(v) check_coverage = v end) local report_processing = logs.reporter("mathematics","processing") local report_remapping = logs.reporter("mathematics","remapping") local report_normalizing = logs.reporter("mathematics","normalizing") +local report_collapsing = logs.reporter("mathematics","collapsing") +local report_goodies = logs.reporter("mathematics","goodies") +local report_variants = logs.reporter("mathematics","variants") +local report_italics = logs.reporter("mathematics","italics") +local report_families = logs.reporter("mathematics","families") local set_attribute = node.set_attribute local has_attribute = node.has_attribute local mlist_to_hlist = node.mlist_to_hlist local font_of_family = node.family_font +local insert_node_after = node.insert_after +local free_node = node.free +local new_node = node.new -- todo: pool: math_noad math_sub + +local new_kern = nodes.pool.kern local fonthashes = fonts.hashes local fontdata = fonthashes.identifiers +local fontcharacters = fonthashes.characters +local fontproperties = fonthashes.properties +local fontitalics = fonthashes.italics +local fontquads = fonthashes.quads + +local variables = interfaces.variables +local texattribute = tex.attribute +local unsetvalue = attributes.unsetvalue noads = noads or { } -- todo: only here local noads = noads @@ -97,9 +125,13 @@ local function process(start,what,n,parent) end local proc = what[id] if proc then - local done, newstart = proc(start,what,n,parent or start.prev) + -- report_processing("start processing") + local done, newstart = proc(start,what,n,parent) -- prev is bugged: or start.prev 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 @@ -110,7 +142,8 @@ local function process(start,what,n,parent) noad = start.sup if noad then process(noad,what,n,start) end -- list noad = start.sub if noad then process(noad,what,n,start) end -- list elseif id == math_box or id == math_sub then - local noad = start.list if noad then process(noad,what,n,start) end -- list + -- local noad = start.list if noad then process(noad,what,n,start) end -- list + local noad = start.head if noad then process(noad,what,n,start) end -- list elseif id == math_fraction then local noad = start.num if noad then process(noad,what,n,start) end -- list noad = start.denom if noad then process(noad,what,n,start) end -- list @@ -142,7 +175,17 @@ local function process(start,what,n,parent) end end -noads.process = process +local function processnoads(head,actions,banner) + if trace_processing then + report_processing("start '%s'",banner) + process(head,actions) + report_processing("stop '%s'",banner) + else + process(head,actions) + end +end + +noads.process = processnoads -- character remapping @@ -158,34 +201,30 @@ end local remapalphabets = mathematics.remapalphabets local setnodecolor = nodes.tracers.colors.set --- we can have a global famdata == fonts.famdata - --~ This does not work out well, as there are no fallbacks. Ok, we could --~ define a poor mans simplify mechanism. ---~ ---~ local function checked(pointer) ---~ local char = pointer.char ---~ local fam = pointer.fam ---~ local id = font_of_family(fam) ---~ local tfmdata = fontdata[id] ---~ local tc = tfmdata and tfmdata.characters ---~ 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 ---~ pointer.char = newchar ---~ return true ---~ end ---~ end ---~ end -local current_id, current_characters +local function checked(pointer) + local char = pointer.char + local fam = 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 + set_attribute(pointer,exportstatus,char) -- testcase: exponentiale + pointer.char = newchar + return true + end + end +end processors.relocate[math_char] = function(pointer) local g = has_attribute(pointer,mathgreek) or 0 @@ -202,15 +241,8 @@ processors.relocate[math_char] = function(pointer) if newchar then local fam = pointer.fam local id = font_of_family(fam) - -- - local tfmdata = fontdata[id] - if tfmdata and tfmdata.characters[newchar] then - -- -- to be tested: - -- if id ~= current_id then - -- current_id = id - -- current_characters = fontdata[id].characters - -- end - -- if current_characters and current_characters[newchar] then + local characters = fontcharacters[id] + if characters and characters[newchar] then if trace_remapping then report_remap("char",id,char,newchar) end @@ -219,18 +251,19 @@ processors.relocate[math_char] = function(pointer) end pointer.char = newchar return true - elseif trace_remapping then - report_remap("char",id,char,newchar," fails") + else + if trace_remapping then + report_remap("char",id,char,newchar," fails") + end end - else - -- return checked(pointer) end - else - -- return checked(pointer) 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) @@ -246,7 +279,41 @@ processors.relocate[math_delim] = function(pointer) end function handlers.relocate(head,style,penalties) - process(head,processors.relocate) + processnoads(head,processors.relocate,"relocate") + return true +end + +-- rendering (beware, not exported) + +local a_mathrendering = attributes.private("mathrendering") +local a_exportstatus = attributes.private("exportstatus") + +processors.render = { } + +local rendersets = mathematics.renderings.numbers or { } -- store + +processors.render[math_char] = function(pointer) + local attr = has_attribute(pointer,a_mathrendering) + if attr and attr > 0 then + local char = pointer.char + local renderset = rendersets[attr] + if renderset then + local newchar = renderset[char] + if newchar then + local fam = pointer.fam + local id = font_of_family(fam) + local characters = fontcharacters[id] + if characters and characters[newchar] then + pointer.char = newchar + set_attribute(pointer,a_exportstatus,char) + end + end + end + end +end + +function handlers.render(head,style,penalties) + processnoads(head,processors.render,"render") return true end @@ -281,7 +348,7 @@ resize[math_fence] = function(pointer) end function handlers.resize(head,style,penalties) - process(head,resize) + processnoads(head,resize,"resize") return true end @@ -295,8 +362,9 @@ local chardata = characters.data -- only [nd,ll,ul][po][nd,ll,ul] -respace[math_noad] = function(pointer) - if pointer.subtype == noad_ord then +respace[math_char] = function(pointer,what,n,parent) -- not math_noad .. math_char ... and then parent + pointer = parent + if pointer and pointer.subtype == noad_ord then local a = has_attribute(pointer,mathpunctuation) if a and a > 0 then set_attribute(pointer,mathpunctuation,0) @@ -322,14 +390,14 @@ respace[math_noad] = function(pointer) local lc = chardata[last_char] lc = lc and lc.category if lc == "nd" or lc == "ll" or lc == "lu" then - local ord = node.new(math_noad) -- todo: pool + local ord = new_node(math_noad) -- todo: pool ord.subtype, ord.nucleus, ord.sub, ord.sup, ord.attr = noad_ord, next_noad.nucleus, next_noad.sub, next_noad.sup, next_noad.attr -- next_noad.nucleus, next_noad.sub, next_noad.sup, next_noad.attr = nil, nil, nil, nil next_noad.nucleus, next_noad.sub, next_noad.sup = nil, nil, nil -- else crash with attributes ref count --~ next_noad.attr = nil ord.next = last_noad pointer.next = ord - node.free(next_noad) + free_node(next_noad) end end end @@ -343,7 +411,7 @@ respace[math_noad] = function(pointer) end function handlers.respace(head,style,penalties) - process(head,respace) + processnoads(head,respace,"respace") return true end @@ -357,34 +425,50 @@ local collapse = { } processors.collapse = collapse local mathpairs = characters.mathpairs -collapse[math_noad] = function(pointer) - if pointer.subtype == noad_rel then - local current_nucleus = pointer.nucleus - if current_nucleus.id == math_char then - local current_char = current_nucleus.char - local mathpair = mathpairs[current_char] - if mathpair then - local next_noad = pointer.next - if next_noad and next_noad.id == math_noad and next_noad.subtype == noad_rel then - local next_nucleus = next_noad.nucleus - if next_nucleus.id == math_char then - local next_char = next_nucleus.char - local newchar = mathpair[next_char] - if newchar then - local fam = current_nucleus.fam - local id = font_of_family(fam) - local tfmdata = fontdata[id] - if tfmdata and tfmdata.characters[newchar] then - -- print("!!!!!",current_char,next_char,newchar) - current_nucleus.char = newchar - local next_next_noad = next_noad.next - if next_next_noad then - pointer.next = next_next_noad - next_next_noad.prev = pointer - else - pointer.next = nil +mathpairs[0x2032] = { [0x2032] = 0x2033, [0x2033] = 0x2034 } -- (prime,prime) (prime,doubleprime) +mathpairs[0x2033] = { [0x2032] = 0x2034 } -- (doubleprime,prime) + +local function collapsepair(pointer,what,n,parent) -- todo: switch to turn in on and off + if parent then + local subtype = parent.subtype + if subtype == noad_rel or subtype == noad_ord then -- ord is new + local current_nucleus = parent.nucleus + if not parent.sub and not parent.sup and current_nucleus.id == math_char then + local current_char = current_nucleus.char + local mathpair = mathpairs[current_char] + if mathpair then + local next_noad = parent.next + if next_noad and next_noad.id == math_noad then + local next_subtype = next_noad.subtype + if next_subtype == noad_rel or next_subtype == noad_ord then -- ord is new + local next_nucleus = next_noad.nucleus + if next_nucleus.id == math_char then + local next_char = next_nucleus.char + local newchar = mathpair[next_char] + if newchar then + local fam = 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+%05X + U+%05X => U+%05X",current_char,next_char,newchar) + end + current_nucleus.char = newchar + local next_next_noad = next_noad.next + if next_next_noad then + parent.next = next_next_noad + next_next_noad.prev = parent + else + parent.next = nil + end + parent.sup = next_noad.sup + parent.sub = next_noad.sub + next_noad.sup = nil + next_noad.sub = nil + free_node(next_noad) + collapsepair(pointer,what,n,parent) + end end - node.free(next_noad) end end end @@ -394,8 +478,10 @@ collapse[math_noad] = function(pointer) end end +collapse[math_char] = collapsepair + function noads.handlers.collapse(head,style,penalties) - process(head,collapse) + processnoads(head,collapse,"collapse") return true end @@ -408,7 +494,8 @@ local subscripts = characters.subscripts local replaced = { } -local function replace(pointer) +local function replace(pointer,what,n,parent) + pointer = parent -- we're following the parent list (chars trigger this) local next = pointer.next local start_super, stop_super, start_sub, stop_sub local mode = "unset" @@ -459,7 +546,7 @@ local function replace(pointer) if start_super == stop_super then pointer.sup = start_super.nucleus else - local list = node.new(math_sub) -- todo attr + local list = new_node(math_sub) -- todo attr list.head = start_super pointer.sup = list end @@ -472,7 +559,7 @@ local function replace(pointer) if start_sub == stop_sub then pointer.sub = start_sub.nucleus else - local list = node.new(math_sub) -- todo attr + local list = new_node(math_sub) -- todo attr list.head = start_sub pointer.sub = list end @@ -481,15 +568,13 @@ local function replace(pointer) end stop_sub.next = nil end + -- we could return stop end - unscript[math_noad] = replace --- unscript[math_accent] = replace --- unscript[math_radical] = replace --- unscript[math_fraction] = replace +unscript[math_char] = replace -- not noads as we need to recurse function handlers.unscript(head,style,penalties) - process(head,unscript) + processnoads(head,unscript,"unscript") return true end @@ -504,7 +589,8 @@ statistics.register("math script replacements", function() end end) --- math alternates: (in xits lgf: $ABC$ $\cal ABC$ $\mathalternate{cal}\cal ABC$) +-- math alternates: (in xits lgf: $ABC$ $\cal ABC$ $\mathalternate{cal}\cal ABC$) +-- math alternates: (in lucidanova lgf: $ABC \mathalternate{italic} ABC$) local function initializemathalternates(tfmdata) local goodies = tfmdata.goodies @@ -516,6 +602,9 @@ local function initializemathalternates(tfmdata) local mathgoodies = goodies[i].mathematics local alternates = mathgoodies and mathgoodies.alternates if alternates then + if trace_goodies then + report_goodies("loading alternates for font '%s'",tfmdata.properties.name) + end local lastattribute, attributes = 0, { } for k, v in next, alternates do lastattribute = lastattribute + 1 @@ -541,24 +630,24 @@ registerotffeature { local getalternate = otf.getalternate -local mathalternate = attributes.private("mathalternate") +local a_mathalternate = attributes.private("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.mathalternates + local mathalternates = tfmdata.shared and tfmdata.shared.mathalternates if mathalternates then local m = mathalternates[tag] - tex.attribute[mathalternate] = m and m.attribute or attributes.unsetvalue + tex.attribute[a_mathalternate] = m and m.attribute or unsetvalue end end alternate[math_char] = function(pointer) - local a = has_attribute(pointer,mathalternate) + local a = has_attribute(pointer,a_mathalternate) if a and a > 0 then - set_attribute(pointer,mathalternate,0) + set_attribute(pointer,a_mathalternate,0) local tfmdata = fontdata[font_of_family(pointer.fam)] -- we can also have a famdata local mathalternatesattributes = tfmdata.shared.mathalternatesattributes if mathalternatesattributes then @@ -572,7 +661,256 @@ alternate[math_char] = function(pointer) end function handlers.check(head,style,penalties) - process(head,alternate) + processnoads(head,alternate,"check") + return true +end + +-- experiment (when not present fall back to fam 0) -- needs documentation + +-- 0-2 regular +-- 3-5 bold +-- 6-8 pseudobold + +local families = { } +local a_mathfamily = attributes.private("mathfamily") +local boldmap = mathematics.boldmap + +local tracemap = { [0] = + "regular", + "regular", + "regular", + "bold", + "bold", + "bold", + "pseudobold", + "pseudobold", + "pseudobold", +} + +families[math_char] = function(pointer) + if pointer.fam == 0 then + local a = has_attribute(pointer,a_mathfamily) + if a and a > 0 then + set_attribute(pointer,a_mathfamily,0) + if a > 5 then + local char = pointer.char + local bold = boldmap[char] + local newa = a - 3 + if bold then + set_attribute(pointer,exportstatus,char) + pointer.char = bold + if trace_families then + report_families("replacing U+%05X by bold U+%05X, family %s (%s) becomes %s (%s)", + char,bold,a,tracemap[a],newa,tracemap[newa]) + end + else + if trace_families then + report_families("no bold replacement for U+%05X, family %s (%s) becomes %s (%s)", + char,a,tracemap[a],newa,tracemap[newa]) + end + end + pointer.fam = newa + else + if trace_families then + report_families("family of U+%05X becomes %s (%s)", + pointer.char,a,tracemap[a]) + end + pointer.fam = a + end + else + -- pointer.fam = 0 + end + end +end + +families[math_delim] = function(pointer) + if pointer.small_fam == 0 then + local a = has_attribute(pointer,a_mathfamily) + if a and a > 0 then + set_attribute(pointer,a_mathfamily,0) + if a > 5 then + -- no bold delimiters in unicode + a = a - 3 + end + pointer.small_fam = a + pointer.large_fam = a + else + pointer.small_fam = 0 + 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 + +-- 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) + +local a_mathitalics = attributes.private("mathitalics") + +local italics = { } +local default_factor = 1/20 + +italics[math_char] = function(pointer,what,n,parent) + local method = has_attribute(pointer,a_mathitalics) + if method and method > 0 then + local char = pointer.char + local font = font_of_family(pointer.fam) -- todo: table + local correction + if method == 1 then + -- only font data triggered by fontitalics + local italics = fontitalics[font] + if italics then + local character = fontcharacters[font][char] + correction = character and character.italic_correction -- or character.italic (this one is for tex) + end + elseif method == 2 then + -- only font data triggered by fontdata + local character = fontcharacters[font][char] + correction = character and character.italic_correction -- or character.italic (this one is for tex) + 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*fontquads[font] + end + elseif method == 4 then + -- combination of 1 and 3 + local italics = fontitalics[font] + if italics then + local character = fontcharacters[font][char] + correction = character and character.italic_correction -- or character.italic (this one is for tex) + 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*fontquads[font] + end + end + end + if correction and correction ~= 0 then + local next_noad = parent.next + if next_noad and next_noad.id == math_noad then + local next_subtype = next_noad.subtype + if next_subtype == noad_punct or next_subtype == noad_ord then + local next_nucleus = next_noad.nucleus + if next_nucleus.id == math_char then + local next_char = next_nucleus.char + if not chardata[next_char].italic then -- or category + if trace_italics then + report_italics("method %s: adding %s italic correction between %s (0x%05X) and %s (0x%05X)", + method,number.points(correction),utfchar(char),char,utfchar(next_char),next_char) + end + insert_node_after(parent,parent,new_kern(correction)) + 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 + texattribute[a_mathitalics] = unsetvalue + else + texattribute[a_mathitalics] = tonumber(n) or unsetvalue + end +end + +function mathematics.resetitalics() + texattribute[a_mathitalics] = unsetvalue +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 = pointer.char + local selector = validvariants[char] + if selector then + local next = parent.next + if next and next.id == math_noad then + local nucleus = next.nucleus + if nucleus and nucleus.id == math_char and nucleus.char == selector then + local variant + local tfmdata = fontdata[font_of_family(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 + pointer.char = variant + set_attribute(pointer,exportstatus,char) -- we don't export the variant as it's visual markup + if trace_variants then + report_variants("variant (U+%05X,U+%05X) replaced by U+%05X",char,selector,variant) + end + else + if trace_variants then + report_variants("no variant (U+%05X,U+%05X)",char,selector) + end + end + next.prev = pointer + parent.next = next.next + free_node(next) + end + end + end +end + +function handlers.variants(head,style,penalties) + processnoads(head,variants,"unicode variant") return true end @@ -596,12 +934,13 @@ end tasks.new { name = "math", arguments = 2, + processor = utilities.sequencers.nodeprocessor, sequence = { "before", "normalizers", "builders", "after", - } + }, } tasks.freezegroup("math", "normalizers") -- experimental @@ -625,3 +964,9 @@ callbacks.register('mlist_to_hlist',processors.mlist_to_hlist,"preprocessing mat statistics.register("math processing time", function() return statistics.elapsedseconds(noads) end) + +-- interface + +commands.setmathalternate = mathematics.setalternate +commands.setmathitalics = mathematics.setitalics +commands.resetmathitalics = mathematics.resetitalics |