From 0cfeab235554eeee0dddd6c3f44d3939ab490ff1 Mon Sep 17 00:00:00 2001 From: Hans Hagen Date: Tue, 17 Jan 2017 18:05:46 +0100 Subject: 2017-01-17 17:43:00 --- tex/context/base/mkiv/node-scn.lua | 311 +++++++++++++++++++++++++++++++++++++ 1 file changed, 311 insertions(+) create mode 100644 tex/context/base/mkiv/node-scn.lua (limited to 'tex/context/base/mkiv/node-scn.lua') diff --git a/tex/context/base/mkiv/node-scn.lua b/tex/context/base/mkiv/node-scn.lua new file mode 100644 index 000000000..2409750c2 --- /dev/null +++ b/tex/context/base/mkiv/node-scn.lua @@ -0,0 +1,311 @@ +if not modules then modules = { } end modules ['node-scn'] = { + version = 1.001, + comment = "companion to node-ini.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +local floor = math.floor + +local attributes = attributes +local nodes = nodes + +local nuts = nodes.nuts +local tonode = nuts.tonode +local tonut = nuts.tonut + +local getnext = nuts.getnext +local getprev = nuts.getprev +local getid = nuts.getid +local getattr = nuts.getattr +local getsubtype = nuts.getsubtype +local getlist = nuts.getlist +local setlist = nuts.setlist + +local end_of_math = nuts.end_of_math + +local nodecodes = nodes.nodecodes +local rulecodes = nodes.rulecodes +local gluecodes = nodes.gluecodes +local listcodes = nodes.listcodes +local kerncodes = nodes.kerncodes + +local glyph_code = nodecodes.glyph +local disc_code = nodecodes.disc +local rule_code = nodecodes.rule +local boundary_code = nodecodes.boundary +local dir_code = nodecodes.dir +local math_code = nodecodes.math +local glue_code = nodecodes.glue +local penalty_code = nodecodes.penalty +local kern_code = nodecodes.kern +local hlist_code = nodecodes.hlist +local vlist_code = nodecodes.vlist + +local userskip_code = gluecodes.userskip +local spaceskip_code = gluecodes.spaceskip +local xspaceskip_code = gluecodes.xspaceskip +local leader_code = gluecodes.leaders + +local kerning_code = kerncodes.kern + +local variables = interfaces.variables + +local privateattributes = attributes.private + +local a_runningtext = privateattributes('runningtext') +local a_fontkern = privateattributes('fontkern') + +local v_yes = variables.yes +local v_all = variables.all + +local function striprange(first,last) -- todo: dir + if first and last then -- just to be sure + if first == last then + return first, last + end + while first and first ~= last do + local id = getid(first) + if id == glyph_code or id == disc_code or id == dir_code or id == boundary_code then -- or id == rule_code + break + else + first = getnext(first) + end + end + if not first then + return nil, nil + elseif first == last then + return first, last + end + while last and last ~= first do + local id = getid(last) + if id == glyph_code or id == disc_code or id == dir_code or id == boundary_code then -- or id == rule_code + break + else + local prev = getprev(last) -- luatex < 0.70 has italic correction kern not prev'd + if prev then + last = prev + else + break + end + end + end + if not last then + return nil, nil + end + end + return first, last +end + +nodes.striprange = striprange + +-- todo: order and maybe other dimensions + +-- we can use this one elsewhere too +-- +-- todo: functions: word, sentence +-- +-- glyph rule unset whatsit glue margin_kern kern math disc + +-- we assume {glyphruns} and no funny extra kerning, ok, maybe we need +-- a dummy character as start and end; anyway we only collect glyphs +-- +-- this one needs to take layers into account (i.e. we need a list of +-- critical attributes) + +-- omkeren class en level -> scheelt functie call in analyze + +-- todo: switching inside math + +-- handlers + +local function processwords(attribute,data,flush,head,parent,skip) -- we have hlistdir and local dir + local n = head + if n then + local f, l, a, d, i, class + local continue, leaders, done, strip, level = false, false, false, true, -1 + while n do + local id = getid(n) + if id == glyph_code or id == rule_code or (id == hlist_code and getattr(n,a_runningtext) == 1) then + local aa = getattr(n,attribute) + if aa and aa ~= skip then + if aa == a then + if not f then -- ? + f = n + end + l = n + else + -- possible extensions: when in same class then keep spanning + local newlevel, newclass = floor(aa/1000), aa%1000 -- will be configurable + -- strip = not continue or level == 1 -- 0 + if f then + if class == newclass then -- and newlevel > level then + head, done = flush(head,f,l,d,level,parent,false), true + else + head, done = flush(head,f,l,d,level,parent,strip), true + end + end + f, l, a = n, n, aa + level, class = newlevel, newclass + d = data[class] + if d then + local c = d.continue + leaders = c == v_all + continue = leaders or c == v_yes + else + continue = true + end + end + else + if f then + head, done = flush(head,f,l,d,level,parent,strip), true + end + f, l, a = nil, nil, nil + end + if id == hlist_code then + local list = getlist(n) + if list then + setlist(n,(processwords(attribute,data,flush,list,n,aa))) -- watch () + end + end + elseif id == disc_code or id == boundary_code then + if f then + l = n + end + elseif id == kern_code and (getsubtype(n) == kerning_code or getattr(n,a_fontkern)) then + if f then + l = n + end + elseif id == math_code then + -- otherwise not consistent: a $b$ c vs a $b+c$ d etc + -- we need a special (optional) go over math variant + if f then + head, done = flush(head,f,l,d,level,parent,strip), true + f, l, a = nil, nil, nil + end + elseif id == hlist_code or id == vlist_code then + if f then + head, done = flush(head,f,l,d,level,parent,strip), true + f, l, a = nil, nil, nil + end + local list = getlist(n) + if list then + setlist(n,(processwords(attribute,data,flush,list,n,skip))) -- watch () + end + elseif id == dir_code then -- only changes in dir, we assume proper boundaries + if f then + l = n + end + elseif f then + if continue then + if id == penalty_code then + l = n + -- elseif id == kern_code then + -- l = n + elseif id == glue_code then + -- catch \underbar{a} \underbar{a} (subtype test is needed) + local subtype = getsubtype(n) + if getattr(n,attribute) and (subtype == userskip_code or subtype == spaceskip_code or subtype == xspaceskip_code or (leaders and subtype >= leader_code)) then + l = n + else + head, done = flush(head,f,l,d,level,parent,strip), true + f, l, a = nil, nil, nil + end + end + else + head, done = flush(head,f,l,d,level,parent,strip), true + f, l, a = nil, nil, nil + end + end + n = getnext(n) + end + if f then + head, done = flush(head,f,l,d,level,parent,strip), true + end + return head, true -- todo: done + else + return head, false + end +end + +nodes.processwords = function(attribute,data,flush,head,parent) -- we have hlistdir and local dir + head = tonut(head) + if parent then + parent = tonut(parent) + end + local head, done = processwords(attribute,data,flush,head,parent) + return tonode(head), done +end + +-- + +local function processranges(attribute,flush,head,parent) + local n = head + if n then + local f, l, a + local done = false + while n do + local id = getid(n) + if id == glyph_code or id == rule_code then + local aa = getattr(n,attribute) + if aa and aa ~= skip then + if aa == a then + if not f then + f = n + end + l = n + else + if f then + head, done = flush(head,f,l,a,parent), true + end + f, l, a = n, n, aa + end + else + if f then + head, done = flush(head,f,l,a,parent), true + end + f, l, a = nil, nil, nil + end + elseif id == disc_code or id == boundary_code then + if f then + l = n + else + -- weird + end + elseif id == kern_code and (getsubtype(n) == kerning_code or getattr(n,a_fontkern)) then + if f then + l = n + end + -- elseif id == penalty_code then + elseif id == glue_code then + -- todo: leaders + elseif id == hlist_code or id == vlist_code then + if f then + l = n + end + local list = getlist(n) + if list then + setlist(n,(processranges(attribute,flush,list,n,aa))) + end + end + n = getnext(n) + end + if f then + head, done = flush(head,f,l,a,parent), true + end + return head, done + else + return head, false + end +end + +nodes.processranges = function(attribute,flush,head,parent) -- we have hlistdir and local dir + head = tonut(head) + if parent then + parent = tonut(parent) + end + local head, done = processranges(attribute,flush,head,parent) + return tonode(head), done +end + -- cgit v1.2.3