diff options
Diffstat (limited to 'tex/context/base/mkiv/node-rul.lua')
-rw-r--r-- | tex/context/base/mkiv/node-rul.lua | 374 |
1 files changed, 221 insertions, 153 deletions
diff --git a/tex/context/base/mkiv/node-rul.lua b/tex/context/base/mkiv/node-rul.lua index 2b0368c2b..ea0e5c7a0 100644 --- a/tex/context/base/mkiv/node-rul.lua +++ b/tex/context/base/mkiv/node-rul.lua @@ -37,18 +37,20 @@ local setlink = nuts.setlink local getnext = nuts.getnext local getprev = nuts.getprev local getid = nuts.getid -local getdir = nuts.getdir +local getdirection = nuts.getdirection local getattr = nuts.getattr local setattr = nuts.setattr local getfont = nuts.getfont local getsubtype = nuts.getsubtype local getlist = nuts.getlist local setwhd = nuts.setwhd -local setdir = nuts.setdir local setattrlist = nuts.setattrlist local setshift = nuts.setshift local getwidth = nuts.getwidth local setwidth = nuts.setwidth +local setfield = nuts.setfield + +local isglyph = nuts.isglyph local flushlist = nuts.flush_list local effective_glue = nuts.effective_glue @@ -56,17 +58,16 @@ local insert_node_after = nuts.insert_after local insert_node_before = nuts.insert_before local find_tail = nuts.tail local setglue = nuts.setglue -local traverse_id = nuts.traverse_id -local list_dimensions = nuts.rangedimensions +local getrangedimensions = nuts.rangedimensions local hpack_nodes = nuts.hpack -local current_attr = nuts.current_attr local copy_list = nuts.copy_list +local nexthlist = nuts.traversers.hlist + 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 localpar_code = nodecodes.localpar @@ -74,8 +75,8 @@ local dir_code = nodecodes.dir local glue_code = nodecodes.glue local hlist_code = nodecodes.hlist -local indent_code = listcodes.indent -local line_code = listcodes.line +local indentlist_code = listcodes.indent +local linelist_code = listcodes.line local leftskip_code = gluecodes.leftskip local rightskip_code = gluecodes.rightskip @@ -121,8 +122,8 @@ local setmetatableindex = table.setmetatableindex -- -local striprange = nodes.striprange -local processwords = nodes.processwords +local striprange = nuts.striprange +local processwords = nuts.processwords -- @@ -144,7 +145,7 @@ local function usernutrule(t,noattributes) if noattributes == false or noattributes == nil then -- avoid fuzzy ones else - setattrlist(r,current_attr()) + setattrlist(r,true) end properties[r] = t return r @@ -156,9 +157,11 @@ local function userrule(t,noattributes) return tonode(usernutrule(t,noattributes)) end -rules.userrule = userrule -local ruleactions = { } -rules.ruleactions = ruleactions +rules.userrule = userrule +local ruleactions = { } + +rules .ruleactions = ruleactions +nutrules.ruleactions = ruleactions -- convenient local function mathradical(n,h,v) ----- size = getfield(n,"index") @@ -203,18 +206,18 @@ local subtypeactions = { [rulecodes.radical] = mathradical, } -callbacks.register( - "process_rule", - function(n,h,v) - local n = tonut(n) - local s = getsubtype(n) - local a = subtypeactions[s] - if a then - a(n,h,v) - end - end, - "handle additional user rule features" -) +local function process_rule(n,h,v) + local n = tonut(n) + local s = getsubtype(n) + local a = subtypeactions[s] + if a then + a(n,h,v) + end +end + +callbacks.register("process_rule",process_rule,"handle additional user rule features") + +callbacks.functions.process_rule = process_rule -- @@ -239,9 +242,9 @@ end local function flush_ruled(head,f,l,d,level,parent,strip) -- not that fast but acceptable for this purpose local font = nil - local id = getid(f) - if id == glyph_code then - font = getfont(f) + local char, id = isglyph(f) + if char then + font = id elseif id == hlist_code then font = getattr(f,a_runningtext) end @@ -263,7 +266,7 @@ local function flush_ruled(head,f,l,d,level,parent,strip) -- not that fast but a if not f then return head end - local w, ht, dp = list_dimensions(parent,f,getnext(l)) + local w, ht, dp = getrangedimensions(parent,f,getnext(l)) local method = d.method local empty = d.empty == v_yes local offset = d.offset @@ -331,7 +334,7 @@ local function flush_ruled(head,f,l,d,level,parent,strip) -- not that fast but a end end if mp and mp ~= "" then - local r = userrule { + local r = usernutrule { width = w, height = ht, depth = dp, @@ -344,16 +347,17 @@ local function flush_ruled(head,f,l,d,level,parent,strip) -- not that fast but a ca = color, ta = transparency, } - inject(tonut(r),w,ht,dp) + inject(r,w,ht,dp) else local tx = d.text if tx then - tx = copy_list(tx) + local l = copy_list(tx) if d["repeat"] == v_yes then - tx = new_leader(w,tx) + l = new_leader(w,l) + setattrlist(l,tx) end - local r = hpack_nodes(tx,w,"exactly") - inject(r,w,ht,dp) + l = hpack_nodes(l,w,"exactly") + inject(l,w,ht,dp) else for i=1,level do local ht = (offset+(i-1)*dy)*e + rulethickness - m @@ -373,10 +377,8 @@ local function flush_ruled(head,f,l,d,level,parent,strip) -- not that fast but a return head end -local process = nodes.processwords - rules.handler = function(head) - return process(a_ruled,data,flush_ruled,head) + return processwords(a_ruled,data,flush_ruled,head) end function rules.enable() @@ -409,7 +411,7 @@ local function flush_shifted(head,first,last,data,level,parent,strip) -- not tha local next = getnext(last) setprev(first) setnext(last) - local width, height, depth = list_dimensions(parent,first,next) + local width, height, depth = getrangedimensions(parent,first,next) local list = hpack_nodes(first,width,"exactly") -- we can use a simple pack if first == head then head = list @@ -429,9 +431,9 @@ local function flush_shifted(head,first,last,data,level,parent,strip) -- not tha return head end -local process = nodes.processwords - -nodes.shifts.handler = function(head) return process(a_shifted,data,flush_shifted,head) end +nodes.shifts.handler = function(head) + return processwords(a_shifted,data,flush_shifted,head) +end function nodes.shifts.enable() enableaction("shipouts","nodes.shifts.handler") @@ -459,7 +461,7 @@ local function linefiller(current,data,width,location) local ca = data.ca local ta = data.ta if mp and mp ~= "" then - return tonut(userrule { + return usernutrule { width = width, height = height, depth = depth, @@ -470,18 +472,56 @@ local function linefiller(current,data,width,location) ca = ca, ta = ta, option = location, - direction = getdir(current), - }) + direction = getdirection(current), + } else - local linefiller = new_rule(width,height,depth) + local rule = new_rule(width,height,depth) if ca then - setattr(linefiller,a_colorspace,ma) - setattr(linefiller,a_color,ca) + setattr(rule,a_colorspace,ma) + setattr(rule,a_color,ca) end if ta then - setattr(linefiller,a_transparency,ta) + setattr(rule,a_transparency,ta) + end + return rule + end +end + +function nodes.linefillers.filler(current,data,width,height,depth) + if width and width > 0 then + local height = height or data.height or 0 + local depth = depth or data.depth or 0 + if (height + depth) ~= 0 then + local mp = data.mp + local ma = data.ma + local ca = data.ca + local ta = data.ta + if mp and mp ~= "" then + return usernutrule { + width = width, + height = height, + depth = depth, + type = "mp", + line = data.rulethickness, + data = mp, + ma = ma, + ca = ca, + ta = ta, + option = location, + direction = getdirection(current), + } + else + local rule = new_rule(width,height,depth) + if ca then + setattr(rule,a_colorspace,ma) + setattr(rule,a_color,ca) + end + if ta then + setattr(rule,a_transparency,ta) + end + return rule + end end - return linefiller end end @@ -496,119 +536,115 @@ local function find_attr(head,attr) end function nodes.linefillers.handler(head) --- local current = tonut(head) -- when we hook into the contributers - for current in traverse_id(hlist_code,tonut(head)) do - if getsubtype(current) == line_code then - local list = getlist(current) - if list then - -- why doesn't leftskip take the attributes - -- or list[linefiller] or maybe first match (maybe we need a fast helper for that) - local a = getattr(current,a_linefiller) - if a then - local class = a % 1000 - local data = data[class] - if data then - local location = data.location - local scope = data.scope - local distance = data.distance - local threshold = data.threshold - local leftlocal = false - local rightlocal = false - -- - if scope == v_right then - leftlocal = true - elseif scope == v_left then - rightlocal = true - elseif scope == v_local then - leftlocal = true - rightlocal = true - end - -- - if location == v_left or location == v_both then - local lskip = nil -- leftskip - local iskip = nil -- indentation - local head = list - while head do - local id = getid(head) - if id == glue_code then - if getsubtype(head) == leftskip_code then - lskip = head - else - break - end - elseif id == localpar_code or id == dir_code then - -- go on - elseif id == hlist_code then - if getsubtype(head) == indent_code then - iskip = head - end - break + for current, subtype, list in nexthlist, head do + if list and subtype == linelist_code then + -- why doesn't leftskip take the attributes + -- or list[linefiller] or maybe first match (maybe we need a fast helper for that) + local a = getattr(current,a_linefiller) + if a then + local class = a % 1000 + local data = data[class] + if data then + local location = data.location + local scope = data.scope + local distance = data.distance + local threshold = data.threshold + local leftlocal = false + local rightlocal = false + -- + if scope == v_right then + leftlocal = true + elseif scope == v_left then + rightlocal = true + elseif scope == v_local then + leftlocal = true + rightlocal = true + end + -- + if location == v_left or location == v_both then + local lskip = nil -- leftskip + local iskip = nil -- indentation + local head = list + while head do + local id = getid(head) + if id == glue_code then + if getsubtype(head) == leftskip_code then + lskip = head else break end - head = getnext(head) + elseif id == localpar_code or id == dir_code then + -- go on + elseif id == hlist_code then + if getsubtype(head) == indentlist_code then + iskip = head + end + break + else + break end - if head then - local indentation = iskip and getwidth(iskip) or 0 - local leftfixed = lskip and getwidth(lskip) or 0 - local lefttotal = lskip and effective_glue(lskip,current) or 0 - local width = lefttotal - (leftlocal and leftfixed or 0) + indentation - distance - if width > threshold then - if iskip then - setwidth(iskip,0) + head = getnext(head) + end + if head then + local indentation = iskip and getwidth(iskip) or 0 + local leftfixed = lskip and getwidth(lskip) or 0 + local lefttotal = lskip and effective_glue(lskip,current) or 0 + local width = lefttotal - (leftlocal and leftfixed or 0) + indentation - distance + if width > threshold then + if iskip then + setwidth(iskip,0) + end + if lskip then + setglue(lskip,leftlocal and getwidth(lskip) or nil) + if distance > 0 then + insert_node_after(list,lskip,new_kern(distance)) end - if lskip then - setglue(lskip,leftlocal and getwidth(lskip) or nil) - if distance > 0 then - insert_node_after(list,lskip,new_kern(distance)) - end - insert_node_after(list,lskip,linefiller(current,data,width,"left")) - else - insert_node_before(list,head,linefiller(current,data,width,"left")) - if distance > 0 then - insert_node_before(list,head,new_kern(distance)) - end + insert_node_after(list,lskip,linefiller(current,data,width,"left")) + else + insert_node_before(list,head,linefiller(current,data,width,"left")) + if distance > 0 then + insert_node_before(list,head,new_kern(distance)) end end end end - -- - if location == v_right or location == v_both then - local pskip = nil -- parfillskip - local rskip = nil -- rightskip - local tail = find_tail(list) - while tail and getid(tail) == glue_code do - local subtype = getsubtype(tail) - if subtype == rightskip_code then - rskip = tail - elseif subtype == parfillskip_code then - pskip = tail - else - break - end - tail = getprev(tail) + end + -- + if location == v_right or location == v_both then + local pskip = nil -- parfillskip + local rskip = nil -- rightskip + local tail = find_tail(list) + while tail and getid(tail) == glue_code do + local subtype = getsubtype(tail) + if subtype == rightskip_code then + rskip = tail + elseif subtype == parfillskip_code then + pskip = tail + else + break end - if tail then - local rightfixed = rskip and getwidth(rskip) or 0 - local righttotal = rskip and effective_glue(rskip,current) or 0 - local parfixed = pskip and getwidth(pskip) or 0 - local partotal = pskip and effective_glue(pskip,current) or 0 - local width = righttotal - (rightlocal and rightfixed or 0) + partotal - distance - if width > threshold then - if pskip then - setglue(pskip) + tail = getprev(tail) + end + if tail then + local rightfixed = rskip and getwidth(rskip) or 0 + local righttotal = rskip and effective_glue(rskip,current) or 0 + local parfixed = pskip and getwidth(pskip) or 0 + local partotal = pskip and effective_glue(pskip,current) or 0 + local width = righttotal - (rightlocal and rightfixed or 0) + partotal - distance + if width > threshold then + if pskip then + setglue(pskip) + end + if rskip then + setglue(rskip,rightlocal and getwidth(rskip) or nil) + if distance > 0 then + insert_node_before(list,rskip,new_kern(distance)) end - if rskip then - setglue(rskip,rightlocal and getwidth(rskip) or nil) - if distance > 0 then - insert_node_before(list,rskip,new_kern(distance)) - end - insert_node_before(list,rskip,linefiller(current,data,width,"right")) - else - insert_node_after(list,tail,linefiller(current,data,width,"right")) - if distance > 0 then - insert_node_after(list,tail,new_kern(distance)) - end + insert_node_before(list,rskip,linefiller(current,data,width,"right")) + else + insert_node_after(list,tail,linefiller(current,data,width,"right")) + if distance > 0 then + insert_node_after(list,tail,new_kern(distance)) end end end @@ -708,3 +744,35 @@ implement { onlyonce = true, actions = nodes.linefillers.enable } + +-- We add a bonus feature here: + +interfaces.implement { + name = "autorule", + arguments = { + { + { "width", "dimension" }, + { "height", "dimension" }, + { "depth", "dimension" }, + { "left", "dimension" }, + { "right", "dimension" }, + }, + }, + actions = function(t) + local l = t.left + local r = t.right + local n = new_rule( + t.width, + t.height, + t.depth + ) + setattrlist(n,true) + if l then + setfield(n,"left",l) + end + if r then + setfield(n,"right",r) + end + context(tonode(n)) + end +} |