diff options
Diffstat (limited to 'otfl-font-otn.lua')
-rw-r--r-- | otfl-font-otn.lua | 157 |
1 files changed, 102 insertions, 55 deletions
diff --git a/otfl-font-otn.lua b/otfl-font-otn.lua index c4c42fa..d23a8a0 100644 --- a/otfl-font-otn.lua +++ b/otfl-font-otn.lua @@ -134,6 +134,8 @@ local trace_cursive = false trackers.register("otf.cursive", function local trace_preparing = false trackers.register("otf.preparing", function(v) trace_preparing = v end) local trace_bugs = false trackers.register("otf.bugs", function(v) trace_bugs = v end) local trace_details = false trackers.register("otf.details", function(v) trace_details = v end) +local trace_applied = false trackers.register("otf.applied", function(v) trace_applied = v end) +local trace_steps = false trackers.register("otf.steps", function(v) trace_steps = v end) trackers.register("otf.verbose_chain", function(v) otf.setcontextchain(v and "verbose") end) trackers.register("otf.normal_chain", function(v) otf.setcontextchain(v and "normal") end) @@ -155,6 +157,7 @@ local has_attribute = node.has_attribute local zwnj = 0x200C local zwj = 0x200D local wildcard = "*" +local default = "dflt" local split_at_space = lpeg.Ct(lpeg.splitat(" ")) -- no trailing or multiple spaces anyway @@ -201,11 +204,13 @@ local lookuptable = false local anchorlookups = false local handlers = { } local rlmode = 0 +local featurevalue = false -- we cheat a bit and assume that a font,attr combination are kind of ranged local context_setups = fonts.define.specify.context_setups local context_numbers = fonts.define.specify.context_numbers +local context_merged = fonts.define.specify.context_merged -- we cannot optimize with "start = first_character(head)" because then we don't -- know which rlmode we're in which messes up cursive handling later on @@ -226,7 +231,10 @@ local registerstep = (nodes and nodes.tracers and nodes.tracers.steppers.regi local registermessage = (nodes and nodes.tracers and nodes.tracers.steppers.message) or function() end local function logprocess(...) - logs.report("otf direct",registermessage(...)) + if trace_steps then + registermessage(...) + end + logs.report("otf direct",...) end local function logwarning(...) logs.report("otf direct",...) @@ -259,9 +267,9 @@ local function cref(kind,chainname,chainlookupname,lookupname,index) if index then return format("feature %s, chain %s, sub %s, lookup %s, index %s",kind,chainname,chainlookupname,lookupname,index) elseif lookupname then - return format("feature %s, chain %s, sub %s, lookup %s",kind,chainname,chainlookupname,lookupname) + return format("feature %s, chain %s, sub %s, lookup %s",kind,chainname or "?",chainlookupname or "?",lookupname) elseif chainlookupname then - return format("feature %s, chain %s, sub %s",kind,chainname,chainlookupname) + return format("feature %s, chain %s, sub %s",kind,chainname or "?",chainlookupname) elseif chainname then return format("feature %s, chain %s",kind,chainname) else @@ -369,7 +377,7 @@ function handlers.gsub_single(start,kind,lookupname,replacement) end local function alternative_glyph(start,alternatives,kind,chainname,chainlookupname,lookupname) -- chainname and chainlookupname optional - local value, choice, n = tfmdata.shared.features[kind], nil, #alternatives + local value, choice, n = featurevalue or tfmdata.shared.features[kind], nil, #alternatives -- global value, brrr if value == "random" then local r = math.random(1,n) value, choice = format("random, choice %s",r), alternatives[r] @@ -381,6 +389,8 @@ local function alternative_glyph(start,alternatives,kind,chainname,chainlookupna value, choice = "default, choice 1", alternatives[1] elseif value > n then value, choice = format("no %s variants, taking %s",value,n), alternatives[n] + elseif value == 0 then + value, choice = format("choice %s (no change)",value), start.char elseif value < 1 then value, choice = format("no %s variants, taking %s",value,1), alternatives[1] else @@ -554,7 +564,7 @@ function handlers.gpos_mark2base(start,kind,lookupname,markanchors,sequence) end else -- if trace_bugs then -- logwarning("%s: char %s is missing in font",pref(kind,lookupname),gref(basechar)) - fonts.register_missing(currentfont,basechar) + fonts.register_message(currentfont,basechar,"no base anchors") end elseif trace_bugs then logwarning("%s: prev node is no char",pref(kind,lookupname)) @@ -624,7 +634,7 @@ function handlers.gpos_mark2ligature(start,kind,lookupname,markanchors,sequence) end else -- if trace_bugs then -- logwarning("%s: char %s is missing in font",pref(kind,lookupname),gref(basechar)) - fonts.register_missing(currentfont,basechar) + fonts.register_message(currentfont,basechar,"no base anchors") end elseif trace_bugs then logwarning("%s: prev node is no char",pref(kind,lookupname)) @@ -638,8 +648,8 @@ end function handlers.gpos_mark2mark(start,kind,lookupname,markanchors,sequence) local markchar = start.char if marks[markchar] then - local alreadydone = markonce and has_attribute(start,markmark) - if not alreadydone then +--~ local alreadydone = markonce and has_attribute(start,markmark) +--~ if not alreadydone then local base = start.prev -- [glyph] [basemark] [start=mark] if base and base.id == glyph and base.subtype<256 and base.font == currentfont then -- subtype test can go local basechar = base.char @@ -670,14 +680,14 @@ function handlers.gpos_mark2mark(start,kind,lookupname,markanchors,sequence) end else -- if trace_bugs then -- logwarning("%s: char %s is missing in font",pref(kind,lookupname),gref(basechar)) - fonts.register_missing(currentfont,basechar) + fonts.register_message(currentfont,basechar,"no base anchors") end elseif trace_bugs then logwarning("%s: prev node is no mark",pref(kind,lookupname)) end - elseif trace_marks and trace_details then - logprocess("%s, mark %s is already bound (n=%s), ignoring mark2mark",pref(kind,lookupname),gref(markchar),alreadydone) - end +--~ elseif trace_marks and trace_details then +--~ logprocess("%s, mark %s is already bound (n=%s), ignoring mark2mark",pref(kind,lookupname),gref(markchar),alreadydone) +--~ end elseif trace_bugs then logwarning("%s: mark %s is no mark",pref(kind,lookupname),gref(markchar)) end @@ -725,7 +735,7 @@ function handlers.gpos_cursive(start,kind,lookupname,exitanchors,sequence) -- to end else -- if trace_bugs then -- logwarning("%s: char %s is missing in font",pref(kind,lookupname),gref(startchar)) - fonts.register_missing(currentfont,startchar) + fonts.register_message(currentfont,startchar,"no entry anchors") end break end @@ -822,7 +832,10 @@ local chainmores = { } local chainprocs = { } local function logprocess(...) - logs.report("otf subchain",registermessage(...)) + if trace_steps then + registermessage(...) + end + logs.report("otf subchain",...) end local function logwarning(...) logs.report("otf subchain",...) @@ -862,7 +875,10 @@ end -- end local function logprocess(...) - logs.report("otf chain",registermessage(...)) + if trace_steps then + registermessage(...) + end + logs.report("otf chain",...) end local function logwarning(...) logs.report("otf chain",...) @@ -1270,8 +1286,8 @@ end function chainprocs.gpos_mark2mark(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname) local markchar = start.char if marks[markchar] then - local alreadydone = markonce and has_attribute(start,markmark) - if not alreadydone then +--~ local alreadydone = markonce and has_attribute(start,markmark) +--~ if not alreadydone then -- local markanchors = descriptions[markchar].anchors markanchors = markanchors and markanchors.mark local subtables = currentlookup.subtables local lookupname = subtables[1] @@ -1312,9 +1328,9 @@ function chainprocs.gpos_mark2mark(start,stop,kind,chainname,currentcontext,cach elseif trace_bugs then logwarning("%s: mark %s has no anchors",cref(kind,chainname,chainlookupname,lookupname),gref(markchar)) end - elseif trace_marks and trace_details then - logprocess("%s, mark %s is already bound (n=%s), ignoring mark2mark",pref(kind,lookupname),gref(markchar),alreadydone) - end +--~ elseif trace_marks and trace_details then +--~ logprocess("%s, mark %s is already bound (n=%s), ignoring mark2mark",pref(kind,lookupname),gref(markchar),alreadydone) +--~ end elseif trace_bugs then logwarning("%s: mark %s is no mark",cref(kind,chainname,chainlookupname),gref(markchar)) end @@ -1371,7 +1387,7 @@ function chainprocs.gpos_cursive(start,stop,kind,chainname,currentcontext,cache, end else -- if trace_bugs then -- logwarning("%s: char %s is missing in font",pref(kind,lookupname),gref(startchar)) - fonts.register_missing(currentfont,startchar) + fonts.register_message(currentfont,startchar,"no entry anchors") end break end @@ -1761,7 +1777,10 @@ otf.setcontextchain() local missing = { } -- we only report once local function logprocess(...) - logs.report("otf process",registermessage(...)) + if trace_steps then + registermessage(...) + end + logs.report("otf process",...) end local function logwarning(...) logs.report("otf process",...) @@ -1798,14 +1817,21 @@ function fonts.methods.node.otf.features(head,font,attr) local sequences = luatex.sequences lookuptable = luatex.lookups local done = false - local script, language, enabled - if attr and attr > 0 then + local script, language, s_enabled, a_enabled, dyn + local attribute_driven = attr and attr ~= 0 + if attribute_driven then local features = context_setups[context_numbers[attr]] -- could be a direct list + dyn = context_merged[attr] or 0 language, script = features.language or "dflt", features.script or "dflt" - enabled = features -- shared.features -- can be made local to the resolver + a_enabled = features -- shared.features -- can be made local to the resolver + if dyn == 2 or dyn == -2 then + -- font based + s_enabled = shared.features + end else language, script = tfmdata.language or "dflt", tfmdata.script or "dflt" - enabled = shared.features -- can be made local to the resolver + s_enabled = shared.features -- can be made local to the resolver + dyn = 0 end -- we can save some runtime by caching feature tests local res = resolved[font] if not res then res = { } resolved[font] = res end @@ -1817,44 +1843,62 @@ function fonts.methods.node.otf.features(head,font,attr) local success = false local sequence = sequences[s] local r = ra[s] -- cache - if not r then - local typ = sequence.type - -- we could save this in the tma/c file ---~ local chain ---~ if typ == "gsub_contextchain" or typ == "gpos_contextchain" then ---~ chain = 1 ---~ elseif typ == "gsub_reversecontextchain" or typ == "gpos_reversecontextchain" then ---~ chain = -1 ---~ else ---~ chain = 0 ---~ end -local chain = sequence.chain or 0 + if r == nil then + -- + -- this bit will move to font-ctx and become a function + --- + local chain = sequence.chain or 0 local features = sequence.features if not features then -- indirect lookup, part of chain (todo: make this a separate table) - r = { false, false, chain } + r = false -- { false, false, chain } else - local valid, attribute, kind = false, false + local valid, attribute, kind, what = false, false for k,v in next, features do - if enabled[k] then + -- we can quit earlier but for the moment we want the tracing + local s_e = s_enabled and s_enabled[k] + local a_e = a_enabled and a_enabled[k] + if s_e or a_e then local l = v[script] or v[wildcard] - if l and (l[language] or l[wildcard]) then - valid = true - kind = k - attribute = special_attributes[k] or false -- only first, so we assume simple fina's - break + if l then + -- not l[language] or l[default] or l[wildcard] because we want tracing + -- only first attribute match check, so we assume simple fina's + -- default can become a font feature itself + if l[language] then +--~ valid, what = true, language + valid, what = s_e or a_e, language + -- elseif l[default] then + -- valid, what = true, default + elseif l[wildcard] then +--~ valid, what = true, wildcard + valid, what = s_e or a_e, wildcard + end + if valid then + kind, attribute = k, special_attributes[k] or false + if a_e and dyn < 0 then + valid = false + end + if trace_applied then + local typ, action = match(sequence.type,"(.*)_(.*)") + logs.report("otf node mode", + "%s font: %03i, dynamic: %03i, kind: %s, lookup: %3i, script: %-4s, language: %-4s (%-4s), type: %s, action: %s, name: %s", + (valid and "+") or "-",font,attr or 0,kind,s,script,language,what,typ,action,sequence.name) + end + break + end end end end - if kind then + if valid then r = { valid, attribute, chain, kind } else - r = { valid, attribute, chain, "generic" } -- false anyway + r = false -- { valid, attribute, chain, "generic" } -- false anyway, could be flag instead of table end end ra[s] = r end - if r[1] then -- valid + featurevalue = r and r[1] -- todo: pass to function instead of using a global + if featurevalue then local attribute, chain, typ, subtables = r[2], r[3], sequence.type, sequence.subtables if chain < 0 then -- this is a limited case, no special treatments like 'init' etc @@ -1865,7 +1909,8 @@ local chain = sequence.chain or 0 while start do local id = start.id if id == glyph then - if start.subtype<256 and start.font == font and (not attr or has_attribute(start,0,attr)) then +--~ if start.subtype<256 and start.font == font and (not attr or has_attribute(start,0,attr)) then + if start.subtype<256 and start.font == font and has_attribute(start,0,attr) then for i=1,#subtables do local lookupname = subtables[i] local lookupcache = thecache[lookupname] @@ -1904,7 +1949,8 @@ local chain = sequence.chain or 0 while start do local id = start.id if id == glyph then - if start.font == font and start.subtype<256 and (not attr or has_attribute(start,0,attr)) and (not attribute or has_attribute(start,state,attribute)) then +--~ if start.font == font and start.subtype<256 and (not attr or has_attribute(start,0,attr)) and (not attribute or has_attribute(start,state,attribute)) then + if start.font == font and start.subtype<256 and has_attribute(start,0,attr) and (not attribute or has_attribute(start,state,attribute)) then local lookupmatch = lookupcache[start.char] if lookupmatch then -- sequence kan weg @@ -1965,7 +2011,8 @@ local chain = sequence.chain or 0 while start do local id = start.id if id == glyph then - if start.subtype<256 and start.font == font and (not attr or has_attribute(start,0,attr)) and (not attribute or has_attribute(start,state,attribute)) then +--~ if start.subtype<256 and start.font == font and (not attr or has_attribute(start,0,attr)) and (not attribute or has_attribute(start,state,attribute)) then + if start.subtype<256 and start.font == font and has_attribute(start,0,attr) and (not attribute or has_attribute(start,state,attribute)) then for i=1,ns do local lookupname = subtables[i] local lookupcache = thecache[lookupname] @@ -2034,9 +2081,9 @@ local chain = sequence.chain or 0 if success then done = true end ---~ if trace_steps then - registerstep(head) ---~ end + if trace_steps then -- ? + registerstep(head) + end end end return head, done |