diff options
Diffstat (limited to 'tex/context/base/node-fin.lua')
-rw-r--r-- | tex/context/base/node-fin.lua | 1047 |
1 files changed, 763 insertions, 284 deletions
diff --git a/tex/context/base/node-fin.lua b/tex/context/base/node-fin.lua index 9367badd3..2e62ebcb5 100644 --- a/tex/context/base/node-fin.lua +++ b/tex/context/base/node-fin.lua @@ -29,15 +29,15 @@ local vlist_code = nodecodes.vlist local pdfliteral_code = whatcodes.pdfliteral -local states = attributes.states -local numbers = attributes.numbers -local a_trigger = attributes.private('trigger') -local triggering = false +local states = attributes.states +local numbers = attributes.numbers +local a_trigger = attributes.private('trigger') +local triggering = false -local starttiming = statistics.starttiming -local stoptiming = statistics.stoptiming - -local unsetvalue = attributes.unsetvalue +local starttiming = statistics.starttiming +local stoptiming = statistics.stoptiming +local loadstripped = utilities.lua.loadstripped +local unsetvalue = attributes.unsetvalue -- these two will be like trackers @@ -80,97 +80,105 @@ end -- so that we moved looping to the processor itself; this may lead to a bit of -- duplicate code once that we have more state handlers -local function process_attribute(head,plugin) -- head,attribute,enabled,initializer,resolver,processor,finalizer - local namespace = plugin.namespace - if namespace.enabled ~= false then -- this test will go away - starttiming(attributes) -- in principle we could delegate this to the main caller +-- local function process_attribute(head,plugin) -- head,attribute,enabled,initializer,resolver,processor,finalizer +-- local namespace = plugin.namespace +-- if namespace.enabled ~= false then -- this test will go away +-- starttiming(attributes) -- in principle we could delegate this to the main caller +-- local done, used, ok = false, nil, false +-- local attribute = namespace.attribute or numbers[plugin.name] -- todo: plugin.attribute +-- local processor = plugin.processor +-- if processor then +-- local initializer = plugin.initializer +-- local resolver = plugin.resolver +-- local inheritance = (resolver and resolver()) or nil -- -0x7FFFFFFF -- we can best use nil and skip ! +-- if initializer then +-- initializer(namespace,attribute,head) +-- end +-- head, ok = processor(namespace,attribute,head,inheritance) +-- if ok then +-- local finalizer = plugin.finalizer +-- if finalizer then +-- head, ok, used = finalizer(namespace,attribute,head) +-- if used then +-- local flusher = plugin.flusher +-- if flusher then +-- head = flusher(namespace,attribute,head,used) +-- end +-- end +-- end +-- done = true +-- end +-- end +-- stoptiming(attributes) +-- return head, done +-- else +-- return head, false +-- end +-- end +-- +-- function nodes.installattributehandler(plugin) -- we need to avoid this nested function +-- return function(head) +-- return process_attribute(head,plugin) +-- end +-- end + +-- An experiment: lean and mean functions. It is not really faster but +-- with upcoming functionality it might make a difference, e.g. features +-- like 'casing' and 'italics' can be called a lot so there it makes sense. + +nodes.plugindata = nil + +local template = [[ +local plugin = nodes.plugindata +local starttiming = statistics.starttiming +local stoptiming = statistics.stoptiming +local namespace = plugin.namespace +local attribute = namespace.attribute or attributes.numbers[plugin.name] +local processor = plugin.processor +local initializer = plugin.initializer +local resolver = plugin.resolver +local finalizer = plugin.finalizer +local flusher = plugin.flusher +if not processor then + return function(head) + return head, false + end +elseif initializer or finalizer or resolver then + return function(head) + starttiming(attributes) local done, used, ok = false, nil, false - local attribute = namespace.attribute or numbers[plugin.name] -- todo: plugin.attribute - local processor = plugin.processor - if processor then - local initializer = plugin.initializer - local resolver = plugin.resolver - local inheritance = (resolver and resolver()) or nil -- -0x7FFFFFFF -- we can best use nil and skip ! - if initializer then - initializer(namespace,attribute,head) - end - head, ok = processor(namespace,attribute,head,inheritance) - if ok then - local finalizer = plugin.finalizer - if finalizer then - head, ok, used = finalizer(namespace,attribute,head) - if used then - local flusher = plugin.flusher - if flusher then - head = flusher(namespace,attribute,head,used) - end - end + local inheritance = (resolver and resolver()) or nil -- -0x7FFFFFFF -- we can best use nil and skip ! + if initializer then + initializer(namespace,attribute,head) + end + head, ok = processor(namespace,attribute,head,inheritance) + if ok then + if finalizer then + head, ok, used = finalizer(namespace,attribute,head) + if used and flusher then + head = flusher(namespace,attribute,head,used) end - done = true end + done = true end stoptiming(attributes) return head, done - else - return head, false end -end - --- nodes.process_attribute = process_attribute - -function nodes.installattributehandler(plugin) -- we need to avoid this nested function +else return function(head) - return process_attribute(head,plugin) + starttiming(attributes) + local head, done = processor(namespace,attribute,head) + stoptiming(attributes) + return head, done end end +nodes.plugindata = nil +]] ---~ experiment (maybe local to function makes more sense) ---~ ---~ plugindata = { } ---~ ---~ local template = [[ ---~ local plugin = plugindata["%s"] ---~ local starttiming, stoptiming = statistics.starttiming, statistics.stoptiming ---~ local namespace = plugin.namespace ---~ local attribute = namespace.attribute ---~ local processor = plugin.processor ---~ local initializer = plugin.initializer ---~ local resolver = plugin.resolver ---~ local finalizer = plugin.finalizer ---~ local flusher = plugin.flusher ---~ return function (head) ---~ if namespace.enabled then ---~ starttiming(attributes) ---~ local done, used, ok = false, nil, false ---~ if procesxsor then ---~ local inheritance = (resolver and resolver()) or nil -- -0x7FFFFFFF -- we can best use nil and skip ! ---~ if initializer then ---~ initializer(namespace,attribute,head) ---~ end ---~ head, ok = processor(namespace,attribute,head,inheritance) ---~ if ok then ---~ if finalizer then ---~ head, ok, used = finalizer(namespace,attribute,head) ---~ if used and flusher then ---~ head = flusher(namespace,attribute,head,used) ---~ end ---~ end ---~ done = true ---~ end ---~ end ---~ stoptiming(attributes) ---~ return head, done ---~ else ---~ return head, false ---~ end ---~ end ---~ ]] ---~ ---~ function nodes.installattributehandler(plugin) -- we need to avoid this nested function ---~ plugindata[plugin.name] = plugin ---~ local str = format(template,plugin.name) ---~ return loadstring(str)() ---~ end +function nodes.installattributehandler(plugin) + nodes.plugindata = plugin + return loadstripped(template)() +end -- the injectors @@ -299,85 +307,318 @@ end -- return head, done -- end -local function process(namespace,attribute,head,inheritance,default) -- one attribute - local stack, done = head, false +-- local function process(namespace,attribute,head,inheritance,default) -- one attribute +-- local stack, done = head, false - local function check() - local c = stack[attribute] - if c then - if default and c == inheritance then - if current ~= default then - head = insert_node_before(head,stack,copy_node(nsdata[default])) - current = default - done = true - end - elseif current ~= c then - head = insert_node_before(head,stack,copy_node(nsdata[c])) - current = c - done = true - end - elseif default and inheritance then - if current ~= default then - head = insert_node_before(head,stack,copy_node(nsdata[default])) - current = default - done = true - end - elseif current > 0 then - head = insert_node_before(head,stack,copy_node(nsnone)) - current = 0 - done = true - end - return c - end +-- local function check() +-- local c = stack[attribute] +-- if c then +-- if default and c == inheritance then +-- if current ~= default then +-- head = insert_node_before(head,stack,copy_node(nsdata[default])) +-- current = default +-- done = true +-- end +-- elseif current ~= c then +-- head = insert_node_before(head,stack,copy_node(nsdata[c])) +-- current = c +-- done = true +-- end +-- elseif default and inheritance then +-- if current ~= default then +-- head = insert_node_before(head,stack,copy_node(nsdata[default])) +-- current = default +-- done = true +-- end +-- elseif current > 0 then +-- head = insert_node_before(head,stack,copy_node(nsnone)) +-- current = 0 +-- done = true +-- end +-- return c +-- end - local function nested(content) - if nstrigger and stack[nstrigger] then - local outer = stack[attribute] - if outer ~= inheritance then - return process(namespace,attribute,content,inheritance,outer) - else - return process(namespace,attribute,content,inheritance,default) - end - else - return process(namespace,attribute,content,inheritance,default) - end - end +-- local function nested(content) +-- if nstrigger and stack[nstrigger] then +-- local outer = stack[attribute] +-- if outer ~= inheritance then +-- return process(namespace,attribute,content,inheritance,outer) +-- else +-- return process(namespace,attribute,content,inheritance,default) +-- end +-- else +-- return process(namespace,attribute,content,inheritance,default) +-- end +-- end + +-- while stack do +-- local id = stack.id +-- if id == glyph_code then +-- check() +-- elseif id == glue_code then +-- local content = stack.leader +-- if content and check() then +-- local savedcurrent = current +-- local ci = content.id +-- if ci == hlist_code or ci == vlist_code then +-- -- else we reset inside a box unneeded, okay, the downside is +-- -- that we trigger color in each repeated box, so there is room +-- -- for improvement here +-- current = 0 +-- end + +-- local ok = false +-- stack.leader, ok = nested(content) +-- done = done or ok + +-- current = savedcurrent +-- end +-- elseif id == hlist_code or id == vlist_code then +-- local content = stack.list +-- if content then + +-- local ok = false +-- stack.list, ok = nested(content) +-- done = done or ok + +-- end +-- elseif id == rule_code then +-- if stack.width ~= 0 then +-- check() +-- end +-- end +-- stack = stack.next +-- end +-- return head, done +-- end + +-- local function process(namespace,attribute,head,inheritance,default) -- one attribute +-- local stack, done = head, false +-- while stack do +-- local id = stack.id +-- if id == glyph_code then +-- -- begin of check +-- local c = stack[attribute] +-- if c then +-- if default and c == inheritance then +-- if current ~= default then +-- head = insert_node_before(head,stack,copy_node(nsdata[default])) +-- current = default +-- done = true +-- end +-- elseif current ~= c then +-- head = insert_node_before(head,stack,copy_node(nsdata[c])) +-- current = c +-- done = true +-- end +-- elseif default and inheritance then +-- if current ~= default then +-- head = insert_node_before(head,stack,copy_node(nsdata[default])) +-- current = default +-- done = true +-- end +-- elseif current > 0 then +-- head = insert_node_before(head,stack,copy_node(nsnone)) +-- current = 0 +-- done = true +-- end +-- -- end of check +-- elseif id == glue_code then +-- local content = stack.leader +-- if content then +-- -- begin of check +-- local c = stack[attribute] +-- if c then +-- if default and c == inheritance then +-- if current ~= default then +-- head = insert_node_before(head,stack,copy_node(nsdata[default])) +-- current = default +-- done = true +-- end +-- elseif current ~= c then +-- head = insert_node_before(head,stack,copy_node(nsdata[c])) +-- current = c +-- done = true +-- end +-- -- begin special to this check +-- local savedcurrent = current +-- local ci = content.id +-- if ci == hlist_code or ci == vlist_code then +-- -- else we reset inside a box unneeded, okay, the downside is +-- -- that we trigger color in each repeated box, so there is room +-- -- for improvement here +-- current = 0 +-- end +-- -- begin nested -- +-- local ok = false +-- if nstrigger and stack[nstrigger] then +-- local outer = stack[attribute] +-- if outer ~= inheritance then +-- stack.leader, ok = process(namespace,attribute,content,inheritance,outer) +-- else +-- stack.leader, ok = process(namespace,attribute,content,inheritance,default) +-- end +-- else +-- stack.leader, ok = process(namespace,attribute,content,inheritance,default) +-- end +-- -- end nested -- +-- done = done or ok +-- current = savedcurrent +-- -- end special to this check +-- elseif default and inheritance then +-- if current ~= default then +-- head = insert_node_before(head,stack,copy_node(nsdata[default])) +-- current = default +-- done = true +-- end +-- elseif current > 0 then +-- head = insert_node_before(head,stack,copy_node(nsnone)) +-- current = 0 +-- done = true +-- end +-- -- end of check +-- end +-- elseif id == hlist_code or id == vlist_code then +-- local content = stack.list +-- if content then +-- -- begin nested -- +-- local ok +-- if nstrigger and stack[nstrigger] then +-- local outer = stack[attribute] +-- if outer ~= inheritance then +-- stack.list, ok = process(namespace,attribute,content,inheritance,outer) +-- else +-- stack.list, ok = process(namespace,attribute,content,inheritance,default) +-- end +-- else +-- stack.list, ok = process(namespace,attribute,content,inheritance,default) +-- end +-- -- end nested -- +-- done = done or ok +-- end +-- elseif id == rule_code then +-- if stack.width ~= 0 then +-- -- begin of check +-- local c = stack[attribute] +-- if c then +-- if default and c == inheritance then +-- if current ~= default then +-- head = insert_node_before(head,stack,copy_node(nsdata[default])) +-- current = default +-- done = true +-- end +-- elseif current ~= c then +-- head = insert_node_before(head,stack,copy_node(nsdata[c])) +-- current = c +-- done = true +-- end +-- elseif default and inheritance then +-- if current ~= default then +-- head = insert_node_before(head,stack,copy_node(nsdata[default])) +-- current = default +-- done = true +-- end +-- elseif current > 0 then +-- head = insert_node_before(head,stack,copy_node(nsnone)) +-- current = 0 +-- done = true +-- end +-- -- end of check +-- end +-- end +-- stack = stack.next +-- end +-- return head, done +-- end +local function process(namespace,attribute,head,inheritance,default) -- one attribute + local stack = head + local done = false + local check = false + local leader = nil while stack do local id = stack.id if id == glyph_code then - check() + check = true elseif id == glue_code then - local content = stack.leader - if content and check() then - local savedcurrent = current - local ci = content.id - if ci == hlist_code or ci == vlist_code then - -- else we reset inside a box unneeded, okay, the downside is - -- that we trigger color in each repeated box, so there is room - -- for improvement here - current = 0 - end - - local ok = false - stack.leader, ok = nested(content) - done = done or ok - - current = savedcurrent + leader = stack.leader + if leader then + check = true end elseif id == hlist_code or id == vlist_code then local content = stack.list if content then - - local ok = false - stack.list, ok = nested(content) + -- begin nested -- + local ok + if nstrigger and stack[nstrigger] then + local outer = stack[attribute] + if outer ~= inheritance then + stack.list, ok = process(namespace,attribute,content,inheritance,outer) + else + stack.list, ok = process(namespace,attribute,content,inheritance,default) + end + else + stack.list, ok = process(namespace,attribute,content,inheritance,default) + end + -- end nested -- done = done or ok - end elseif id == rule_code then - if stack.width ~= 0 then - check() + check = stack.width ~= 0 + end + -- much faster this way than using a check() and nested() function + if check then + local c = stack[attribute] + if c then + if default and c == inheritance then + if current ~= default then + head = insert_node_before(head,stack,copy_node(nsdata[default])) + current = default + done = true + end + elseif current ~= c then + head = insert_node_before(head,stack,copy_node(nsdata[c])) + current = c + done = true + end + if leader then + local savedcurrent = current + local ci = leader.id + if ci == hlist_code or ci == vlist_code then + -- else we reset inside a box unneeded, okay, the downside is + -- that we trigger color in each repeated box, so there is room + -- for improvement here + current = 0 + end + -- begin nested -- + local ok = false + if nstrigger and stack[nstrigger] then + local outer = stack[attribute] + if outer ~= inheritance then + stack.leader, ok = process(namespace,attribute,leader,inheritance,outer) + else + stack.leader, ok = process(namespace,attribute,leader,inheritance,default) + end + else + stack.leader, ok = process(namespace,attribute,leader,inheritance,default) + end + -- end nested -- + done = done or ok + current = savedcurrent + leader = false + end + elseif default and inheritance then + if current ~= default then + head = insert_node_before(head,stack,copy_node(nsdata[default])) + current = default + done = true + end + elseif current > 0 then + head = insert_node_before(head,stack,copy_node(nsnone)) + current = 0 + done = true end + check = false end stack = stack.next end @@ -479,100 +720,184 @@ states.process = process -- return head, done -- end -local function selective(namespace,attribute,head,inheritance,default) -- two attributes - local stack, done = head, false +-- local function selective(namespace,attribute,head,inheritance,default) -- two attributes +-- local stack, done = head, false - local function check() - local c = stack[attribute] - if c then - if default and c == inheritance then - if current ~= default then - local data = nsdata[default] - head = insert_node_before(head,stack,copy_node(data[nsforced or stack[nsselector] or nsselector])) - current = default - done = true - end - else - local s = stack[nsselector] - if current ~= c or current_selector ~= s then - local data = nsdata[c] - head = insert_node_before(head,stack,copy_node(data[nsforced or stack[nsselector] or nsselector])) - current = c - current_selector = s - done = true - end - end - elseif default and inheritance then - if current ~= default then - local data = nsdata[default] - head = insert_node_before(head,stack,copy_node(data[nsforced or stack[nsselector] or nsselector])) - current = default - done = true - end - elseif current > 0 then - head = insert_node_before(head,stack,copy_node(nsnone)) - current, current_selector, done = 0, 0, true - end - return c - end +-- local function check() +-- local c = stack[attribute] +-- if c then +-- if default and c == inheritance then +-- if current ~= default then +-- local data = nsdata[default] +-- head = insert_node_before(head,stack,copy_node(data[nsforced or stack[nsselector] or nsselector])) +-- current = default +-- done = true +-- end +-- else +-- local s = stack[nsselector] +-- if current ~= c or current_selector ~= s then +-- local data = nsdata[c] +-- head = insert_node_before(head,stack,copy_node(data[nsforced or stack[nsselector] or nsselector])) +-- current = c +-- current_selector = s +-- done = true +-- end +-- end +-- elseif default and inheritance then +-- if current ~= default then +-- local data = nsdata[default] +-- head = insert_node_before(head,stack,copy_node(data[nsforced or stack[nsselector] or nsselector])) +-- current = default +-- done = true +-- end +-- elseif current > 0 then +-- head = insert_node_before(head,stack,copy_node(nsnone)) +-- current, current_selector, done = 0, 0, true +-- end +-- return c +-- end - local function nested(content) - if nstrigger and stack[nstrigger] then - local outer = stack[attribute] - if outer ~= inheritance then - return selective(namespace,attribute,content,inheritance,outer) - else - return selective(namespace,attribute,content,inheritance,default) - end - else - return selective(namespace,attribute,content,inheritance,default) - end - end +-- local function nested(content) +-- if nstrigger and stack[nstrigger] then +-- local outer = stack[attribute] +-- if outer ~= inheritance then +-- return selective(namespace,attribute,content,inheritance,outer) +-- else +-- return selective(namespace,attribute,content,inheritance,default) +-- end +-- else +-- return selective(namespace,attribute,content,inheritance,default) +-- end +-- end +-- while stack do +-- local id = stack.id +-- if id == glyph_code then +-- check() +-- elseif id == glue_code then +-- local content = stack.leader +-- if content and check() then +-- -- local savedcurrent = current +-- -- local ci = content.id +-- -- if ci == hlist_code or ci == vlist_code then +-- -- -- else we reset inside a box unneeded, okay, the downside is +-- -- -- that we trigger color in each repeated box, so there is room +-- -- -- for improvement here +-- -- current = 0 +-- -- end + +-- local ok = false +-- stack.leader, ok = nested(content) +-- done = done or ok + +-- -- current = savedcurrent +-- end +-- elseif id == hlist_code or id == vlist_code then +-- local content = stack.list +-- if content then + +-- local ok = false +-- stack.list, ok = nested(content) +-- done = done or ok + +-- end +-- elseif id == rule_code then +-- if stack.width ~= 0 then +-- check() +-- end +-- end +-- stack = stack.next +-- end +-- return head, done +-- end + +local function selective(namespace,attribute,head,inheritance,default) -- two attributes + local stack = head + local done = false + local check = false + local leader = nil while stack do local id = stack.id if id == glyph_code then - check() + check = true elseif id == glue_code then - local content = stack.leader - if content and check() then - local savedcurrent = current - local ci = content.id - if ci == hlist_code or ci == vlist_code then - -- else we reset inside a box unneeded, okay, the downside is - -- that we trigger color in each repeated box, so there is room - -- for improvement here - current = 0 - end - - local ok = false - stack.leader, ok = nested(content) - done = done or ok - - current = savedcurrent + leader = stack.leader + if leader then + check = true end elseif id == hlist_code or id == vlist_code then local content = stack.list if content then - local ok = false - stack.list, ok = nested(content) + -- begin nested + if nstrigger and stack[nstrigger] then + local outer = stack[attribute] + if outer ~= inheritance then + stack.list, ok = selective(namespace,attribute,content,inheritance,outer) + else + stack.list, ok = selective(namespace,attribute,content,inheritance,default) + end + else + stack.list, ok = selective(namespace,attribute,content,inheritance,default) + end + -- end nested done = done or ok - - -- nicer: - -- - -- local content, ok = nested(content) - -- if ok then - -- stack.leader = content - -- done = true - -- end - end elseif id == rule_code then - if stack.width ~= 0 then - check() + check = stack.width ~= 0 + end + + if check then + local c = stack[attribute] + if c then + if default and c == inheritance then + if current ~= default then + local data = nsdata[default] + head = insert_node_before(head,stack,copy_node(data[nsforced or stack[nsselector] or nsselector])) + current = default + done = true + end + else + local s = stack[nsselector] + if current ~= c or current_selector ~= s then + local data = nsdata[c] + head = insert_node_before(head,stack,copy_node(data[nsforced or stack[nsselector] or nsselector])) + current = c + current_selector = s + done = true + end + end + if leader then + local ok = false + -- begin nested + if nstrigger and stack[nstrigger] then + local outer = stack[attribute] + if outer ~= inheritance then + stack.leader, ok = selective(namespace,attribute,leader,inheritance,outer) + else + stack.leader, ok = selective(namespace,attribute,leader,inheritance,default) + end + else + stack.leader, ok = selective(namespace,attribute,leader,inheritance,default) + end + -- end nested + done = done or ok + leader = false + end + elseif default and inheritance then + if current ~= default then + local data = nsdata[default] + head = insert_node_before(head,stack,copy_node(data[nsforced or stack[nsselector] or nsselector])) + current = default + done = true + end + elseif current > 0 then + head = insert_node_before(head,stack,copy_node(nsnone)) + current, current_selector, done = 0, 0, true end + check = false end + stack = stack.next end return head, done @@ -589,38 +914,92 @@ states.selective = selective -- Todo: make a better stacker. Keep track (in attribute) about nesting level. Not -- entirely trivial and a generic solution is nicer (compares to the exporter). -local function stacked(namespace,attribute,head,default) -- no triggering, no inheritance, but list-wise - local stack, done = head, false - local current, depth = default or 0, 0 - - local function check() - local a = stack[attribute] - if a then - if current ~= a then - head = insert_node_before(head,stack,copy_node(nsdata[a])) - depth = depth + 1 - current, done = a, true - end - elseif default > 0 then - -- - elseif current > 0 then - head = insert_node_before(head,stack,copy_node(nsnone)) - depth = depth - 1 - current, done = 0, true - end - return a - end +-- local function stacked(namespace,attribute,head,default) -- no triggering, no inheritance, but list-wise +-- local stack, done = head, false +-- local current, depth = default or 0, 0 +-- +-- local function check() +-- local a = stack[attribute] +-- if a then +-- if current ~= a then +-- head = insert_node_before(head,stack,copy_node(nsdata[a])) +-- depth = depth + 1 +-- current, done = a, true +-- end +-- elseif default > 0 then +-- -- +-- elseif current > 0 then +-- head = insert_node_before(head,stack,copy_node(nsnone)) +-- depth = depth - 1 +-- current, done = 0, true +-- end +-- return a +-- end +-- +-- while stack do +-- local id = stack.id +-- if id == glyph_code then +-- check() +-- elseif id == glue_code then +-- local content = stack.leader +-- if content and check() then +-- local ok = false +-- stack.leader, ok = stacked(namespace,attribute,content,current) +-- done = done or ok +-- end +-- elseif id == hlist_code or id == vlist_code then +-- local content = stack.list +-- if content then +-- -- the problem is that broken lines gets the attribute which can be a later one +-- if nslistwise then +-- local a = stack[attribute] +-- if a and current ~= a and nslistwise[a] then -- viewerlayer / needs checking, see below +-- local p = current +-- current, done = a, true +-- head = insert_node_before(head,stack,copy_node(nsdata[a])) +-- stack.list = stacked(namespace,attribute,content,current) +-- head, stack = insert_node_after(head,stack,copy_node(nsnone)) +-- current = p +-- else +-- local ok = false +-- stack.list, ok = stacked(namespace,attribute,content,current) +-- done = done or ok +-- end +-- else +-- local ok = false +-- stack.list, ok = stacked(namespace,attribute,content,current) +-- done = done or ok +-- end +-- end +-- elseif id == rule_code then +-- if stack.width ~= 0 then +-- check() +-- end +-- end +-- stack = stack.next +-- end +-- while depth > 0 do +-- head = insert_node_after(head,stack,copy_node(nsnone)) +-- depth = depth - 1 +-- end +-- return head, done +-- end +local function stacked(namespace,attribute,head,default) -- no triggering, no inheritance, but list-wise + local stack = head + local done = false + local current = default or 0 + local depth = 0 + local check = false + local leader = false while stack do local id = stack.id if id == glyph_code then - check() + check = true elseif id == glue_code then - local content = stack.leader - if content and check() then - local ok = false - stack.leader, ok = stacked(namespace,attribute,content,current) - done = done or ok + leader = stack.leader + if leader then + check = true end elseif id == hlist_code or id == vlist_code then local content = stack.list @@ -647,10 +1026,33 @@ local function stacked(namespace,attribute,head,default) -- no triggering, no in end end elseif id == rule_code then - if stack.width ~= 0 then - check() + check = stack.width ~= 0 + end + + if check then + local a = stack[attribute] + if a then + if current ~= a then + head = insert_node_before(head,stack,copy_node(nsdata[a])) + depth = depth + 1 + current, done = a, true + end + if leader then + local ok = false + stack.leader, ok = stacked(namespace,attribute,content,current) + done = done or ok + leader = false + end + elseif default > 0 then + -- + elseif current > 0 then + head = insert_node_before(head,stack,copy_node(nsnone)) + depth = depth - 1 + current, done = 0, true end + check = false end + stack = stack.next end while depth > 0 do @@ -664,35 +1066,93 @@ states.stacked = stacked -- experimental +-- local function stacker(namespace,attribute,head,default) -- no triggering, no inheritance, but list-wise +-- nsbegin() +-- local current, previous, done, okay = head, head, false, false +-- local attrib = default or unsetvalue +-- +-- local function check() +-- local a = current[attribute] or unsetvalue +-- if a ~= attrib then +-- local n = nsstep(a) +-- if n then +-- -- !!!! TEST CODE !!!! +-- -- head = insert_node_before(head,current,copy_node(nsdata[tonumber(n)])) -- a +-- head = insert_node_before(head,current,n) -- a +-- end +-- attrib, done, okay = a, true, true +-- end +-- return a +-- end +-- +-- while current do +-- local id = current.id +-- if id == glyph_code then +-- check() +-- elseif id == glue_code then +-- local content = current.leader +-- if content and check() then +-- -- tricky as a leader has to be a list so we cannot inject before +-- local _, ok = stacker(namespace,attribute,content,attrib) +-- done = done or ok +-- end +-- elseif id == hlist_code or id == vlist_code then +-- local content = current.list +-- if not content then +-- -- skip +-- elseif nslistwise then +-- local a = current[attribute] +-- if a and attrib ~= a and nslistwise[a] then -- viewerlayer +-- done = true +-- head = insert_node_before(head,current,copy_node(nsdata[a])) +-- current.list = stacker(namespace,attribute,content,a) +-- head, current = insert_node_after(head,current,copy_node(nsnone)) +-- else +-- local ok = false +-- current.list, ok = stacker(namespace,attribute,content,attrib) +-- done = done or ok +-- end +-- else +-- local ok = false +-- current.list, ok = stacker(namespace,attribute,content,default) +-- done = done or ok +-- end +-- elseif id == rule_code then +-- if current.width ~= 0 then +-- check() +-- end +-- end +-- previous = current +-- current = current.next +-- end +-- if okay then +-- local n = nsend() +-- if n then +-- -- !!!! TEST CODE !!!! +-- -- head = insert_node_after(head,previous,copy_node(nsdata[tostring(n)])) +-- head = insert_node_after(head,previous,n) +-- end +-- end +-- return head, done +-- end + local function stacker(namespace,attribute,head,default) -- no triggering, no inheritance, but list-wise nsbegin() - local current, previous, done, okay = head, head, false, false - local attrib = default or unsetvalue - - local function check() - local a = current[attribute] or unsetvalue - if a ~= attrib then - local n = nsstep(a) - if n then - -- !!!! TEST CODE !!!! --- head = insert_node_before(head,current,copy_node(nsdata[tonumber(n)])) -- a - head = insert_node_before(head,current,n) -- a - end - attrib, done, okay = a, true, true - end - return a - end - + local current = head + local previous = head + local done = false + local okay = false + local attrib = default or unsetvalue + local check = false + local leader = false while current do local id = current.id if id == glyph_code then - check() + check = true elseif id == glue_code then - local content = current.leader - if content and check() then - -- tricky as a leader has to be a list so we cannot inject before - local _, ok = stacker(namespace,attribute,content,attrib) - done = done or ok + leader = current.leader + if leader then + check = true end elseif id == hlist_code or id == vlist_code then local content = current.list @@ -716,10 +1176,29 @@ local function stacker(namespace,attribute,head,default) -- no triggering, no in done = done or ok end elseif id == rule_code then - if current.width ~= 0 then - check() + check = current.width ~= 0 + end + + if check then + local a = current[attribute] or unsetvalue + if a ~= attrib then + local n = nsstep(a) + if n then + -- !!!! TEST CODE !!!! + -- head = insert_node_before(head,current,copy_node(nsdata[tonumber(n)])) -- a + head = insert_node_before(head,current,n) -- a + end + attrib, done, okay = a, true, true + if leader then + -- tricky as a leader has to be a list so we cannot inject before + local _, ok = stacker(namespace,attribute,leader,attrib) + done = done or ok + leader = false + end end + check = false end + previous = current current = current.next end @@ -727,7 +1206,7 @@ local function stacker(namespace,attribute,head,default) -- no triggering, no in local n = nsend() if n then -- !!!! TEST CODE !!!! --- head = insert_node_after(head,previous,copy_node(nsdata[tostring(n)])) + -- head = insert_node_after(head,previous,copy_node(nsdata[tostring(n)])) head = insert_node_after(head,previous,n) end end |