diff options
Diffstat (limited to 'tex/context/base/node-rul.lua')
-rw-r--r-- | tex/context/base/node-rul.lua | 778 |
1 files changed, 389 insertions, 389 deletions
diff --git a/tex/context/base/node-rul.lua b/tex/context/base/node-rul.lua index 00039550c..09300964e 100644 --- a/tex/context/base/node-rul.lua +++ b/tex/context/base/node-rul.lua @@ -1,389 +1,389 @@ -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
---
--- todo: make robust for layers ... order matters
-
-local attributes, nodes, node = attributes, nodes, node
-
-local nodecodes = nodes.nodecodes
-local tasks = nodes.tasks
-
-local glyph_code = nodecodes.glyph
-local disc_code = nodecodes.disc
-local rule_code = nodecodes.rule
-
-function nodes.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 = first.id
- if id == glyph_code or id == disc_code then -- or id == rule_code
- break
- else
- first = first.next
- 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 = last.id
- if id == glyph_code or id == disc_code then -- or id == rule_code
- break
- else
- local prev = last.prev -- luatex < 0.70 has italic correction kern not prev'd
- if prev then
- last = last.prev
- else
- break
- end
- end
- end
- if not last then
- return nil, nil
- end
- end
- 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_color = attributes.private('color')
-local a_transparency = attributes.private('transparency')
-local a_colorspace = attributes.private('colormodel')
-
-local insert_node_before = node.insert_before
-local insert_node_after = node.insert_after
-local striprange = nodes.striprange
-local list_dimensions = node.dimensions
-
-local hpack_nodes = node.hpack
-
-local fontdata = fonts.hashes.identifiers
-local variables = interfaces.variables
-local dimenfactor = fonts.helpers.dimenfactor
-local splitdimen = number.splitdimen
-
-local nodecodes = nodes.nodecodes
-local skipcodes = nodes.skipcodes
-local whatcodes = nodes.whatcodes
-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 whatsit_code = nodecodes.whatsit
-
-local userskip_code = skipcodes.userskip
-local spaceskip_code = skipcodes.spaceskip
-local xspaceskip_code = skipcodes.xspaceskip
-
-local dir_code = whatcodes.dir
-
-local kerning_code = kerncodes.kern
-
-local nodepool = nodes.pool
-
-local new_rule = nodepool.rule
-local new_kern = nodepool.kern
-local new_glue = nodepool.glue
-
--- 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
---
--- 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
-
-local function processwords(attribute,data,flush,head,parent) -- we have hlistdir and local dir
- local n = head
- if n then
- local f, l, a, d, i, class
- local continue, done, strip, level = false, false, true, -1
- while n do
- local id = n.id
- if id == glyph_code or id == rule_code then
- local aa = 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
- local newlevel, newclass = floor(aa/1000), aa%1000
---~ 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]
- 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_code or (id == kern_code and n.subtype == kerning_code)) then
- l = n
- 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 = n.list
- if list then
- n.list = processwords(attribute,data,flush,list,n)
- end
- elseif checkdir and id == whatsit_code and n.subtype == dir_code 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_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 = n.subtype
- if continue and n[attribute] and
- (subtype == userskip_code or subtype == spaceskip_code or subskip == xspaceskip_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 = 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.processwords = processwords
-
---
-
-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
- 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
--- check for f and l
- if f.id ~= glyph_code then
- -- saveguard ... we need to deal with rules and so (math)
- return head
- end
- local r, m
- if strip then
- if trace_ruled then
- local before = n_tosequence(f,l,true)
- f, l = striprange(f,l)
- local after = n_tosequence(f,l,true)
- report_ruled("range stripper, before %a, after %a",before,after)
- else
- f, l = striprange(f,l)
- end
- end
- if not f then
- return head
- end
- local w = list_dimensions(parent.glue_set,parent.glue_sign,parent.glue_order,f,l.next)
- local method, offset, continue, dy, order, max = d.method, d.offset, d.continue, d.dy, d.order, d.max
- local rulethickness, unit = d.rulethickness, d.unit
- local ma, ca, ta = d.ma, d.ca, d.ta
- local colorspace = (ma > 0 and ma) or f[a_colorspace] or 1
- local color = (ca > 0 and ca) or f[a_color]
- local transparency = (ta > 0 and ta) or f[a_transparency]
- local foreground = order == variables.foreground
-
- local e = dimenfactor(unit,fontdata[f.font]) -- what if no glyph node
-
- local rt = tonumber(rulethickness)
- if rt then
- rulethickness = e * rulethickness / 2
- else
- local n, u = splitdimen(rulethickness)
- if n and u then -- we need to intercept ex and em and % and ...
- rulethickness = n * dimenfactor(u,fontdata[f.font]) / 2
- else
- rulethickness = 1/5
- end
- end
-
- if level > max then
- level = max
- end
- if method == 0 then -- center
- offset = 2*offset
--- m = (offset+(level-1)*dy+rulethickness)*e/2
- m = (offset+(level-1)*dy)*e/2 + rulethickness/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 ht = (offset+(i-1)*dy)*e + rulethickness - m
- local dp = -(offset+(i-1)*dy)*e + rulethickness + m
- local r = new_rule(w,ht,dp)
- local v = f[a_viewerlayer]
- -- quick hack
- if v then
- r[a_viewerlayer] = v
- end
- --
- if color then
- r[a_colorspace] = colorspace
- r[a_color] = color
- end
- if transparency then
- r[a_transparency] = transparency
- end
- local k = new_kern(-w)
- if foreground then
- insert_node_after(head,l,k)
- insert_node_after(head,k,r)
- l = r
- else
- head = insert_node_before(head,f,r)
- insert_node_after(head,r,k)
- end
- if trace_ruled then
- report_ruled("level %a, width %p, height %p, depth %p, nodes %a, text %a",
- level,w,ht,dp,n_tostring(f,l),n_tosequence(f,l,true))
- end
- end
- return head
-end
-
-local process = nodes.processwords
-
-nodes.rules.handler = function(head) return process(a_ruled,data,flush_ruled,head) end
-
-function nodes.rules.enable()
- tasks.enableaction("shipouts","nodes.rules.handler")
-end
-
--- elsewhere:
---
--- tasks.appendaction ("shipouts", "normalizers", "nodes.rules.handler")
--- tasks.disableaction("shipouts", "nodes.rules.handler") -- only kick in when used
-
-local trace_shifted = false trackers.register("nodes.shifting", function(v) trace_shifted = v end)
-
-local report_shifted = logs.reporter("nodes","shifting")
-
-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
- context(#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 = striprange(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
- report_shifted("width %p, nodes %a, text %a",width,n_tostring(first,last),n_tosequence(first,last,true))
- end
- return head
-end
-
-local process = nodes.processwords
-
-nodes.shifts.handler = function(head) return process(a_shifted,data,flush_shifted,head) end
-
-function nodes.shifts.enable()
- tasks.enableaction("shipouts","nodes.shifts.handler")
-end
+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 +-- +-- todo: make robust for layers ... order matters + +local attributes, nodes, node = attributes, nodes, node + +local nodecodes = nodes.nodecodes +local tasks = nodes.tasks + +local glyph_code = nodecodes.glyph +local disc_code = nodecodes.disc +local rule_code = nodecodes.rule + +function nodes.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 = first.id + if id == glyph_code or id == disc_code then -- or id == rule_code + break + else + first = first.next + 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 = last.id + if id == glyph_code or id == disc_code then -- or id == rule_code + break + else + local prev = last.prev -- luatex < 0.70 has italic correction kern not prev'd + if prev then + last = last.prev + else + break + end + end + end + if not last then + return nil, nil + end + end + 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_color = attributes.private('color') +local a_transparency = attributes.private('transparency') +local a_colorspace = attributes.private('colormodel') + +local insert_node_before = node.insert_before +local insert_node_after = node.insert_after +local striprange = nodes.striprange +local list_dimensions = node.dimensions + +local hpack_nodes = node.hpack + +local fontdata = fonts.hashes.identifiers +local variables = interfaces.variables +local dimenfactor = fonts.helpers.dimenfactor +local splitdimen = number.splitdimen + +local nodecodes = nodes.nodecodes +local skipcodes = nodes.skipcodes +local whatcodes = nodes.whatcodes +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 whatsit_code = nodecodes.whatsit + +local userskip_code = skipcodes.userskip +local spaceskip_code = skipcodes.spaceskip +local xspaceskip_code = skipcodes.xspaceskip + +local dir_code = whatcodes.dir + +local kerning_code = kerncodes.kern + +local nodepool = nodes.pool + +local new_rule = nodepool.rule +local new_kern = nodepool.kern +local new_glue = nodepool.glue + +-- 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 +-- +-- 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 + +local function processwords(attribute,data,flush,head,parent) -- we have hlistdir and local dir + local n = head + if n then + local f, l, a, d, i, class + local continue, done, strip, level = false, false, true, -1 + while n do + local id = n.id + if id == glyph_code or id == rule_code then + local aa = 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 + local newlevel, newclass = floor(aa/1000), aa%1000 +--~ 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] + 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_code or (id == kern_code and n.subtype == kerning_code)) then + l = n + 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 = n.list + if list then + n.list = processwords(attribute,data,flush,list,n) + end + elseif checkdir and id == whatsit_code and n.subtype == dir_code 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_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 = n.subtype + if continue and n[attribute] and + (subtype == userskip_code or subtype == spaceskip_code or subskip == xspaceskip_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 = 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.processwords = processwords + +-- + +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 + 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 +-- check for f and l + if f.id ~= glyph_code then + -- saveguard ... we need to deal with rules and so (math) + return head + end + local r, m + if strip then + if trace_ruled then + local before = n_tosequence(f,l,true) + f, l = striprange(f,l) + local after = n_tosequence(f,l,true) + report_ruled("range stripper, before %a, after %a",before,after) + else + f, l = striprange(f,l) + end + end + if not f then + return head + end + local w = list_dimensions(parent.glue_set,parent.glue_sign,parent.glue_order,f,l.next) + local method, offset, continue, dy, order, max = d.method, d.offset, d.continue, d.dy, d.order, d.max + local rulethickness, unit = d.rulethickness, d.unit + local ma, ca, ta = d.ma, d.ca, d.ta + local colorspace = (ma > 0 and ma) or f[a_colorspace] or 1 + local color = (ca > 0 and ca) or f[a_color] + local transparency = (ta > 0 and ta) or f[a_transparency] + local foreground = order == variables.foreground + + local e = dimenfactor(unit,fontdata[f.font]) -- what if no glyph node + + local rt = tonumber(rulethickness) + if rt then + rulethickness = e * rulethickness / 2 + else + local n, u = splitdimen(rulethickness) + if n and u then -- we need to intercept ex and em and % and ... + rulethickness = n * dimenfactor(u,fontdata[f.font]) / 2 + else + rulethickness = 1/5 + end + end + + if level > max then + level = max + end + if method == 0 then -- center + offset = 2*offset +-- m = (offset+(level-1)*dy+rulethickness)*e/2 + m = (offset+(level-1)*dy)*e/2 + rulethickness/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 ht = (offset+(i-1)*dy)*e + rulethickness - m + local dp = -(offset+(i-1)*dy)*e + rulethickness + m + local r = new_rule(w,ht,dp) + local v = f[a_viewerlayer] + -- quick hack + if v then + r[a_viewerlayer] = v + end + -- + if color then + r[a_colorspace] = colorspace + r[a_color] = color + end + if transparency then + r[a_transparency] = transparency + end + local k = new_kern(-w) + if foreground then + insert_node_after(head,l,k) + insert_node_after(head,k,r) + l = r + else + head = insert_node_before(head,f,r) + insert_node_after(head,r,k) + end + if trace_ruled then + report_ruled("level %a, width %p, height %p, depth %p, nodes %a, text %a", + level,w,ht,dp,n_tostring(f,l),n_tosequence(f,l,true)) + end + end + return head +end + +local process = nodes.processwords + +nodes.rules.handler = function(head) return process(a_ruled,data,flush_ruled,head) end + +function nodes.rules.enable() + tasks.enableaction("shipouts","nodes.rules.handler") +end + +-- elsewhere: +-- +-- tasks.appendaction ("shipouts", "normalizers", "nodes.rules.handler") +-- tasks.disableaction("shipouts", "nodes.rules.handler") -- only kick in when used + +local trace_shifted = false trackers.register("nodes.shifting", function(v) trace_shifted = v end) + +local report_shifted = logs.reporter("nodes","shifting") + +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 + context(#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 = striprange(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 + report_shifted("width %p, nodes %a, text %a",width,n_tostring(first,last),n_tosequence(first,last,true)) + end + return head +end + +local process = nodes.processwords + +nodes.shifts.handler = function(head) return process(a_shifted,data,flush_shifted,head) end + +function nodes.shifts.enable() + tasks.enableaction("shipouts","nodes.shifts.handler") +end |