diff options
author | Context Git Mirror Bot <phg42.2a@gmail.com> | 2014-12-03 19:15:05 +0100 |
---|---|---|
committer | Context Git Mirror Bot <phg42.2a@gmail.com> | 2014-12-03 19:15:05 +0100 |
commit | 606f30879286f37c0cf0ef42bc225e835d0d596d (patch) | |
tree | 969577a4f86a2d1e9c085bda80812ebb45c074cb /tex/context/base/font-otn.lua | |
parent | 8fa06810ed0fdc14d3c45eefff9a41800a84150b (diff) | |
download | context-606f30879286f37c0cf0ef42bc225e835d0d596d.tar.gz |
2014-12-03 18:28:00
Diffstat (limited to 'tex/context/base/font-otn.lua')
-rw-r--r-- | tex/context/base/font-otn.lua | 568 |
1 files changed, 417 insertions, 151 deletions
diff --git a/tex/context/base/font-otn.lua b/tex/context/base/font-otn.lua index 32dc820d3..e23a1366c 100644 --- a/tex/context/base/font-otn.lua +++ b/tex/context/base/font-otn.lua @@ -129,16 +129,14 @@ results in different tables.</p> -- Todo: make plugin feature that operates on char/glyphnode arrays -local concat, insert, remove = table.concat, table.insert, table.remove -local gmatch, gsub, find, match, lower, strip = string.gmatch, string.gsub, string.find, string.match, string.lower, string.strip -local type, next, tonumber, tostring = type, next, tonumber, tostring -local lpegmatch = lpeg.match +local type, next, tonumber = type, next, tonumber local random = math.random local formatters = string.formatters local logs, trackers, nodes, attributes = logs, trackers, nodes, attributes -local registertracker = trackers.register +local registertracker = trackers.register +local registerdirective = directives.register local fonts = fonts local otf = fonts.handlers.otf @@ -160,6 +158,11 @@ local trace_steps = false registertracker("otf.steps", function(v local trace_skips = false registertracker("otf.skips", function(v) trace_skips = v end) local trace_directions = false registertracker("otf.directions", function(v) trace_directions = v end) +local kernruns = true registerdirective("otf.kernruns", function(v) kernruns = v end) +local discruns = true registerdirective("otf.discruns", function(v) discruns = v end) +local compruns = true registerdirective("otf.compruns", function(v) compruns = v end) +local zwnjruns = true registerdirective("otf.zwnjruns", function(v) zwnjruns = v end) + local report_direct = logs.reporter("fonts","otf direct") local report_subchain = logs.reporter("fonts","otf subchain") local report_chain = logs.reporter("fonts","otf chain") @@ -194,12 +197,14 @@ local getfont = nuts.getfont local getsubtype = nuts.getsubtype local getchar = nuts.getchar +local insert_node_before = nuts.insert_before local insert_node_after = nuts.insert_after local delete_node = nuts.delete local copy_node = nuts.copy local find_node_tail = nuts.tail local flush_node_list = nuts.flush_list local end_of_math = nuts.end_of_math +local traverse_nodes = nuts.traverse local setmetatableindex = table.setmetatableindex @@ -416,9 +421,36 @@ local function getcomponentindex(start) end end --- eventually we will do positioning in an other way (needs addional w/h/d fields) +local a_noligature = attributes.private("noligature") +local prehyphenchar = languages and languages.prehyphenchar +local posthyphenchar = languages and languages.posthyphenchar + +if not prehyphenchar then + + local newlang = lang.new + local getpre = lang.prehyphenchar + local getpost = lang.posthyphenchar + + prehyphenchar = function(l) local l = newlang(l) return l and getpre (l) or -1 end + posthyphenchar = function(l) local l = newlang(l) return l and getpost(l) or -1 end + +end local function toligature(kind,lookupname,head,start,stop,char,markflag,discfound) -- brr head + + -- not here: + + -- for n in nuts.traverse(glyph_code,start) do + -- if getid(n) == glyph_code and getchar(n) == zwnj then + -- return head, start + -- end + -- if n == stop then break end + -- end + + if getattr(start,a_noligature) == 1 then + -- so we can do: e\noligature{ff}e e\noligature{f}fie (we only look at the first) + return head, start + end if start == stop and getchar(start) == char then resetinjection(start) setfield(start,"char",char) @@ -426,6 +458,7 @@ local function toligature(kind,lookupname,head,start,stop,char,markflag,discfoun end local prev = getprev(start) local next = getnext(stop) + local comp = start setfield(start,"prev",nil) setfield(stop,"next",nil) local base = copy_glyph(start) @@ -435,7 +468,7 @@ local function toligature(kind,lookupname,head,start,stop,char,markflag,discfoun resetinjection(base) setfield(base,"char",char) setfield(base,"subtype",ligature_code) - setfield(base,"components",start) -- start can have components + setfield(base,"components",comp) -- start can have components .. do we need to flush? if prev then setfield(prev,"next",base) end @@ -483,6 +516,56 @@ local function toligature(kind,lookupname,head,start,stop,char,markflag,discfoun end start = getnext(start) end + elseif not kernruns or not discruns or not compruns then + -- disabled + elseif getsubtype(discfound) == discretionary_code then + -- maybe some day + else + -- forget about marks .. probably no scripts that hyphenate and have marks + -- todo: check for special disc nodes (with pre's and so) + -- todo: use insert_before + local prev = getfield(discfound,"prev") + local next = getfield(discfound,"next") + if prev and next then + setfield(next,"prev",nil) + setfield(prev,"next",nil) + local l = getfield(comp,"lang") + local p = prehyphenchar(l) + if p and p > 0 then + local c = copy_node(comp) + local t = find_node_tail(comp) + setfield(c,"char",p) + comp = insert_node_after(comp,t,c) + end + local p = posthyphenchar(l) + if p and p > 0 then + local c = copy_node(next) + setfield(c,"char",p) + next = insert_node_before(next,next,c) + end + setfield(discfound,"pre",comp) + setfield(discfound,"post",next) + -- + local prev = getfield(base,"prev") + local next = getfield(base,"next") + -- + -- remove_node(prev,prev) + -- insert_node_after(prev,prev,discfound) + -- + setfield(prev,"next",discfound) + setfield(next,"prev",discfound) + setfield(discfound,"next",next) + setfield(discfound,"prev",prev) + -- + setfield(base,"next",nil) + setfield(base,"prev",nil) + setfield(base,"components",nil) + setfield(discfound,"replace",base) + setfield(discfound,"subtype",discretionary_code) + base = next + else + -- weird disc .. maybe some day + end end return head, base end @@ -587,7 +670,7 @@ function handlers.gsub_multiple(head,start,kind,lookupname,multiple,sequence) end function handlers.gsub_ligature(head,start,kind,lookupname,ligature,sequence) - local s, stop, discfound = getnext(start), nil, false + local s, stop = getnext(start), nil local startchar = getchar(start) if marks[startchar] then while s do @@ -615,25 +698,26 @@ function handlers.gsub_ligature(head,start,kind,lookupname,ligature,sequence) else head, start = markstoligature(kind,lookupname,head,start,stop,lig) end - return head, start, true + return head, start, true, false else -- ok, goto next lookup end end else - local skipmark = sequence.flags[1] + local skipmark = sequence.flags[1] + local discfound = false while s do local id = getid(s) - if id == glyph_code and getsubtype(s)<256 then - if getfont(s) == currentfont then + if id == glyph_code and getsubtype(s)<256 then -- not needed + if getfont(s) == currentfont then -- also not needed only when mark local char = getchar(s) if skipmark and marks[char] then s = getnext(s) else - local lg = ligature[char] + local lg = ligature[char] -- can there be multiple in a row? maybe in a bad font if lg then - stop = s ligature = lg + stop = s s = getnext(s) else break @@ -643,7 +727,8 @@ function handlers.gsub_ligature(head,start,kind,lookupname,ligature,sequence) break end elseif id == disc_code then - discfound = true + discfound = s + stop = s s = getnext(s) else break @@ -667,12 +752,12 @@ function handlers.gsub_ligature(head,start,kind,lookupname,ligature,sequence) logprocess("%s: replacing %s by (no real) ligature %s case 3",pref(kind,lookupname),gref(startchar),gref(lig)) end end - return head, start, true + return head, start, true, discfound else -- weird but happens end end - return head, start, false + return head, start, false, discfound end --[[ldx-- @@ -920,16 +1005,16 @@ function handlers.gpos_cursive(head,start,kind,lookupname,exitanchors,sequence) end end -function handlers.gpos_single(head,start,kind,lookupname,kerns,sequence) +function handlers.gpos_single(head,start,kind,lookupname,kerns,sequence,injection) local startchar = getchar(start) - local dx, dy, w, h = setpair(start,tfmdata.parameters.factor,rlmode,sequence.flags[4],kerns,characters[startchar]) + local dx, dy, w, h = setpair(start,tfmdata.parameters.factor,rlmode,sequence.flags[4],kerns,injection) -- ,characters[startchar]) if trace_kerns then logprocess("%s: shifting single %s by (%p,%p) and correction (%p,%p)",pref(kind,lookupname),gref(startchar),dx,dy,w,h) end return head, start, false end -function handlers.gpos_pair(head,start,kind,lookupname,kerns,sequence) +function handlers.gpos_pair(head,start,kind,lookupname,kerns,sequence,lookuphash,i,injection) -- todo: kerns in disc nodes: pre, post, replace -> loop over disc too -- todo: kerns in components of ligatures local snext = getnext(start) @@ -953,14 +1038,14 @@ function handlers.gpos_pair(head,start,kind,lookupname,kerns,sequence) local a, b = krn[2], krn[3] if a and #a > 0 then local startchar = getchar(start) - local x, y, w, h = setpair(start,factor,rlmode,sequence.flags[4],a,characters[startchar]) + local x, y, w, h = setpair(start,factor,rlmode,sequence.flags[4],a,injection) -- characters[startchar]) if trace_kerns then logprocess("%s: shifting first of pair %s and %s by (%p,%p) and correction (%p,%p)",pref(kind,lookupname),gref(startchar),gref(nextchar),x,y,w,h) end end if b and #b > 0 then local startchar = getchar(start) - local x, y, w, h = setpair(snext,factor,rlmode,sequence.flags[4],b,characters[nextchar]) + local x, y, w, h = setpair(snext,factor,rlmode,sequence.flags[4],b,injection) -- characters[nextchar]) if trace_kerns then logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p)",pref(kind,lookupname),gref(startchar),gref(nextchar),x,y,w,h) end @@ -980,7 +1065,7 @@ function handlers.gpos_pair(head,start,kind,lookupname,kerns,sequence) end done = true elseif krn ~= 0 then - local k = setkern(snext,factor,rlmode,krn) + local k = setkern(snext,factor,rlmode,krn,injection) if trace_kerns then logprocess("%s: inserting kern %s between %s and %s",pref(kind,lookupname),k,gref(getchar(prev)),gref(nextchar)) end @@ -1107,7 +1192,7 @@ function chainprocs.gsub_single(head,start,stop,kind,chainname,currentcontext,lo local current = start local subtables = currentlookup.subtables if #subtables > 1 then - logwarning("todo: check if we need to loop over the replacements: %s",concat(subtables," ")) + logwarning("todo: check if we need to loop over the replacements: % t",subtables) end while current do if getid(current) == glyph_code then @@ -1263,8 +1348,12 @@ function chainprocs.gsub_ligature(head,start,stop,kind,chainname,currentcontext, while s do local id = getid(s) if id == disc_code then + discfound = s +if s == stop then + break -- okay? +else s = getnext(s) - discfound = true +end else local schar = getchar(s) if skipmark and marks[schar] then -- marks @@ -1297,7 +1386,7 @@ function chainprocs.gsub_ligature(head,start,stop,kind,chainname,currentcontext, end end head, start = toligature(kind,lookupname,head,start,stop,l2,currentlookup.flags[1],discfound) - return head, start, true, nofreplacements + return head, start, true, nofreplacements, discfound elseif trace_bugs then if start == stop then logwarning("%s: replacing character %s by ligature fails",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar)) @@ -1307,7 +1396,7 @@ function chainprocs.gsub_ligature(head,start,stop,kind,chainname,currentcontext, end end end - return head, start, false, 0 + return head, start, false, 0, false end chainmores.gsub_ligature = chainprocs.gsub_ligature @@ -1579,7 +1668,7 @@ function chainprocs.gpos_single(head,start,stop,kind,chainname,currentcontext,lo if kerns then kerns = kerns[startchar] -- needed ? if kerns then - local dx, dy, w, h = setpair(start,tfmdata.parameters.factor,rlmode,sequence.flags[4],kerns,characters[startchar]) + local dx, dy, w, h = setpair(start,tfmdata.parameters.factor,rlmode,sequence.flags[4],kerns) -- ,characters[startchar]) if trace_kerns then logprocess("%s: shifting single %s by (%p,%p) and correction (%p,%p)",cref(kind,chainname,chainlookupname),gref(startchar),dx,dy,w,h) end @@ -1619,14 +1708,14 @@ function chainprocs.gpos_pair(head,start,stop,kind,chainname,currentcontext,look local a, b = krn[2], krn[3] if a and #a > 0 then local startchar = getchar(start) - local x, y, w, h = setpair(start,factor,rlmode,sequence.flags[4],a,characters[startchar]) + local x, y, w, h = setpair(start,factor,rlmode,sequence.flags[4],a) -- ,characters[startchar]) if trace_kerns then logprocess("%s: shifting first of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(kind,chainname,chainlookupname),gref(startchar),gref(nextchar),x,y,w,h) end end if b and #b > 0 then local startchar = getchar(start) - local x, y, w, h = setpair(snext,factor,rlmode,sequence.flags[4],b,characters[nextchar]) + local x, y, w, h = setpair(snext,factor,rlmode,sequence.flags[4],b) -- ,characters[nextchar]) if trace_kerns then logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(kind,chainname,chainlookupname),gref(startchar),gref(nextchar),x,y,w,h) end @@ -1680,11 +1769,11 @@ local function show_skip(kind,chainname,char,ck,class) end end -local quit_on_no_replacement = true +local quit_on_no_replacement = true -- maybe per font +local quit_on_discretionary = false -- only for experiments -directives.register("otf.chain.quitonnoreplacement",function(value) -- maybe per font - quit_on_no_replacement = value -end) +registerdirective("otf.chain.quitonnoreplacement",function(value) quit_on_no_replacement = value end) +registerdirective("otf.chain.quitondiscretionary",function(value) quit_on_discretionary = value end) local function normal_handle_contextchain(head,start,kind,chainname,contexts,sequence,lookuphash) -- local rule, lookuptype, sequence, f, l, lookups = ck[1], ck[2] ,ck[3], ck[4], ck[5], ck[6] @@ -1755,7 +1844,12 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq break end elseif id == disc_code then - last = getnext(last) + if quit_on_discretionary then + match = false + break + else + last = getnext(last) + end else match = false break @@ -1801,7 +1895,12 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq break end elseif id == disc_code then - -- skip 'm + if quit_on_discretionary then + match = false + break + else + -- skip 'm + end elseif seq[n][32] then n = n -1 else @@ -1810,7 +1909,7 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq end prev = getprev(prev) elseif seq[n][32] then -- somewhat special, as zapfino can have many preceding spaces - n = n -1 + n = n - 1 else match = false break @@ -1862,7 +1961,12 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq break end elseif id == disc_code then - -- skip 'm + if quit_on_discretionary then + match = false + break + else + -- skip 'm + end elseif seq[n][32] then -- brrr n = n + 1 else @@ -2149,6 +2253,124 @@ end -- -- the action -- end +-- assumptions: +-- +-- * languages that use complex disc nodes + +-- optimization comes later ... + +local function kernrun(disc,run) -- we can assume that prev and next are glyphs + if kernruns then + -- + local prev = getprev(disc) -- todo, keep these in the main loop + local next = getnext(disc) -- todo, keep these in the main loop + -- + local pre = getfield(disc,"pre") + if not pre then + -- go on + elseif prev then + setfield(pre,"prev",prev) + setfield(prev,"next",pre) + run(prev,"preinjections") + setfield(pre,"prev",nil) + setfield(prev,"next",disc) + else + run(pre,"preinjections") + end + -- + local post = getfield(disc,"post") + if not post then + -- go on + elseif next then + local tail = find_node_tail(post) + setfield(tail,"next",next) + setfield(next,"prev",tail) + run(post,"postinjections",tail) + setfield(tail,"next",nil) + setfield(next,"prev",disc) + else + run(post,"postinjections") + end + -- + local replace = getfield(disc,"replace") + if not replace then + -- this should be already done by discfound + elseif prev and next then + local tail = find_node_tail(replace) + setfield(replace,"prev",prev) + setfield(prev,"next",replace) + setfield(tail,"next",next) + setfield(next,"prev",tail) + run(prev,"replaceinjections",tail) + setfield(replace,"prev",nil) + setfield(prev,"next",disc) + setfield(tail,"next",nil) + setfield(next,"prev",disc) + elseif prev then + setfield(replace,"prev",prev) + setfield(prev,"next",replace) + run(prev,"replaceinjections") + setfield(replace,"prev",nil) + setfield(prev,"next",disc) + elseif next then + local tail = find_node_tail(replace) + setfield(tail,"next",next) + setfield(next,"prev",tail) + run(replace,"replaceinjections",tail) + setfield(tail,"next",nil) + setfield(next,"prev",disc) + else + run(replace,"replaceinjections") + end + -- + end +end + +local function comprun(disc,run) + if compruns then + -- + local pre = getfield(disc,"pre") + if pre then + local new = run(pre) + if new ~= pre then + setfield(disc,"pre",new) + end + end + -- + local post = getfield(disc,"post") + if post then + local new = run(post) + if new ~= post then + setfield(disc,"post",new) + end + end + -- + local replace = getfield(disc,"replace") + if replace then + local new = run(replace) + if new ~= replace then + setfield(disc,"replace",new) + end + end + -- + end +end + +local function discrun(disc,run) + local next = getnext(disc) + if discruns and next then + local prev = getprev(disc) + if prev then + setfield(prev,"next",next) + -- setfield(next,"prev",prev) + run(disc) + setfield(prev,"next",disc) + -- setfield(next,"prev",disc) + end + end + return next +end + local function featuresprocessor(head,font,attr) local lookuphash = lookuphashes[font] -- we can also check sequences here @@ -2193,21 +2415,25 @@ local function featuresprocessor(head,font,attr) -- todo: retain prev + -- We don't goto the next node of a disc node is created so that we can then treat + -- the pre, post and replace. It's abit of a hack but works out ok for most cases. + for s=1,#datasets do - local dataset = datasets[s] - featurevalue = dataset[1] -- todo: pass to function instead of using a global - - local sequence = dataset[5] -- sequences[s] -- also dataset[5] - local rlparmode = 0 - local topstack = 0 - local success = false - local attribute = dataset[2] - local chain = dataset[3] -- sequence.chain or 0 - local typ = sequence.type - local subtables = sequence.subtables + local dataset = datasets[s] + featurevalue = dataset[1] -- todo: pass to function instead of using a global + local attribute = dataset[2] + local chain = dataset[3] -- sequence.chain or 0 + local kind = dataset[4] + local sequence = dataset[5] -- sequences[s] -- also dataset[5] + local rlparmode = 0 + local topstack = 0 + local success = false + local typ = sequence.type + local gpossing = typ == "gpos_single" or typ == "gpos_pair" + local subtables = sequence.subtables + local handler = handlers[typ] if chain < 0 then -- this is a limited case, no special treatments like 'init' etc - local handler = handlers[typ] -- we need to get rid of this slide! probably no longer needed in latest luatex local start = find_node_tail(head) -- slow (we can store tail because there's always a skip at the end): todo while start do @@ -2227,7 +2453,8 @@ local function featuresprocessor(head,font,attr) if lookupcache then local lookupmatch = lookupcache[getchar(start)] if lookupmatch then - head, start, success = handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i) + -- todo: disc? + head, start, success = handler(head,start,kind,lookupname,lookupmatch,sequence,lookuphash,i) if success then break end @@ -2248,7 +2475,6 @@ local function featuresprocessor(head,font,attr) end end else - local handler = handlers[typ] local ns = #subtables local start = head -- local ? rlmode = 0 -- to be checked ? @@ -2259,8 +2485,7 @@ local function featuresprocessor(head,font,attr) report_missing_cache(typ,lookupname) else - local function subrun(start) - -- mostly for gsub, gpos would demand a more clever approach + local function c_run(start) local head = start local done = false while start do @@ -2277,7 +2502,7 @@ local function featuresprocessor(head,font,attr) if lookupmatch then -- sequence kan weg local ok - head, start, ok = handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,1) + head, start, ok = handler(head,start,kind,lookupname,lookupmatch,sequence,lookuphash,1) if ok then done = true end @@ -2292,43 +2517,64 @@ local function featuresprocessor(head,font,attr) end if done then success = true - return head end + return head end - local function kerndisc(disc) -- we can assume that prev and next are glyphs - local prev = getprev(disc) - local next = getnext(disc) - if prev and next then - setfield(prev,"next",next) - -- setfield(next,"prev",prev) - local a = getattr(prev,0) - if a then - a = (a == attr) and (not attribute or getprop(prev,a_state) == attribute) - else - a = not attribute or getprop(prev,a_state) == attribute + local function d_run(prev) -- we can assume that prev and next are glyphs + local a = getattr(prev,0) + if a then + a = (a == attr) and (not attribute or getprop(prev,a_state) == attribute) + else + a = not attribute or getprop(prev,a_state) == attribute + end + if a then + local lookupmatch = lookupcache[getchar(prev)] + if lookupmatch then + -- sequence kan weg + local h, d, ok = handler(head,prev,kind,lookupname,lookupmatch,sequence,lookuphash,1) + if ok then + done = true + success = true + end end - if a then - local lookupmatch = lookupcache[getchar(prev)] - if lookupmatch then - -- sequence kan weg - local h, d, ok = handler(head,prev,dataset[4],lookupname,lookupmatch,sequence,lookuphash,1) - if ok then - done = true - success = true + end + end + + local function k_run(sub,injection,last) + local a = getattr(sub,0) + if a then + a = (a == attr) and (not attribute or getprop(sub,a_state) == attribute) + else + a = not attribute or getprop(sub,a_state) == attribute + end + if a then + -- sequence kan weg + for n in traverse_nodes(sub) do -- only gpos + local id = getid(n) + if id == glyph_code then + local lookupmatch = lookupcache[getchar(n)] + if lookupmatch then + local h, d, ok = handler(sub,n,kind,lookupname,lookupmatch,sequence,lookuphash,1,injection) + if ok then + done = true + success = true + end end + else + -- message + end + if n == last then + break end end - setfield(prev,"next",disc) - -- setfield(next,"prev",disc) end - return next end while start do local id = getid(start) if id == glyph_code then - if getfont(start) == font and getsubtype(start) < 256 then + if getfont(start) == font and getsubtype(start) < 256 then -- why a 256 test ... local a = getattr(start,0) if a then a = (a == attr) and (not attribute or getprop(start,a_state) == attribute) @@ -2336,14 +2582,19 @@ local function featuresprocessor(head,font,attr) a = not attribute or getprop(start,a_state) == attribute end if a then - local lookupmatch = lookupcache[getchar(start)] + local char = getchar(start) + local lookupmatch = lookupcache[char] if lookupmatch then -- sequence kan weg local ok - head, start, ok = handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,1) + head, start, ok = handler(head,start,kind,lookupname,lookupmatch,sequence,lookuphash,1) if ok then success = true + elseif gpossing and zwnjruns and char == zwnj then + discrun(start,d_run) end + elseif gpossing and zwnjruns and char == zwnj then + discrun(start,d_run) end if start then start = getnext(start) end else @@ -2353,25 +2604,15 @@ local function featuresprocessor(head,font,attr) start = getnext(start) end elseif id == disc_code then - -- mostly for gsub - if getsubtype(start) == discretionary_code then - local pre = getfield(start,"pre") - if pre then - local new = subrun(pre) - if new then setfield(start,"pre",new) end - end - local post = getfield(start,"post") - if post then - local new = subrun(post) - if new then setfield(start,"post",new) end - end - local replace = getfield(start,"replace") - if replace then - local new = subrun(replace) - if new then setfield(start,"replace",new) end + local discretionary = getsubtype(start) == discretionary_code + if gpossing then + if discretionary then + kernrun(start,k_run) + else + discrun(start,d_run) end -elseif typ == "gpos_single" or typ == "gpos_pair" then - kerndisc(start) + elseif discretionary then + comprun(start,c_run) end start = getnext(start) elseif id == whatsit_code then -- will be function @@ -2418,10 +2659,10 @@ elseif typ == "gpos_single" or typ == "gpos_pair" then end end end + else - local function subrun(start) - -- mostly for gsub, gpos would demand a more clever approach + local function c_run(start) local head = start local done = false while start do @@ -2442,7 +2683,7 @@ elseif typ == "gpos_single" or typ == "gpos_pair" then if lookupmatch then -- we could move all code inline but that makes things even more unreadable local ok - head, start, ok = handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i) + head, start, ok = handler(head,start,kind,lookupname,lookupmatch,sequence,lookuphash,i) if ok then done = true break @@ -2465,45 +2706,75 @@ elseif typ == "gpos_single" or typ == "gpos_pair" then end if done then success = true - return head end + return head end - local function kerndisc(disc) -- we can assume that prev and next are glyphs - local prev = getprev(disc) - local next = getnext(disc) - if prev and next then - setfield(prev,"next",next) - -- setfield(next,"prev",prev) - local a = getattr(prev,0) - if a then - a = (a == attr) and (not attribute or getprop(prev,a_state) == attribute) - else - a = not attribute or getprop(prev,a_state) == attribute + local function d_run(prev) + local a = getattr(prev,0) + if a then + a = (a == attr) and (not attribute or getprop(prev,a_state) == attribute) + else + a = not attribute or getprop(prev,a_state) == attribute + end + if a then + local char = getchar(prev) + for i=1,ns do + local lookupname = subtables[i] + local lookupcache = lookuphash[lookupname] + if lookupcache then + local lookupmatch = lookupcache[char] + if lookupmatch then + -- we could move all code inline but that makes things even more unreadable + local h, d, ok = handler(head,prev,kind,lookupname,lookupmatch,sequence,lookuphash,i) + if ok then + done = true + break + end + end + else + report_missing_cache(typ,lookupname) + end end - if a then - for i=1,ns do - local lookupname = subtables[i] - local lookupcache = lookuphash[lookupname] - if lookupcache then - local lookupmatch = lookupcache[getchar(prev)] - if lookupmatch then - -- we could move all code inline but that makes things even more unreadable - local h, d, ok = handler(head,prev,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i) - if ok then - done = true - break + end + end + + local function k_run(sub,injection,last) + local a = getattr(sub,0) + if a then + a = (a == attr) and (not attribute or getprop(sub,a_state) == attribute) + else + a = not attribute or getprop(sub,a_state) == attribute + end + if a then + for n in traverse_nodes(sub) do -- only gpos + local id = getid(n) + if id == glyph_code then + local char = getchar(n) + for i=1,ns do + local lookupname = subtables[i] + local lookupcache = lookuphash[lookupname] + if lookupcache then + local lookupmatch = lookupcache[char] + if lookupmatch then + local h, d, ok = handler(head,n,kind,lookupname,lookupmatch,sequence,lookuphash,i,injection) + if ok then + done = true + break + end end + else + report_missing_cache(typ,lookupname) end - else - report_missing_cache(typ,lookupname) end + else + -- message + end + if n == last then + break end end - setfield(prev,"next",disc) - -- setfield(next,"prev",disc) end - return next end while start do @@ -2521,18 +2792,23 @@ elseif typ == "gpos_single" or typ == "gpos_pair" then local lookupname = subtables[i] local lookupcache = lookuphash[lookupname] if lookupcache then - local lookupmatch = lookupcache[getchar(start)] + local char = getchar(start) + local lookupmatch = lookupcache[char] if lookupmatch then -- we could move all code inline but that makes things even more unreadable local ok - head, start, ok = handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i) + head, start, ok = handler(head,start,kind,lookupname,lookupmatch,sequence,lookuphash,i) if ok then success = true break elseif not start then -- don't ask why ... shouldn't happen break + elseif gpossing and zwnjruns and char == zwnj then + discrun(start,d_run) end + elseif gpossing and zwnjruns and char == zwnj then + discrun(start,d_run) end else report_missing_cache(typ,lookupname) @@ -2546,25 +2822,15 @@ elseif typ == "gpos_single" or typ == "gpos_pair" then start = getnext(start) end elseif id == disc_code then - -- mostly for gsub - if getsubtype(start) == discretionary_code then - local pre = getfield(start,"pre") - if pre then - local new = subrun(pre) - if new then setfield(start,"pre",new) end - end - local post = getfield(start,"post") - if post then - local new = subrun(post) - if new then setfield(start,"post",new) end - end - local replace = getfield(start,"replace") - if replace then - local new = subrun(replace) - if new then setfield(start,"replace",new) end + local discretionary = getsubtype(start) == discretionary_code + if gpossing then + if discretionary then + kernrun(start,k_run) + else + discrun(start,d_run) end -elseif typ == "gpos_single" or typ == "gpos_pair" then - kerndisc(start) + elseif discretionary then + comprun(start,c_run) end start = getnext(start) elseif id == whatsit_code then |