summaryrefslogtreecommitdiff
path: root/tex/context/base/mkiv/node-rul.lua
diff options
context:
space:
mode:
authorContext Git Mirror Bot <phg42.2a@gmail.com>2016-09-23 11:04:57 +0200
committerContext Git Mirror Bot <phg42.2a@gmail.com>2016-09-23 11:04:57 +0200
commit9858ddd23d54c56b2ce9e1f5580190d3210d18ed (patch)
treea73afdfc043fae5b69367c89ec2d7f3fa56a870f /tex/context/base/mkiv/node-rul.lua
parente713d5aa882024dc438506c2f75eae6c5021a237 (diff)
downloadcontext-9858ddd23d54c56b2ce9e1f5580190d3210d18ed.tar.gz
2016-09-23 10:19:00
Diffstat (limited to 'tex/context/base/mkiv/node-rul.lua')
-rw-r--r--tex/context/base/mkiv/node-rul.lua483
1 files changed, 378 insertions, 105 deletions
diff --git a/tex/context/base/mkiv/node-rul.lua b/tex/context/base/mkiv/node-rul.lua
index 219aa5e26..3a60ca502 100644
--- a/tex/context/base/mkiv/node-rul.lua
+++ b/tex/context/base/mkiv/node-rul.lua
@@ -17,42 +17,116 @@ if not modules then modules = { } end modules ['node-rul'] = {
-- fill s withcolor .5white ;
-- draw boundingbox s withcolor yellow;
-local attributes, nodes, node = attributes, nodes, node
-
-local nuts = nodes.nuts
-local tonode = nuts.tonode
-local tonut = nuts.tonut
-
-local getfield = nuts.getfield
-local setfield = nuts.setfield
-local setnext = nuts.setnext
-local setprev = nuts.setprev
-local setlink = nuts.setlink
-local getnext = nuts.getnext
-local getprev = nuts.getprev
-local getid = nuts.getid
-local getattr = nuts.getattr
-local setattr = nuts.setattr
-local getfont = nuts.getfont
-local getsubtype = nuts.getsubtype
-local getlist = nuts.getlist
-local setlist = nuts.setlist
-local flushlist = nuts.flush_list
-
-local nodecodes = nodes.nodecodes
-local tasks = nodes.tasks
-
-local properties = nodes.properties
-local attribs = node.current_attr
-
-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
-
-function nodes.striprange(first,last) -- todo: dir
+local floor = math.floor
+
+local attributes = attributes
+local nodes = nodes
+local tasks = nodes.tasks
+local properties = nodes.properties
+
+local nuts = nodes.nuts
+local tonode = nuts.tonode
+local tonut = nuts.tonut
+
+local getfield = nuts.getfield
+local setfield = nuts.setfield
+local setnext = nuts.setnext
+local setprev = nuts.setprev
+local setlink = nuts.setlink
+local getnext = nuts.getnext
+local getprev = nuts.getprev
+local getid = nuts.getid
+local getattr = nuts.getattr
+local setattr = nuts.setattr
+local getfont = nuts.getfont
+local getsubtype = nuts.getsubtype
+local getlist = nuts.getlist
+local setlist = nuts.setlist
+
+local flushlist = nuts.flush_list
+local effective_glue = nuts.effective_glue
+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 hpack_nodes = nuts.hpack
+local attribs = nuts.current_attr
+
+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 localpar_code = nodecodes.localpar
+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 indent_code = listcodes.indent
+local line_code = listcodes.line
+
+local leftskip_code = gluecodes.leftskip
+local rightskip_code = gluecodes.rightskip
+local parfillskip_code = gluecodes.parfillskip
+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 nodepool = nuts.pool
+
+local new_rule = nodepool.rule
+local new_userrule = nodepool.userrule
+local new_kern = nodepool.kern
+
+local n_tostring = nodes.idstostring
+local n_tosequence = nodes.tosequence
+
+local variables = interfaces.variables
+local implement = interfaces.implement
+
+local privateattributes = attributes.private
+
+local a_ruled = privateattributes('ruled')
+local a_runningtext = privateattributes('runningtext')
+local a_color = privateattributes('color')
+local a_transparency = privateattributes('transparency')
+local a_colormodel = privateattributes('colormodel')
+local a_linefiller = privateattributes("linefiller")
+local a_viewerlayer = privateattributes("viewerlayer")
+
+local v_both = variables.both
+local v_left = variables.left
+local v_right = variables.right
+local v_local = variables["local"]
+local v_yes = variables.yes
+local v_all = variables.all
+local v_foreground = variables.foreground
+
+local fonthashes = fonts.hashes
+local fontdata = fonthashes.identifiers
+local fontunicodes = fonthashes.unicodes
+local fontcharacters = fonthashes.characters
+local fontresources = fonthashes.resources
+
+local dimenfactor = fonts.helpers.dimenfactor
+local splitdimen = number.splitdimen
+local setmetatableindex = table.setmetatableindex
+
+local function striprange(first,last) -- todo: dir
if first and last then -- just to be sure
if first == last then
return first, last
@@ -90,65 +164,9 @@ function nodes.striprange(first,last) -- todo: dir
return first, last
end
--- todo: order and maybe other dimensions
-
-local floor = math.floor
-
-local trace_ruled = false trackers.register("nodes.rules", function(v) trace_ruled = v end)
-local report_ruled = logs.reporter("nodes","rules")
-
-local n_tostring = nodes.idstostring
-local n_tosequence = nodes.tosequence
-
-local a_ruled = attributes.private('ruled')
-local a_runningtext = attributes.private('runningtext')
-local a_color = attributes.private('color')
-local a_transparency = attributes.private('transparency')
-local a_colormodel = attributes.private('colormodel')
-
-local insert_node_before = nuts.insert_before
-local insert_node_after = nuts.insert_after
-local list_dimensions = nuts.rangedimensions
-local hpack_nodes = nuts.hpack
-
-local striprange = nodes.striprange
-
-local fontdata = fonts.hashes.identifiers
-local variables = interfaces.variables
-local dimenfactor = fonts.helpers.dimenfactor
-local splitdimen = number.splitdimen
-
-local v_yes = variables.yes
-local v_all = variables.all
-local v_foreground = variables.foreground
-
-local nodecodes = nodes.nodecodes
-local skipcodes = nodes.skipcodes
-local kerncodes = nodes.kerncodes
-
-local glyph_code = nodecodes.glyph
-local disc_code = nodecodes.disc
-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 rule_code = nodecodes.rule
-local boundary_code = nodecodes.boundary
-local dir_code = nodecodes.dir
+nodes.striprange = striprange
-local userskip_code = skipcodes.userskip
-local spaceskip_code = skipcodes.spaceskip
-local xspaceskip_code = skipcodes.xspaceskip
-local leader_code = skipcodes.leaders
-
-local kerning_code = kerncodes.kern
-
-local nodepool = nuts.pool
-
-local new_rule = nodepool.rule
-local new_userrule = nodepool.userrule
-local new_kern = nodepool.kern
+-- todo: order and maybe other dimensions
-- we can use this one elsewhere too
--
@@ -311,8 +329,31 @@ rules.userrule = userrule
local ruleactions = { }
rules.ruleactions = ruleactions
-callback.register("process_rule",function(n,h,v)
- local n = tonut(n)
+local function mathradical(n,h,v)
+ ----- size = getfield(n,"index")
+ local font = getfield(n,"transform")
+ local actions = fontresources[font].mathruleactions
+ if actions then
+ local action = actions.radicalaction
+ if action then
+ action(n,h,v,font)
+ end
+ end
+end
+
+local function mathrule(n,h,v)
+ ----- size = getfield(n,"index")
+ local font = getfield(n,"transform")
+ local actions = fontresources[font].mathruleactions
+ if actions then
+ local action = actions.hruleaction
+ if action then
+ action(n,h,v,font)
+ end
+ end
+end
+
+local function useraction(n,h,v)
local p = properties[n]
if p then
local i = p.type or "draw"
@@ -321,17 +362,39 @@ callback.register("process_rule",function(n,h,v)
a(p,h,v,i,n)
end
end
-end)
+end
+
+local subtypeactions = {
+ [rulecodes.user] = useraction,
+ [rulecodes.over] = mathrule,
+ [rulecodes.under] = mathrule,
+ [rulecodes.fraction] = mathrule,
+ [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 trace_ruled = false trackers.register("nodes.rules", function(v) trace_ruled = v end)
+local report_ruled = logs.reporter("nodes","rules")
+
function rules.define(settings)
data[#data+1] = settings
context(#data)
end
-local a_viewerlayer = attributes.private("viewerlayer")
-
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)
@@ -426,7 +489,6 @@ local function flush_ruled(head,f,l,d,level,parent,strip) -- not that fast but a
level,w,ht,dp,n_tostring(f,l),n_tosequence(f,l,true))
end
end
-
if mp and mp ~= "" then
local r = userrule {
width = w,
@@ -462,7 +524,9 @@ end
local process = nodes.processwords
-rules.handler = function(head) return process(a_ruled,data,flush_ruled,head) end
+rules.handler = function(head)
+ return process(a_ruled,data,flush_ruled,head)
+end
function rules.enable()
tasks.enableaction("shipouts","nodes.rules.handler")
@@ -528,18 +592,200 @@ function nodes.shifts.enable()
tasks.enableaction("shipouts","nodes.shifts.handler")
end
--- linefillers (placeholder)
+-- linefillers
nodes.linefillers = nodes.linefillers or { }
nodes.linefillers.data = nodes.linefillers.data or { }
+storage.register("nodes/linefillers/data", nodes.linefillers.data, "nodes.linefillers.data")
+
+local data = nodes.linefillers.data
+
+function nodes.linefillers.define(settings)
+ data[#data+1] = settings
+ context(#data)
+end
+
+local function linefiller(current,data,width,location)
+ local height = data.height
+ local depth = data.depth
+ local mp = data.mp
+ local ma = data.ma
+ local ca = data.ca
+ local ta = data.ta
+ if mp and mp ~= "" then
+ return tonut(userrule {
+ width = width,
+ height = height,
+ depth = depth,
+ type = "mp",
+ line = data.rulethickness,
+ data = mp,
+ ma = ma,
+ ca = ca,
+ ta = ta,
+ option = location,
+ direction = getfield(current,"dir"),
+ })
+ else
+ local linefiller = new_rule(width,height,depth)
+ if ca then
+ setattr(linefiller,a_colorspace,ma)
+ setattr(linefiller,a_color,ca)
+ end
+ if ta then
+ setattr(linefiller,a_transparency,ta)
+ end
+ return linefiller
+ end
+end
+
+local function find_attr(head,attr)
+ while head do
+ local a = head[attr]
+ if a then
+ return a, head
+ end
+ head = getnext(head)
+ end
+end
+
function nodes.linefillers.handler(head)
- return head, false
+ 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
+ else
+ break
+ end
+ head = getnext(head)
+ end
+ if head then
+ local indentation = iskip and getfield(iskip,"width") or 0
+ local leftfixed = lskip and getfield(lskip,"width") 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
+ setfield(iskip,"width",0)
+ end
+ if lskip then
+ setglue(lskip,leftlocal and getfield(lskip,"width") 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
+ 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 tail then
+ local rightfixed = rskip and getfield(rskip,"width") or 0
+ local righttotal = rskip and effective_glue(rskip,current) or 0
+ local parfixed = pskip and getfield(pskip,"width") 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 getfield(rskip,"width") 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
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ return head
end
--- interface
+local enable = false
-local implement = interfaces.implement
+function nodes.linefillers.enable()
+ if not enable then
+ -- we could now nil it
+ tasks.enableaction("finalizers","nodes.linefillers.handler")
+ enable = true
+ end
+end
+
+-- interface
implement {
name = "definerule",
@@ -587,3 +833,30 @@ implement {
onlyonce = true,
actions = nodes.shifts.enable
}
+
+implement {
+ name = "definelinefiller",
+ actions = { nodes.linefillers.define, context },
+ arguments = {
+ {
+ { "method", "integer" },
+ { "location", "string" },
+ { "scope", "string" },
+ { "mp", "string" },
+ { "ma", "integer" },
+ { "ca", "integer" },
+ { "ta", "integer" },
+ { "depth", "dimension" },
+ { "height", "dimension" },
+ { "distance", "dimension" },
+ { "threshold", "dimension" },
+ { "rulethickness", "dimension" },
+ }
+ }
+}
+
+implement {
+ name = "enablelinefillers",
+ onlyonce = true,
+ actions = nodes.linefillers.enable
+}