diff options
author | Context Git Mirror Bot <phg42.2a@gmail.com> | 2014-12-06 15:15:04 +0100 |
---|---|---|
committer | Context Git Mirror Bot <phg42.2a@gmail.com> | 2014-12-06 15:15:04 +0100 |
commit | aae07c73a75ada5ade71c9e3125df190e3235abc (patch) | |
tree | 738aac80821d31d5b55e204ceb417a32f8b3292c | |
parent | bdd2db48f4c5e7aa2eb9037bf90ff9c26bd44df9 (diff) | |
download | context-aae07c73a75ada5ade71c9e3125df190e3235abc.tar.gz |
2014-12-06 14:22:00
27 files changed, 636 insertions, 300 deletions
diff --git a/tex/context/base/cont-new.mkiv b/tex/context/base/cont-new.mkiv index 0ff90ab76..532ace65a 100644 --- a/tex/context/base/cont-new.mkiv +++ b/tex/context/base/cont-new.mkiv @@ -11,7 +11,7 @@ %C therefore copyrighted by \PRAGMA. See mreadme.pdf for %C details. -\newcontextversion{2014.12.05 11:11} +\newcontextversion{2014.12.06 14:20} %D This file is loaded at runtime, thereby providing an excellent place for %D hacks, patches, extensions and new features. diff --git a/tex/context/base/context-version.pdf b/tex/context/base/context-version.pdf Binary files differindex d3f8bac3d..a5639e8be 100644 --- a/tex/context/base/context-version.pdf +++ b/tex/context/base/context-version.pdf diff --git a/tex/context/base/context.mkiv b/tex/context/base/context.mkiv index 74197acc5..063ea144a 100644 --- a/tex/context/base/context.mkiv +++ b/tex/context/base/context.mkiv @@ -28,7 +28,7 @@ %D up and the dependencies are more consistent. \edef\contextformat {\jobname} -\edef\contextversion{2014.12.05 11:11} +\edef\contextversion{2014.12.06 14:20} \edef\contextkind {beta} %D For those who want to use this: diff --git a/tex/context/base/font-inj.lua b/tex/context/base/font-inj.lua index deac06b40..68b3e3f23 100644 --- a/tex/context/base/font-inj.lua +++ b/tex/context/base/font-inj.lua @@ -699,28 +699,38 @@ local function inject_kerns_only(head,where,keep) while n do local id = getid(n) if id == glyph_code then - local pn = rawget(properties,n) - if pn then - if p then - local d = getfield(p,"post") - if d then - local pn = pn.postinjections - if pn then - local leftkern = pn.leftkern - if leftkern ~= 0 then - local t = find_tail(d) - insert_node_after(d,t,newkern(leftkern)) + if getsubtype(n) < 256 then + local pn = rawget(properties,n) + if pn then + if p then + local d = getfield(p,"post") + if d then + local pn = pn.postinjections + if pn then + local leftkern = pn.leftkern + if leftkern ~= 0 then + local t = find_tail(d) + insert_node_after(d,t,newkern(leftkern)) + end end end - end - local d = getfield(p,"replace") - if d then - local pn = pn.replaceinjections - if pn then - local leftkern = pn.leftkern - if leftkern ~= 0 then - local t = find_tail(d) - insert_node_after(d,t,newkern(leftkern)) + local d = getfield(p,"replace") + if d then + local pn = pn.replaceinjections + if pn then + local leftkern = pn.leftkern + if leftkern ~= 0 then + local t = find_tail(d) + insert_node_after(d,t,newkern(leftkern)) + end + end + else + local pn = pn.injections + if pn then + local leftkern = pn.leftkern + if leftkern ~= 0 then + setfield(p,"replace",newkern(leftkern)) + end end end else @@ -728,19 +738,13 @@ local function inject_kerns_only(head,where,keep) if pn then local leftkern = pn.leftkern if leftkern ~= 0 then - setfield(p,"replace",newkern(leftkern)) + head = insert_node_before(head,n,newkern(leftkern)) end end end - else - local pn = pn.injections - if pn then - local leftkern = pn.leftkern - if leftkern ~= 0 then - head = insert_node_before(head,n,newkern(leftkern)) - end - end end + else + break end p = nil elseif id == disc_code then @@ -748,14 +752,21 @@ local function inject_kerns_only(head,where,keep) if d then local h = d for n in traverse(d) do - local pn = rawget(properties,n) - if pn then - pn = pn.preinjections - end - if pn then - local leftkern = pn.leftkern - if leftkern ~= 0 then - h = insert_node_before(h,n,newkern(leftkern)) + local id = getid(n) + if id == glyph_code then + if getsubtype(n) < 256 then + local pn = rawget(properties,n) + if pn then + pn = pn.preinjections + end + if pn then + local leftkern = pn.leftkern + if leftkern ~= 0 then + h = insert_node_before(h,n,newkern(leftkern)) + end + end + else + break end end end @@ -767,14 +778,21 @@ local function inject_kerns_only(head,where,keep) if d then local h = d for n in traverse(d) do - local pn = rawget(properties,n) - if pn then - pn = pn.postinjections - end - if pn then - local leftkern = pn.leftkern - if leftkern ~= 0 then - h = insert_node_before(h,n,newkern(leftkern)) + local id = getid(n) + if id == glyph_code then + if getsubtype(n) < 256 then + local pn = rawget(properties,n) + if pn then + pn = pn.postinjections + end + if pn then + local leftkern = pn.leftkern + if leftkern ~= 0 then + h = insert_node_before(h,n,newkern(leftkern)) + end + end + else + break end end end @@ -786,15 +804,22 @@ local function inject_kerns_only(head,where,keep) if d then local h = d for n in traverse(d) do - local pn = rawget(properties,n) -- why can it be empty { } - if pn then - pn = pn.replaceinjections - end - if pn then - local leftkern = pn.leftkern - if leftkern ~= 0 then - h = insert_node_before(h,n,newkern(leftkern)) --- h = insert_node_after(h,n,newkern(leftkern)) + local id = getid(n) + if id == glyph_code then + if getsubtype(n) < 256 then + local pn = rawget(properties,n) -- why can it be empty { } + if pn then + pn = pn.replaceinjections + end + if pn then + local leftkern = pn.leftkern + if leftkern ~= 0 then + h = insert_node_before(h,n,newkern(leftkern)) + -- h = insert_node_after(h,n,newkern(leftkern)) + end + end + else + break end end end @@ -826,73 +851,77 @@ local function inject_pairs_only(head,where,keep) while n do local id = getid(n) if id == glyph_code then - local pn = rawget(properties,n) - if pn then - if p then - local d = getfield(p,"post") - if d then - local pn = pn.postinjections - if pn then - local leftkern = pn.leftkern - if leftkern ~= 0 then - local t = find_tail(d) - insert_node_after(d,t,newkern(leftkern)) + if getsubtype(n) < 256 then + local pn = rawget(properties,n) + if pn then + if p then + local d = getfield(p,"post") + if d then + local pn = pn.postinjections + if pn then + local leftkern = pn.leftkern + if leftkern ~= 0 then + local t = find_tail(d) + insert_node_after(d,t,newkern(leftkern)) + end + -- local rightkern = pn.rightkern + -- if rightkern and rightkern ~= 0 then + -- insert_node_after(head,n,newkern(rightkern)) + -- n = getnext(n) -- to be checked + -- end end - -- local rightkern = pn.rightkern - -- if rightkern and rightkern ~= 0 then - -- insert_node_after(head,n,newkern(rightkern)) - -- n = getnext(n) -- to be checked - -- end end - end - local d = getfield(p,"replace") - if d then - local pn = pn.replaceinjections - if pn then - local leftkern = pn.leftkern - if leftkern ~= 0 then - local t = find_tail(d) - insert_node_after(d,t,newkern(leftkern)) + local d = getfield(p,"replace") + if d then + local pn = pn.replaceinjections + if pn then + local leftkern = pn.leftkern + if leftkern ~= 0 then + local t = find_tail(d) + insert_node_after(d,t,newkern(leftkern)) + end + -- local rightkern = pn.rightkern + -- if rightkern and rightkern ~= 0 then + -- insert_node_after(head,n,newkern(rightkern)) + -- n = getnext(n) -- to be checked + -- end + end + else + local pn = pn.injections + if pn then + local leftkern = pn.leftkern + if leftkern ~= 0 then + setfield(p,"replace",newkern(leftkern)) + end + -- local rightkern = pn.rightkern + -- if rightkern and rightkern ~= 0 then + -- insert_node_after(head,n,newkern(rightkern)) + -- n = getnext(n) -- to be checked + -- end end - -- local rightkern = pn.rightkern - -- if rightkern and rightkern ~= 0 then - -- insert_node_after(head,n,newkern(rightkern)) - -- n = getnext(n) -- to be checked - -- end end else + -- this is the most common case local pn = pn.injections if pn then + local yoffset = pn.yoffset + if yoffset and yoffset ~= 0 then + setfield(n,"yoffset",yoffset) + end local leftkern = pn.leftkern if leftkern ~= 0 then - setfield(p,"replace",newkern(leftkern)) + insert_node_before(head,n,newkern(leftkern)) + end + local rightkern = pn.rightkern + if rightkern and rightkern ~= 0 then + insert_node_after(head,n,newkern(rightkern)) + n = getnext(n) -- to be checked end - -- local rightkern = pn.rightkern - -- if rightkern and rightkern ~= 0 then - -- insert_node_after(head,n,newkern(rightkern)) - -- n = getnext(n) -- to be checked - -- end - end - end - else - -- this is the most common case - local pn = pn.injections - if pn then - local yoffset = pn.yoffset - if yoffset and yoffset ~= 0 then - setfield(n,"yoffset",yoffset) - end - local leftkern = pn.leftkern - if leftkern ~= 0 then - insert_node_before(head,n,newkern(leftkern)) - end - local rightkern = pn.rightkern - if rightkern and rightkern ~= 0 then - insert_node_after(head,n,newkern(rightkern)) - n = getnext(n) -- to be checked end end end + else + break end p = nil elseif id == disc_code then @@ -900,23 +929,30 @@ local function inject_pairs_only(head,where,keep) if d then local h = d for n in traverse(d) do - local pn = rawget(properties,n) - if pn then - pn = pn.preinjections - end - if pn then - local yoffset = pn.yoffset - if yoffset and yoffset ~= 0 then - setfield(n,"yoffset",yoffset) - end - local leftkern = pn.leftkern - if leftkern ~= 0 then - h = insert_node_before(h,n,newkern(leftkern)) - end - local rightkern = pn.rightkern - if rightkern and rightkern ~= 0 then - insert_node_after(head,n,newkern(rightkern)) - n = getnext(n) -- to be checked + local id = getid(n) + if id == glyph_code then + if getsubtype(n) < 256 then + local pn = rawget(properties,n) + if pn then + pn = pn.preinjections + end + if pn then + local yoffset = pn.yoffset + if yoffset and yoffset ~= 0 then + setfield(n,"yoffset",yoffset) + end + local leftkern = pn.leftkern + if leftkern ~= 0 then + h = insert_node_before(h,n,newkern(leftkern)) + end + local rightkern = pn.rightkern + if rightkern and rightkern ~= 0 then + insert_node_after(head,n,newkern(rightkern)) + n = getnext(n) -- to be checked + end + end + else + break end end end @@ -928,23 +964,30 @@ local function inject_pairs_only(head,where,keep) if d then local h = d for n in traverse(d) do - local pn = rawget(properties,n) - if pn then - pn = pn.postinjections - end - if pn then - local yoffset = pn.yoffset - if yoffset and yoffset ~= 0 then - setfield(n,"yoffset",yoffset) - end - local leftkern = pn.leftkern - if leftkern ~= 0 then - h = insert_node_before(h,n,newkern(leftkern)) - end - local rightkern = pn.rightkern - if rightkern and rightkern ~= 0 then - insert_node_after(head,n,newkern(rightkern)) - n = getnext(n) -- to be checked + local id = getid(n) + if id == glyph_code then + if getsubtype(n) < 256 then + local pn = rawget(properties,n) + if pn then + pn = pn.postinjections + end + if pn then + local yoffset = pn.yoffset + if yoffset and yoffset ~= 0 then + setfield(n,"yoffset",yoffset) + end + local leftkern = pn.leftkern + if leftkern ~= 0 then + h = insert_node_before(h,n,newkern(leftkern)) + end + local rightkern = pn.rightkern + if rightkern and rightkern ~= 0 then + insert_node_after(head,n,newkern(rightkern)) + n = getnext(n) -- to be checked + end + end + else + break end end end @@ -956,23 +999,30 @@ local function inject_pairs_only(head,where,keep) if d then local h = d for n in traverse(d) do - local pn = rawget(properties,n) - if pn then - pn = pn.replaceinjections - end - if pn then - local yoffset = pn.yoffset - if yoffset and yoffset ~= 0 then - setfield(n,"yoffset",yoffset) - end - local leftkern = pn.leftkern - if leftkern ~= 0 then - h = insert_node_before(h,n,newkern(leftkern)) - end - local rightkern = pn.rightkern - if rightkern and rightkern ~= 0 then - insert_node_after(head,n,newkern(rightkern)) - n = getnext(n) -- to be checked + local id = getid(n) + if id == glyph_code then + if getsubtype(n) < 256 then + local pn = rawget(properties,n) + if pn then + pn = pn.replaceinjections + end + if pn then + local yoffset = pn.yoffset + if yoffset and yoffset ~= 0 then + setfield(n,"yoffset",yoffset) + end + local leftkern = pn.leftkern + if leftkern ~= 0 then + h = insert_node_before(h,n,newkern(leftkern)) + end + local rightkern = pn.rightkern + if rightkern and rightkern ~= 0 then + insert_node_after(head,n,newkern(rightkern)) + n = getnext(n) -- to be checked + end + end + else + break end end end diff --git a/tex/context/base/font-ota.lua b/tex/context/base/font-ota.lua index dc0469e39..9db52a3c5 100644 --- a/tex/context/base/font-ota.lua +++ b/tex/context/base/font-ota.lua @@ -219,6 +219,7 @@ registerotffeature { -- latin methods.latn = analyzers.setstate +-------.dflt = analyzers.setstate % can be an option or just the default local arab_warned = { } diff --git a/tex/context/base/font-otn.lua b/tex/context/base/font-otn.lua index f1274f79e..797c15d0a 100644 --- a/tex/context/base/font-otn.lua +++ b/tex/context/base/font-otn.lua @@ -26,7 +26,6 @@ if not modules then modules = { } end modules ['font-otn'] = { -- todo: -- --- kerning is probably not yet ok for latin around dics nodes (interesting challenge) -- extension infrastructure (for usage out of context) -- sorting features according to vendors/renderers -- alternative loop quitters @@ -38,7 +37,18 @@ if not modules then modules = { } end modules ['font-otn'] = { -- mark (to mark) code is still not what it should be (too messy but we need some more extreem husayni tests) -- remove some optimizations (when I have a faster machine) -- --- maybe redo the lot some way (more context specific) +-- beware: +-- +-- we do some disc juglling where we need to keep in mind that the +-- pre, post and replace fields can have prev pointers to a nesting +-- node ... i wonder if that is still needed +-- +-- not possible: +-- +-- \discretionary {alpha-} {betagammadelta} +-- {\discretionary {alphabeta-} {gammadelta} +-- {\discretionary {alphabetagamma-} {delta} +-- {alphabetagammadelta}}} --[[ldx-- <p>This module is a bit more split up that I'd like but since we also want to test @@ -121,7 +131,6 @@ results in different tables.</p> -- chainmore : multiple substitutions triggered by contextual lookup (e.g. fij -> f + ij) -- -- remark: the 'not implemented yet' variants will be done when we have fonts that use them --- remark: we need to check what to do with discretionaries -- We used to have independent hashes for lookups but as the tags are unique -- we now use only one hash. If needed we can have multiple again but in that @@ -162,7 +171,13 @@ local trace_kernruns = false registertracker("otf.kernruns", function(v local trace_discruns = false registertracker("otf.discruns", function(v) trace_discruns = v end) local trace_compruns = false registertracker("otf.compruns", function(v) trace_compruns = v end) -local zwnjruns = true registerdirective("otf.zwnjruns", function(v) zwnjruns = v end) +local quit_on_no_replacement = true -- maybe per font +local check_discretionaries = true -- "trace" +local zwnjruns = true + +registerdirective("otf.zwnjruns", function(v) zwnjruns = v end) +registerdirective("otf.chain.quitonnoreplacement",function(value) quit_on_no_replacement = value end) + local report_direct = logs.reporter("fonts","otf direct") local report_subchain = logs.reporter("fonts","otf subchain") @@ -202,11 +217,14 @@ local getchar = nuts.getchar local insert_node_before = nuts.insert_before local insert_node_after = nuts.insert_after local delete_node = nuts.delete +local remove_node = nuts.remove local copy_node = nuts.copy +local copy_node_list = nuts.copy_list 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 traverse_id = nuts.traverse_id local setmetatableindex = table.setmetatableindex @@ -236,7 +254,7 @@ local ligature_code = glyphcodes.ligature local privateattribute = attributes.private -- Something is messed up: we have two mark / ligature indices, one at the injection --- end and one here ... this is bases in KE's patches but there is something fishy +-- end and one here ... this is based on KE's patches but there is something fishy -- there as I'm pretty sure that for husayni we need some connection (as it's much -- more complex than an average font) but I need proper examples of all cases, not -- of only some. @@ -438,17 +456,62 @@ if not prehyphenchar then end -local function toligature(kind,lookupname,head,start,stop,char,markflag,discfound) -- brr head - - -- not here: +local function addhyphens(template,pre,post) + local l = getfield(template,"lang") + local p = prehyphenchar(l) + if p and p > 0 then + local c = copy_node(template) + setfield(c,"char",p) + if pre then + local t = find_node_tail(pre) + setfield(t,"next",c) + setfield(c,"prev",t) + else + pre = c + end + end + local p = posthyphenchar(l) + if p and p > 0 then + local c = copy_node(template) + setfield(c,"char",p) + if post then + -- post has a prev nesting node .. alternatively we could + local prev = getprev(post) + setfield(c,"next",post) + setfield(post,"prev",c) + if prev then + setfield(prev,"next",c) + setfield(c,"prev",prev) + end + else + post = c + end + end + return pre, post +end - -- 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 +local function showdiscretionary(d) -- will move to tracer + local pre = getfield(d,"pre") + local post = getfield(d,"post") + local replace = getfield(d,"replace") + if pre then + for n in traverse_nodes(pre) + do print("<",nuts.tonode(n)) + end + end + if post then + for n in traverse_nodes(post) do + print(">",nuts.tonode(n)) + end + end + if replace then + for n in traverse_nodes(replace) do + print("=",nuts.tonode(n)) + end + end +end +local function toligature(kind,lookupname,head,start,stop,char,markflag,discfound) -- brr head 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 @@ -522,41 +585,21 @@ local function toligature(kind,lookupname,head,start,stop,char,markflag,discfoun -- 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) - -- + setfield(next,"prev",nil) -- also blocks funny assignments + setfield(prev,"next",nil) -- also blocks funny assignments + local pre, post = addhyphens(comp,comp,next) -- takes from components + setfield(discfound,"pre",pre) + setfield(discfound,"post",post) 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) @@ -706,6 +749,7 @@ function handlers.gsub_ligature(head,start,kind,lookupname,ligature,sequence) else local skipmark = sequence.flags[1] local discfound = false + local lastdisc = nil while s do local id = getid(s) if id == glyph_code and getsubtype(s)<256 then -- not needed @@ -713,11 +757,15 @@ function handlers.gsub_ligature(head,start,kind,lookupname,ligature,sequence) local char = getchar(s) if skipmark and marks[char] then s = getnext(s) - else + else -- ligature is a tree local lg = ligature[char] -- can there be multiple in a row? maybe in a bad font if lg then + if not discfound and lastdisc then + discfound = lastdisc + lastdisc = nil + end + stop = s -- needed for fake so outside then ligature = lg - stop = s s = getnext(s) else break @@ -727,14 +775,13 @@ function handlers.gsub_ligature(head,start,kind,lookupname,ligature,sequence) break end elseif id == disc_code then - discfound = s - stop = s + lastdisc = s s = getnext(s) else break end end - local lig = ligature.ligature + local lig = ligature.ligature -- can't we get rid of this .ligature? if lig then if stop then if trace_ligatures then @@ -754,7 +801,7 @@ function handlers.gsub_ligature(head,start,kind,lookupname,ligature,sequence) end return head, start, true, discfound else - -- weird but happens + -- weird but happens, pseudo ligatures ... just the components end end return head, start, false, discfound @@ -1183,8 +1230,7 @@ as less as needed but that would also make the code even more messy.</p> -- end --[[ldx-- -<p>Here we replace start by a single variant, First we delete the rest of the -match.</p> +<p>Here we replace start by a single variant.</p> --ldx]]-- function chainprocs.gsub_single(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,chainindex) @@ -1214,7 +1260,45 @@ function chainprocs.gsub_single(head,start,stop,kind,chainname,currentcontext,lo logprocess("%s: replacing single %s by %s",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(currentchar),gref(replacement)) end resetinjection(current) - setfield(current,"char",replacement) + if check_discretionaries then + -- some fonts use a chain lookup to replace e.g. an f in a fi ligature + -- and there can be a isc node in between ... the next code tries to catch + -- this + local next = getnext(current) + local prev = getprev(current) -- todo: just remember it above + if getid(next) == disc_code and getsubtype(next) ~= discretionary_code then + -- maybe set a property + setfield(next,"prev",prev) + setfield(prev,"next",next) + setfield(current,"prev",nil) + setfield(current,"next",nil) + local pre = addhyphens(current,current) + local replace = copy_node(current) + setfield(replace,"char",replacement) + setfield(next,"subtype",discretionary_code) + setfield(next,"replace",replace) + setfield(next,"pre",pre) + start = next + elseif getid(prev) == disc_code and getsubtype(prev) == discretionary_code then + -- maybe check a property + setfield(next,"prev",prev) + setfield(prev,"next",next) + setfield(current,"prev",nil) + setfield(current,"next",nil) + local repl = copy_node(current) + setfield(repl,"char",replacement) + local _, post = addhyphens(current,nil,current) + local replace = getfield(prev,"replace") + local tail = find_node_tail(replace) -- we could do a check for length 1 + setfield(tail,"next",repl) + setfield(repl,"prev",tail) + setfield(prev,"post",post) + else + setfield(current,"char",replacement) + end + else + setfield(current,"char",replacement) + end end end return head, start, true @@ -1230,8 +1314,7 @@ end chainmores.gsub_single = chainprocs.gsub_single --[[ldx-- -<p>Here we replace start by a sequence of new glyphs. First we delete the rest of -the match.</p> +<p>Here we replace start by a sequence of new glyphs.</p> --ldx]]-- function chainprocs.gsub_multiple(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname) @@ -1348,16 +1431,22 @@ 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) -end + if not discfound then + discfound = s + end + if s == stop then + break -- okay? or before the disc + else + s = getnext(s) + end else local schar = getchar(s) if skipmark and marks[schar] then -- marks +-- if s == stop then -- maybe add this +-- break +-- else s = getnext(s) +-- end else local lg = ligatures[schar] if lg then @@ -1769,12 +1858,6 @@ local function show_skip(kind,chainname,char,ck,class) end end -local quit_on_no_replacement = true -- maybe per font -local quit_on_discretionary = false -- only for experiments - -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] local flags = sequence.flags @@ -1844,11 +1927,35 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq break end elseif id == disc_code then - if quit_on_discretionary then - match = false - break + if check_discretionaries then + local replace = getfield(last,"replace") + if replace then + -- so far we never entered this branch + while replace do + if seq[n][getchar(replace)] then + n = n + 1 + replace = getnext(replace) + if not replace then + break + elseif n > l then + match = false + break + end + else + match = false + break + end + end + if not match then + break + elseif check_discretionaries == "trace" then + report_chain("check disc action in current") + end + else + last = getnext(last) -- no skipping here + end else - last = getnext(last) + last = getnext(last) -- no skipping here end else match = false @@ -1895,9 +2002,36 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq break end elseif id == disc_code then - if quit_on_discretionary then - match = false - break + -- the special case: f i where i becomes dottless i .. + if check_discretionaries then + local replace = getfield(prev,"replace") + if replace then + -- we seldom enter this branch (e.g. on brill efficient) + replace = find_node_tail(replace) + local finish = getprev(replace) + while replace do + if seq[n][getchar(replace)] then + n = n - 1 + replace = getprev(replace) + if not replace or replace == finish then + break + elseif n < 1 then + match = false + break + end + else + match = false + break + end + end + if not match then + break + elseif check_discretionaries == "trace" then + report_chain("check disc action in before") + end + else + -- skip 'm + end else -- skip 'm end @@ -1961,9 +2095,33 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq break end elseif id == disc_code then - if quit_on_discretionary then - match = false - break + if check_discretionaries then + local replace = getfield(current,"replace") + if replace then + -- so far we never entered this branch + while replace do + if seq[n][getchar(replace)] then + n = n + 1 + replace = getnext(replace) + if not replace then + break + elseif n > s then + match = false + break + end + else + match = false + break + end + end + if not match then + break + elseif check_discretionaries == "trace" then + report_chain("check disc action in after") + end + else + -- skip 'm + end else -- skip 'm end @@ -2271,10 +2429,11 @@ local function kernrun(disc,run) -- we can assume that prev and next are glyphs if not pre then -- go on elseif prev then + local nest = getprev(pre) setfield(pre,"prev",prev) setfield(prev,"next",pre) run(prev,"preinjections") - setfield(pre,"prev",nil) + setfield(pre,"prev",nest) setfield(prev,"next",disc) else run(pre,"preinjections") @@ -2299,20 +2458,22 @@ local function kernrun(disc,run) -- we can assume that prev and next are glyphs -- this should be already done by discfound elseif prev and next then local tail = find_node_tail(replace) + local nest = getprev(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(replace,"prev",nest) setfield(prev,"next",disc) setfield(tail,"next",nil) setfield(next,"prev",disc) elseif prev then + local nest = getprev(replace) setfield(replace,"prev",prev) setfield(prev,"next",replace) run(prev,"replaceinjections") - setfield(replace,"prev",nil) + setfield(replace,"prev",nest) setfield(prev,"next",disc) elseif next then local tail = find_node_tail(replace) @@ -2356,6 +2517,45 @@ local function comprun(disc,run) end end +local function testrun(disc,trun,crun) + local next = getnext(disc) + if next then + local replace = getfield(disc,"replace") + if replace then + local prev = getprev(disc) + if prev then + -- only look ahead + local tail = find_node_tail(replace) + local nest = getprev(replace) + setfield(tail,"next",next) + setfield(next,"prev",tail) + if trun(replace,next) then + setfield(disc,"replace",nil) -- beware, side effects of nest so first + setfield(prev,"next",replace) + setfield(replace,"prev",prev) + setfield(next,"prev",tail) + setfield(tail,"next",next) + setfield(disc,"prev",nil) + setfield(disc,"next",nil) + flush_node_list(disc) + return replace + else + setfield(tail,"next",nil) + setfield(next,"prev",disc) + end + else + -- weird case + end + else + -- no need + end + else + -- weird case + end + comprun(disc,crun) + return next +end + local function discrun(disc,drun,krun) local next = getnext(disc) local prev = getprev(disc) @@ -2374,10 +2574,11 @@ local function discrun(disc,drun,krun) if not pre then -- go on elseif prev then + local nest = getprev(pre) setfield(pre,"prev",prev) setfield(prev,"next",pre) krun(prev,"preinjections") - setfield(pre,"prev",nil) + setfield(pre,"prev",nest) setfield(prev,"next",disc) else run(pre,"preinjections") @@ -2535,6 +2736,29 @@ local function featuresprocessor(head,font,attr) return head end + local function t_run(start,stop) + while start ~= stop do + local id = getid(start) + if id == glyph_code and getfont(start) == font and getsubtype(start) < 256 then + local a = getattr(start,0) + if a then + a = (a == attr) and (not attribute or getprop(start,a_state) == attribute) + else + a = not attribute or getprop(start,a_state) == attribute + end + if a then + local lookupmatch = lookupcache[getchar(start)] + if lookupmatch then + return true + end + end + start = getnext(start) + else + break + end + end + end + local function d_run(prev) -- we can assume that prev and next are glyphs local a = getattr(prev,0) if a then @@ -2612,7 +2836,7 @@ local function featuresprocessor(head,font,attr) end if start then start = getnext(start) end else - start = getnext(start) + start = getnext(start) end else start = getnext(start) @@ -2625,10 +2849,17 @@ local function featuresprocessor(head,font,attr) else discrun(start,d_run,k_run) end + start = getnext(start) elseif discretionary then - comprun(start,c_run) + if typ == "gsub_ligature" then + start = testrun(start,t_run,c_run) + else + comprun(start,c_run) + start = getnext(start) + end + else + start = getnext(start) end - start = getnext(start) elseif id == whatsit_code then -- will be function local subtype = getsubtype(start) if subtype == dir_code then @@ -2792,6 +3023,42 @@ local function featuresprocessor(head,font,attr) end end + local function t_run(start,stop) + while start ~= stop do + local id = getid(start) + if id == glyph_code and getfont(start) == font and getsubtype(start) < 256 then + local a = getattr(start,0) + if a then + a = (a == attr) and (not attribute or getprop(start,a_state) == attribute) + else + a = not attribute or getprop(start,a_state) == attribute + end + if a then + -- local lookupmatch = lookupcache[getchar(start)] + -- if lookupmatch then + -- return true + -- end + local char = getchar(start) + for i=1,ns do + local lookupname = subtables[i] + local lookupcache = lookuphash[lookupname] + if lookupcache then + local lookupmatch = lookupcache[char] + if lookupmatch then + return true + end + else + report_missing_cache(typ,lookupname) + end + end + end + start = getnext(start) + else + break + end + end + end + while start do local id = getid(start) if id == glyph_code then @@ -2844,10 +3111,17 @@ local function featuresprocessor(head,font,attr) else discrun(start,d_run,k_run) end + start = getnext(start) elseif discretionary then - comprun(start,c_run) + if typ == "gsub_ligature" then + start = testrun(start,t_run,c_run) + else + comprun(start,c_run) + start = getnext(start) + end + else + start = getnext(start) end - start = getnext(start) elseif id == whatsit_code then local subtype = getsubtype(start) if subtype == dir_code then @@ -2898,8 +3172,10 @@ local function featuresprocessor(head,font,attr) if trace_steps then -- ? registerstep(head) end + end + head = tonode(head) return head, done diff --git a/tex/context/base/lang-hyp.lua b/tex/context/base/lang-hyp.lua index a273009b6..58a8bffcf 100644 --- a/tex/context/base/lang-hyp.lua +++ b/tex/context/base/lang-hyp.lua @@ -776,6 +776,14 @@ if context then [0x200D] = true, -- zwj } + local function somehyphenchar(c) + if c == "" or c == "0" then + return nil + else + return type(c) == "string" and utfbyte(c) or tonumber(c) + end + end + local function definefeatures(name,featureset) local extrachars = featureset.characters -- "[]()" local hyphenchars = featureset.hyphens @@ -785,6 +793,8 @@ if context then local leftcharmin = tonumber(featureset.leftcharmin) local rightcharmin = tonumber(featureset.rightcharmin) local rightedge = featureset.rightedge + local leftchar = somehyphenchar(featureset.leftchar) + local rightchar = somehyphenchar(featureset.rightchar) -- joinerchars = joinerchars == v_yes and defaultjoiners or joinerchars hyphenchars = hyphenchars == v_yes and defaulthyphens or hyphenchars @@ -795,6 +805,8 @@ if context then featureset.rightwordmin = rightwordmin and rightwordmin > 0 and rightwordmin or nil featureset.leftcharmin = leftcharmin and leftcharmin > 0 and leftcharmin or nil featureset.rightcharmin = rightcharmin and rightcharmin > 0 and rightcharmin or nil + featureset.leftchar = leftchar + featureset.rightchar = rightchar featureset.strict = rightedge == 'tex' -- return register(name,featureset) @@ -913,10 +925,6 @@ if context then starttiming(traditional) - local function somehyphenchar(c) - return type(c) == "string" and utfbyte(c) or tonumber(c) - end - local function synchronizefeatureset(a) local f = a and featuresets[a] if f then @@ -926,8 +934,8 @@ if context then rightwordmin = f.rightwordmin leftcharmin = f.leftcharmin rightcharmin = f.rightcharmin - leftchar = somehyphenchar(f.leftchar) - rightchar = somehyphenchar(f.rightchar) + leftchar = f.leftchar + rightchar = f.rightchar strict = f.strict and strictids if rightwordmin and rightwordmin > 0 and lastwordlast ~= rightwordmin then -- so we can change mid paragraph but it's kind of unpredictable then diff --git a/tex/context/base/mult-de.mkii b/tex/context/base/mult-de.mkii index 02c0aa389..f3582e33c 100644 --- a/tex/context/base/mult-de.mkii +++ b/tex/context/base/mult-de.mkii @@ -689,7 +689,7 @@ \setinterfaceconstant{equalwidth}{equalwidth} \setinterfaceconstant{escape}{escape} \setinterfaceconstant{evenmargin}{geraderand} -\setinterfaceconstant{exitoffset}{labeloffset} +\setinterfaceconstant{exitoffset}{exitoffset} \setinterfaceconstant{expansion}{expansion} \setinterfaceconstant{export}{export} \setinterfaceconstant{extras}{extras} diff --git a/tex/context/base/mult-def.lua b/tex/context/base/mult-def.lua index afbc1001a..d1c340c1e 100644 --- a/tex/context/base/mult-def.lua +++ b/tex/context/base/mult-def.lua @@ -6544,7 +6544,7 @@ return { ["en"]="labeloffset", }, ["exitoffset"]={ - ["en"]="labeloffset", + ["en"]="exitoffset", }, ["commentoffset"]={ ["en"]="commentoffset", diff --git a/tex/context/base/mult-en.mkii b/tex/context/base/mult-en.mkii index f522519e4..b5b8f94b6 100644 --- a/tex/context/base/mult-en.mkii +++ b/tex/context/base/mult-en.mkii @@ -689,7 +689,7 @@ \setinterfaceconstant{equalwidth}{equalwidth} \setinterfaceconstant{escape}{escape} \setinterfaceconstant{evenmargin}{evenmargin} -\setinterfaceconstant{exitoffset}{labeloffset} +\setinterfaceconstant{exitoffset}{exitoffset} \setinterfaceconstant{expansion}{expansion} \setinterfaceconstant{export}{export} \setinterfaceconstant{extras}{extras} diff --git a/tex/context/base/mult-fr.mkii b/tex/context/base/mult-fr.mkii index 9c611b32c..898f81875 100644 --- a/tex/context/base/mult-fr.mkii +++ b/tex/context/base/mult-fr.mkii @@ -689,7 +689,7 @@ \setinterfaceconstant{equalwidth}{equalwidth} \setinterfaceconstant{escape}{escape} \setinterfaceconstant{evenmargin}{margepaire} -\setinterfaceconstant{exitoffset}{labeloffset} +\setinterfaceconstant{exitoffset}{exitoffset} \setinterfaceconstant{expansion}{expansion} \setinterfaceconstant{export}{export} \setinterfaceconstant{extras}{extras} diff --git a/tex/context/base/mult-it.mkii b/tex/context/base/mult-it.mkii index c5221fa5d..e31245549 100644 --- a/tex/context/base/mult-it.mkii +++ b/tex/context/base/mult-it.mkii @@ -689,7 +689,7 @@ \setinterfaceconstant{equalwidth}{equalwidth} \setinterfaceconstant{escape}{escape} \setinterfaceconstant{evenmargin}{marginepari} -\setinterfaceconstant{exitoffset}{labeloffset} +\setinterfaceconstant{exitoffset}{exitoffset} \setinterfaceconstant{expansion}{espansione} \setinterfaceconstant{export}{export} \setinterfaceconstant{extras}{extras} diff --git a/tex/context/base/mult-nl.mkii b/tex/context/base/mult-nl.mkii index 4d2322ac9..07a16f67a 100644 --- a/tex/context/base/mult-nl.mkii +++ b/tex/context/base/mult-nl.mkii @@ -689,7 +689,7 @@ \setinterfaceconstant{equalwidth}{equalwidth} \setinterfaceconstant{escape}{escape} \setinterfaceconstant{evenmargin}{evenmarge} -\setinterfaceconstant{exitoffset}{labeloffset} +\setinterfaceconstant{exitoffset}{exitoffset} \setinterfaceconstant{expansion}{expansie} \setinterfaceconstant{export}{exporteer} \setinterfaceconstant{extras}{extras} diff --git a/tex/context/base/mult-pe.mkii b/tex/context/base/mult-pe.mkii index 57fe99565..2aa8372ff 100644 --- a/tex/context/base/mult-pe.mkii +++ b/tex/context/base/mult-pe.mkii @@ -689,7 +689,7 @@ \setinterfaceconstant{equalwidth}{عرضیکسان} \setinterfaceconstant{escape}{فرار} \setinterfaceconstant{evenmargin}{حاشیهزوج} -\setinterfaceconstant{exitoffset}{labeloffset} +\setinterfaceconstant{exitoffset}{exitoffset} \setinterfaceconstant{expansion}{گسترش} \setinterfaceconstant{export}{export} \setinterfaceconstant{extras}{extras} diff --git a/tex/context/base/mult-ro.mkii b/tex/context/base/mult-ro.mkii index 284cf8b0d..77b498dc9 100644 --- a/tex/context/base/mult-ro.mkii +++ b/tex/context/base/mult-ro.mkii @@ -689,7 +689,7 @@ \setinterfaceconstant{equalwidth}{equalwidth} \setinterfaceconstant{escape}{escape} \setinterfaceconstant{evenmargin}{marginepara} -\setinterfaceconstant{exitoffset}{labeloffset} +\setinterfaceconstant{exitoffset}{exitoffset} \setinterfaceconstant{expansion}{expansiune} \setinterfaceconstant{export}{export} \setinterfaceconstant{extras}{extras} diff --git a/tex/context/base/node-fnt.lua b/tex/context/base/node-fnt.lua index f036239fc..0ab0867dc 100644 --- a/tex/context/base/node-fnt.lua +++ b/tex/context/base/node-fnt.lua @@ -146,46 +146,47 @@ function handlers.characters(head) end end for n in traverse_id(glyph_code,tonut(head)) do - -- if getsubtype(n) <256 then -- all are 1 - local font = getfont(n) - local attr = getattr(n,0) or 0 -- zero attribute is reserved for fonts in context - if font ~= prevfont or attr ~= prevattr then - if basefont then - basefont[2] = tonode(getprev(n)) -- todo, save p - end - if attr > 0 then - local used = attrfonts[font] - if not used then - used = { } - attrfonts[font] = used + if getsubtype(n) < 256 then -- all are 1 + local font = getfont(n) + local attr = getattr(n,0) or 0 -- zero attribute is reserved for fonts in context + if font ~= prevfont or attr ~= prevattr then + if basefont then + basefont[2] = tonode(getprev(n)) -- todo, save p end - if not used[attr] then - local fd = setfontdynamics[font] - if fd then - used[attr] = fd[attr] - a = a + 1 - else - b = b + 1 - basefont = { tonode(n), nil } - basefonts[b] = basefont + if attr > 0 then + local used = attrfonts[font] + if not used then + used = { } + attrfonts[font] = used end - end - else - local used = usedfonts[font] - if not used then - local fp = fontprocesses[font] - if fp then - usedfonts[font] = fp - u = u + 1 - else - b = b + 1 - basefont = { tonode(n), nil } - basefonts[b] = basefont + if not used[attr] then + local fd = setfontdynamics[font] + if fd then + used[attr] = fd[attr] + a = a + 1 + else + b = b + 1 + basefont = { tonode(n), nil } + basefonts[b] = basefont + end + end + else + local used = usedfonts[font] + if not used then + local fp = fontprocesses[font] + if fp then + usedfonts[font] = fp + u = u + 1 + else + b = b + 1 + basefont = { tonode(n), nil } + basefonts[b] = basefont + end end end + prevfont = font + prevattr = attr end - prevfont = font - prevattr = attr end -- end end diff --git a/tex/context/base/status-files.pdf b/tex/context/base/status-files.pdf Binary files differindex f7cfa76b9..efc5834d0 100644 --- a/tex/context/base/status-files.pdf +++ b/tex/context/base/status-files.pdf diff --git a/tex/context/base/status-lua.pdf b/tex/context/base/status-lua.pdf Binary files differindex b3c0ae66b..832bbf225 100644 --- a/tex/context/base/status-lua.pdf +++ b/tex/context/base/status-lua.pdf diff --git a/tex/context/interface/keys-cs.xml b/tex/context/interface/keys-cs.xml index b4beb1374..193b5b58f 100644 --- a/tex/context/interface/keys-cs.xml +++ b/tex/context/interface/keys-cs.xml @@ -695,7 +695,7 @@ <cd:constant name='equalwidth' value='equalwidth'/> <cd:constant name='escape' value='escape'/> <cd:constant name='evenmargin' value='sudamarginalie'/> - <cd:constant name='exitoffset' value='labeloffset'/> + <cd:constant name='exitoffset' value='exitoffset'/> <cd:constant name='expansion' value='expanzen'/> <cd:constant name='export' value='export'/> <cd:constant name='extras' value='extras'/> diff --git a/tex/context/interface/keys-de.xml b/tex/context/interface/keys-de.xml index 43ddfd86f..06f34e8c2 100644 --- a/tex/context/interface/keys-de.xml +++ b/tex/context/interface/keys-de.xml @@ -695,7 +695,7 @@ <cd:constant name='equalwidth' value='equalwidth'/> <cd:constant name='escape' value='escape'/> <cd:constant name='evenmargin' value='geraderand'/> - <cd:constant name='exitoffset' value='labeloffset'/> + <cd:constant name='exitoffset' value='exitoffset'/> <cd:constant name='expansion' value='expansion'/> <cd:constant name='export' value='export'/> <cd:constant name='extras' value='extras'/> diff --git a/tex/context/interface/keys-en.xml b/tex/context/interface/keys-en.xml index 9f29f1164..362bb7ad9 100644 --- a/tex/context/interface/keys-en.xml +++ b/tex/context/interface/keys-en.xml @@ -695,7 +695,7 @@ <cd:constant name='equalwidth' value='equalwidth'/> <cd:constant name='escape' value='escape'/> <cd:constant name='evenmargin' value='evenmargin'/> - <cd:constant name='exitoffset' value='labeloffset'/> + <cd:constant name='exitoffset' value='exitoffset'/> <cd:constant name='expansion' value='expansion'/> <cd:constant name='export' value='export'/> <cd:constant name='extras' value='extras'/> diff --git a/tex/context/interface/keys-fr.xml b/tex/context/interface/keys-fr.xml index 427881a07..50f1ce9db 100644 --- a/tex/context/interface/keys-fr.xml +++ b/tex/context/interface/keys-fr.xml @@ -695,7 +695,7 @@ <cd:constant name='equalwidth' value='equalwidth'/> <cd:constant name='escape' value='escape'/> <cd:constant name='evenmargin' value='margepaire'/> - <cd:constant name='exitoffset' value='labeloffset'/> + <cd:constant name='exitoffset' value='exitoffset'/> <cd:constant name='expansion' value='expansion'/> <cd:constant name='export' value='export'/> <cd:constant name='extras' value='extras'/> diff --git a/tex/context/interface/keys-it.xml b/tex/context/interface/keys-it.xml index 073aabe4d..4382cc5e6 100644 --- a/tex/context/interface/keys-it.xml +++ b/tex/context/interface/keys-it.xml @@ -695,7 +695,7 @@ <cd:constant name='equalwidth' value='equalwidth'/> <cd:constant name='escape' value='escape'/> <cd:constant name='evenmargin' value='marginepari'/> - <cd:constant name='exitoffset' value='labeloffset'/> + <cd:constant name='exitoffset' value='exitoffset'/> <cd:constant name='expansion' value='espansione'/> <cd:constant name='export' value='export'/> <cd:constant name='extras' value='extras'/> diff --git a/tex/context/interface/keys-nl.xml b/tex/context/interface/keys-nl.xml index 32c44e62b..5e8bab3ce 100644 --- a/tex/context/interface/keys-nl.xml +++ b/tex/context/interface/keys-nl.xml @@ -695,7 +695,7 @@ <cd:constant name='equalwidth' value='equalwidth'/> <cd:constant name='escape' value='escape'/> <cd:constant name='evenmargin' value='evenmarge'/> - <cd:constant name='exitoffset' value='labeloffset'/> + <cd:constant name='exitoffset' value='exitoffset'/> <cd:constant name='expansion' value='expansie'/> <cd:constant name='export' value='exporteer'/> <cd:constant name='extras' value='extras'/> diff --git a/tex/context/interface/keys-pe.xml b/tex/context/interface/keys-pe.xml index ace31d289..f784912ef 100644 --- a/tex/context/interface/keys-pe.xml +++ b/tex/context/interface/keys-pe.xml @@ -695,7 +695,7 @@ <cd:constant name='equalwidth' value='عرضیکسان'/> <cd:constant name='escape' value='فرار'/> <cd:constant name='evenmargin' value='حاشیهزوج'/> - <cd:constant name='exitoffset' value='labeloffset'/> + <cd:constant name='exitoffset' value='exitoffset'/> <cd:constant name='expansion' value='گسترش'/> <cd:constant name='export' value='export'/> <cd:constant name='extras' value='extras'/> diff --git a/tex/context/interface/keys-ro.xml b/tex/context/interface/keys-ro.xml index af4cc856e..69a0394c5 100644 --- a/tex/context/interface/keys-ro.xml +++ b/tex/context/interface/keys-ro.xml @@ -695,7 +695,7 @@ <cd:constant name='equalwidth' value='equalwidth'/> <cd:constant name='escape' value='escape'/> <cd:constant name='evenmargin' value='marginepara'/> - <cd:constant name='exitoffset' value='labeloffset'/> + <cd:constant name='exitoffset' value='exitoffset'/> <cd:constant name='expansion' value='expansiune'/> <cd:constant name='export' value='export'/> <cd:constant name='extras' value='extras'/> diff --git a/tex/generic/context/luatex/luatex-fonts-merged.lua b/tex/generic/context/luatex/luatex-fonts-merged.lua index 78c801604..e9c66382f 100644 --- a/tex/generic/context/luatex/luatex-fonts-merged.lua +++ b/tex/generic/context/luatex/luatex-fonts-merged.lua @@ -1,6 +1,6 @@ -- merged file : luatex-fonts-merged.lua -- parent file : luatex-fonts.lua --- merge date : 12/05/14 11:11:22 +-- merge date : 12/06/14 14:20:08 do -- begin closure to overcome local limits and interference |