summaryrefslogtreecommitdiff
path: root/tex/context/base/node-rul.lua
diff options
context:
space:
mode:
Diffstat (limited to 'tex/context/base/node-rul.lua')
-rw-r--r--tex/context/base/node-rul.lua288
1 files changed, 288 insertions, 0 deletions
diff --git a/tex/context/base/node-rul.lua b/tex/context/base/node-rul.lua
new file mode 100644
index 000000000..9dd89bcda
--- /dev/null
+++ b/tex/context/base/node-rul.lua
@@ -0,0 +1,288 @@
+if not modules then modules = { } end modules ['node-rul'] = {
+ version = 1.001,
+ comment = "companion to node-rul.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- this will go to an auxiliary module
+-- beware: rules now have a dir field
+
+local glyph = node.id("glyph")
+local disc = node.id("disc")
+local rule = node.id("rule")
+
+function nodes.strip_range(first,last) -- todo: dir
+ if first and last then -- just to be sure
+ local current = first
+ while current and current ~= last do
+ local id = current.id
+ if id == glyph or id == disc then
+ --~ if id == glyph or id == rule or id == disc then
+ first = current
+ break
+ else
+ current = current.next
+ end
+ end
+ local current = last
+ while current and current ~= first do
+ local id = current.id
+ --~ if id == glyph or id == rule or id == disc then
+ if id == glyph or id == disc then
+ last = current
+ break
+ else
+ current = current.prev
+ end
+ end
+ end
+ return first, last
+end
+
+-- todo: order and maybe other dimensions
+
+local trace_ruled = false trackers.register("nodes.ruled", function(v) trace_ruled = v end)
+
+local floor = math.floor
+local n_tostring, n_tosequence = nodes.ids_tostring, nodes.tosequence
+
+local a_ruled = attributes.private('ruled')
+local a_color = attributes.private('color')
+local a_transparency = attributes.private('transparency')
+local a_colorspace = attributes.private('colormodel')
+
+local glyph = node.id("glyph")
+local disc = node.id("disc")
+local glue = node.id("glue")
+local penalty = node.id("penalty")
+local kern = node.id("kern")
+local hlist = node.id("hlist")
+local vlist = node.id("vlist")
+local rule = node.id("rule")
+local whatsit = node.id("whatsit")
+
+local new_rule = nodes.rule
+local new_kern = nodes.kern
+local new_glue = nodes.glue
+
+local insert_before, insert_after, strip_range = node.insert_before, node.insert_after, nodes.strip_range
+local list_dimensions, has_attribute, set_attribute = node.dimensions, node.has_attribute, node.set_attribute
+local hpack_nodes = node.hpack
+local dimenfactor = fonts.dimenfactor
+local texwrite = tex.write
+
+local fontdata = fonts.ids
+local variables = interfaces.variables
+
+-- we can use this one elsewhere too
+--
+-- todo: functions: word, sentence
+--
+-- glyph rule unset whatsit glue margin_kern kern math disc
+
+local checkdir = true
+
+-- we assume {glyphruns} and no funny extra kerning, ok, maybe we need
+-- a dummy character as start and end; anyway we only collect glyphs
+
+local function process_words(attribute,data,flush,head,parent) -- we have hlistdir and local dir
+ local n = head
+ if n then
+ local f, l, a, d, i, level
+ local continue, done, strip = false, false, false
+ while n do
+ local id = n.id
+ if id == glyph or id == rule then
+ local aa = has_attribute(n,attribute)
+ if aa then
+ if aa == a then
+ if not f then -- ?
+ f = n
+ end
+ l = n
+ else
+ -- possible extensions: when in same class then keep spanning
+ if f then
+ head, done = flush(head,f,l,d,level,parent,strip), true
+ end
+ f, l, a = n, n, aa
+ level, i = floor(a/1000), a%1000
+ d = data[i]
+ continue = d.continue == variables.yes
+ end
+ else
+ if f then
+ head, done = flush(head,f,l,d,level,parent,strip), true
+ end
+ f, l, a = nil, nil, nil
+ end
+ elseif f and (id == disc or (id == kern and n.subtype == 0)) then
+ l = n
+ elseif id == hlist or id == vlist then
+ if f then
+ head, done = flush(head,f,l,d,level,parent,strip), true
+ f, l, a = nil, nil, nil
+ end
+ local list = n.list
+ if list then
+ n.list = process_words(attribute,data,flush,list,n)
+ end
+ elseif checkdir and id == whatsit and n.subtype == 7 then -- only changes in dir, we assume proper boundaries
+ if f and a then
+ l = n
+ end
+ elseif f then
+ if continue then
+ if id == penalty or id == kern then
+ l = n
+ elseif id == glue then
+ l = n
+ end
+ else
+ head, done = flush(head,f,l,d,level,parent,strip), true
+ f, l, a = nil, nil, nil
+ end
+ end
+ n = n.next
+ 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.process_words = process_words
+
+--
+
+nodes.rules = nodes.rules or { }
+nodes.rules.data = nodes.rules.data or { }
+
+storage.register("nodes/rules/data", nodes.rules.data, "nodes.rules.data")
+
+local data = nodes.rules.data
+
+function nodes.rules.define(settings)
+ data[#data+1] = settings
+ texwrite(#data)
+end
+
+local function flush_ruled(head,f,l,d,level,parent,strip) -- not that fast but acceptable for this purpose
+-- check for f and l
+ local r, m
+ if true then
+ f, l = strip_range(f,l)
+ end
+ local w = list_dimensions(parent.glue_set,parent.glue_sign,parent.glue_order,f,l.next)
+ local method, offset, continue, dy, rulethickness, unit, order, max, ma, ca, ta =
+ d.method, d.offset, d.continue, d.dy, d.rulethickness, d.unit, d.order, d.max, d.ma, d.ca, d.ta
+ local e = dimenfactor(unit,fontdata[f.font])
+ local colorspace = (ma > 0 and ma) or has_attribute(f,a_colorspace) or 1
+ local color = (ca > 0 and ca) or has_attribute(f,a_color)
+ local transparency = (ta > 0 and ta) or has_attribute(f,a_transparency)
+ local foreground = order == variables.foreground
+ rulethickness= rulethickness/2
+ if level > max then
+ level = max
+ end
+ if method == 0 then -- center
+ offset = 2*offset
+ m = (offset+(level-1)*dy+rulethickness)*e/2
+ else
+ m = 0
+ end
+ for i=1,level do
+ local ht = (offset+(i-1)*dy+rulethickness)*e - m
+ local dp = -(offset+(i-1)*dy-rulethickness)*e + m
+ local r = new_rule(w,ht,dp)
+ if color then
+ set_attribute(r,a_colorspace,colorspace)
+ set_attribute(r,a_color,color)
+ end
+ if transparency then
+ set_attribute(r,a_transparency,transparency)
+ end
+ local k = new_kern(-w)
+ if foreground then
+ insert_after(head,l,k)
+ insert_after(head,k,r)
+ l = r
+ else
+ head, _ = insert_before(head,f,r)
+ insert_after(head,r,k)
+ end
+ if trace_ruled then
+ logs.report("ruled", "level: %s, width: %i, height: %i, depth: %i, nodes: %s, text: %s",
+ level,w,ht,dp,n_tostring(f,l),n_tosequence(f,l,true))
+ -- level,r.width,r.height,r.depth,n_tostring(f,l),n_tosequence(f,l,true))
+ end
+ end
+ return head
+end
+
+local process = nodes.process_words
+
+nodes.rules.process = function(head) return process(a_ruled,data,flush_ruled,head) end
+
+function nodes.rules.enable()
+ tasks.enableaction("shipouts","nodes.rules.process")
+end
+
+-- elsewhere:
+--
+-- tasks.appendaction ("shipouts", "normalizers", "nodes.rules.process")
+-- tasks.disableaction("shipouts", "nodes.rules.process") -- only kick in when used
+
+local trace_shifted = false trackers.register("nodes.shifted", function(v) trace_shifted = v end)
+
+local a_shifted = attributes.private('shifted')
+
+nodes.shifts = nodes.shifts or { }
+nodes.shifts.data = nodes.shifts.data or { }
+
+storage.register("nodes/shifts/data", nodes.shifts.data, "nodes.shifts.data")
+
+local data = nodes.shifts.data
+
+function nodes.shifts.define(settings)
+ data[#data+1] = settings
+ texwrite(#data)
+end
+
+local function flush_shifted(head,first,last,data,level,parent,strip) -- not that fast but acceptable for this purpose
+ if true then
+ first, last = strip_range(first,last)
+ end
+ local prev, next = first.prev, last.next
+ first.prev, last.next = nil, nil
+ local width, height, depth = list_dimensions(parent.glue_set,parent.glue_sign,parent.glue_order,first,next)
+ local list = hpack_nodes(first,width,"exactly")
+ if first == head then
+ head = list
+ end
+ if prev then
+ prev.next, list.prev = list, prev
+ end
+ if next then
+ next.prev, list.next = list, next
+ end
+ local raise = data.dy * dimenfactor(data.unit,fontdata[first.font])
+ list.shift, list.height, list.depth = raise, height, depth
+ if trace_shifted then
+ logs.report("shifted", "width: %s, nodes: %s, text: %s",width,n_tostring(first,last),n_tosequence(first,last,true))
+ end
+ return head
+end
+
+local process = nodes.process_words
+
+nodes.shifts.process = function(head) return process(a_shifted,data,flush_shifted,head) end
+
+function nodes.shifts.enable()
+ tasks.enableaction("shipouts","nodes.shifts.process")
+end