summaryrefslogtreecommitdiff
path: root/tex/context/base/core-spa.lua
diff options
context:
space:
mode:
Diffstat (limited to 'tex/context/base/core-spa.lua')
-rw-r--r--tex/context/base/core-spa.lua290
1 files changed, 178 insertions, 112 deletions
diff --git a/tex/context/base/core-spa.lua b/tex/context/base/core-spa.lua
index 1d8616c3f..9b7486722 100644
--- a/tex/context/base/core-spa.lua
+++ b/tex/context/base/core-spa.lua
@@ -6,6 +6,8 @@ if not modules then modules = { } end modules ['core-spa'] = {
license = "see context related readme files"
}
+-- todo: test without unset
+
-- vertical space handler
nodes.snapvalues = { }
@@ -20,8 +22,6 @@ do
local kern, glue, penalty, hlist = node.id('kern'), node.id('glue'), node.id('penalty'), node.id('hlist')
- local penalty_node = node.new('penalty')
-
local has_attribute = node.has_attribute
local has_field = node.has_field
@@ -55,7 +55,7 @@ do
-- alignment box begin_of_par vmode_par hmode_par insert penalty before_display after_display
function nodes.is_display_math(head)
- n = head.prev
+ local n = head.prev
while n do
local id = n.id
if id == penalty then
@@ -86,18 +86,6 @@ do
-- helpers
- function nodes.snapline(current,where)
- local sn = has_attribute(current.list,snap_category)
- if sn then
- local sv = nodes.snapvalues[sn]
- if sv then
- local height, depth, lineheight = sv[1], sv[2], sv[3]
- current.height = math.ceil((current.height-height)/lineheight)*lineheight + height
- current.depth = math.ceil((current.depth -depth )/lineheight)*lineheight + depth
- end
- end
- end
-
-- local free = node.free
local line_skip = 1
@@ -112,6 +100,7 @@ do
local function collapser(head,where)
if head and head.next then
+ input.starttiming(nodes)
local trace = nodes.trace_collapse
local current, tail = head, nil
local glue_order, glue_data = 0, nil
@@ -213,8 +202,19 @@ do
if trace then trace_done("before",glue_data) end
glue_order, glue_data = 0, nil
end
- if id == hlist and where == 'hmode_par' and current.list then
- nodes.snapline(current,where) -- will be inline later
+ if id == hlist and where == 'hmode_par' then
+ local list = current.list
+ if list then
+ local sn = has_attribute(list,snap_category)
+ if sn then
+ local sv = nodes.snapvalues[sn]
+ if sv then
+ local height, depth, lineheight = sv[1], sv[2], sv[3]
+ current.height = math.ceil((current.height-height)/lineheight)*lineheight + height
+ current.depth = math.ceil((current.depth -depth )/lineheight)*lineheight + depth
+ end
+ end
+ end
end
current = current.next
end
@@ -230,8 +230,7 @@ do
head, current = nodes.remove(head, parskip, true)
end
if penalty_data then
- local p = node.copy(penalty_node)
- p.penalty = penalty_data
+ local p = nodes.penalty(penalty_data)
if trace then trace_done("before",p) end
head, head = nodes.before(head,head,p)
end
@@ -240,6 +239,7 @@ do
head, tail = nodes.after(head,tail,glue_data)
end
if trace then show_tracing() end
+ input.stoptiming(nodes)
end
return head
end
@@ -247,15 +247,13 @@ do
local head, tail = nil, nil
function nodes.flush_vertical_spacing()
- if head then
- input.start_timing(nodes)
+ if head and head.next then
local t = collapser(head)
head = nil
-- tail = nil
- input.stop_timing(nodes)
return t
else
- return nil
+ return head
end
end
@@ -275,7 +273,6 @@ do
tail = tt
t = nil
else
- input.start_timing(nodes)
if head then
t.prev = tail
tail.next = t
@@ -286,7 +283,6 @@ do
else
t = collapser(t,where)
end
- input.stop_timing(nodes,where)
end
elseif head then
t.prev = tail
@@ -302,7 +298,6 @@ do
function nodes.handle_vbox_spacing(t)
if t and t.next then
- local tail = node.slide(t)
return collapser(t,'whole')
else
return t
@@ -313,8 +308,10 @@ end
-- experimental callback definitions will be moved elsewhere
-callback.register('vpack_filter', nodes.handle_vbox_spacing)
-callback.register('buildpage_filter', nodes.handle_page_spacing)
+-- not yet ... we need to get rid of lastskip stuff first
+--
+-- callback.register('vpack_filter', nodes.handle_vbox_spacing)
+-- callback.register('buildpage_filter', nodes.handle_page_spacing)
-- horizontal stuff
@@ -322,13 +319,8 @@ callback.register('buildpage_filter', nodes.handle_page_spacing)
do
- local kern_node = node.new("kern",1)
- local penalty_node = node.new("penalty")
- local glue_node = node.new("glue")
- local glue_spec_node = node.new("glue_spec")
-
- local contains = node.has_attribute
- local unset = node.unset_attribute
+ local has_attribute = node.has_attribute
+ local unset = node.unset_attribute
local glyph = node.id("glyph")
local kern = node.id("kern")
@@ -337,32 +329,9 @@ do
local hlist = node.id('hlist')
local vlist = node.id('vlist')
---~ function nodes.penalty(p)
---~ local n = node.copy(penalty_node)
---~ n.penalty = p
---~ return n
---~ end
---~ function nodes.kern(k)
---~ local n = node.copy(kern_node)
---~ n.kern = k
---~ return n
---~ end
---~ function nodes.glue(width,stretch,shrink)
---~ local n = node.copy(glue_node)
---~ local s = node.copy(glue_spec_node)
---~ s.width, s.stretch, s.shrink = width, stretch, shrink
---~ n.spec = s
---~ return n
---~ end
---~ function nodes.glue_spec(width,stretch,shrink)
---~ local s = node.copy(glue_spec_node)
---~ s.width, s.stretch, s.shrink = width, stretch, shrink
---~ return s
---~ end
-
spacings = spacings or { }
spacings.mapping = spacings.mapping or { }
- spacings.enabled = true
+ spacings.enabled = false
input.storage.register(false,"spacings/mapping", spacings.mapping, "spacings.mapping")
@@ -380,14 +349,16 @@ do
map.left, map.right = left, right
end
+ -- todo: no ligatures
+
function spacings.process(namespace,attribute,head)
local done, mapping, fontids = false, spacings.mapping, fonts.tfm.id
for start in node.traverse_id(glyph,head) do -- tricky since we inject
- local attr = contains(start,attribute)
+ local attr = has_attribute(start,attribute)
if attr then
local map = mapping[attr]
if map then
- map = mapping[attr][start.char]
+ map = map[start.char]
unset(start,attribute)
if map then
local kern, prev = map.left, start.prev
@@ -414,7 +385,7 @@ do
kerns = kerns or { }
kerns.mapping = kerns.mapping or { }
- kerns.enabled = true
+ kerns.enabled = false
input.storage.register(false, "kerns/mapping", kerns.mapping, "kerns.mapping")
@@ -425,12 +396,12 @@ do
-- local marks = fti[font].shared.otfdata.luatex.marks
-- if not marks[tchar] then
- function kerns.process(namespace,attribute,head) -- todo interchar kerns / disc nodes
+ function kerns.process(namespace,attribute,head) -- todo interchar kerns / disc nodes / can be made faster
local fti, scale = fonts.tfm.id, tex.scale
local start, done, mapping, fontids, lastfont = head, false, kerns.mapping, fonts.tfm.id, nil
while start do
-- faster to test for attr first
- local attr = contains(start,attribute)
+ local attr = has_attribute(start,attribute)
if attr then
unset(start,attribute)
local krn = mapping[attr]
@@ -485,38 +456,87 @@ do
node.insert_before(head,start,nodes.kern(krn))
done = true
elseif pid == disc then
- local d = start.prev
- local pre, post = d.pre, d.post
- if pre then
- local p = d.prev
- local nn, pp = p.prev, p.next
- p.prev, p.next = nil, pre -- hijack node
- pre = kerns.process(namespace,attribute,p)
+ -- probably wrong anyway
+ -- currently this hooks into the node handlere before
+ -- hyphenation takes place, but this may change
+ --
+ -- local d = start.prev
+ -- local pre, post = d.pre, d.post
+ -- if pre then
+ -- local p = d.prev
+ -- local nn, pp = p.prev, p.next
+ -- p.prev, p.next = nil, pre -- hijack node
+ -- pre = kerns.process(namespace,attribute,p)
+ -- pre = pre.next
+ -- pre.prev = nil
+ -- p.prev, p.next = nn, pp
+ -- d.pre = pre
+ -- end
+ -- if post then -- more checks needed
+ -- local tail = node.slide(post)
+ -- local nn, pp = d.next.prev, d.next.next
+ -- d.next.next, d.next.prev = nil, tail
+ -- tail.next = start.next -- hijack node
+ -- post = kerns.process(namespace,attribute,post)
+ -- tail.next = nil
+ -- d.next.prev, d.next.next = nn, pp
+ -- d.post = post
+ -- end
+ -- local prevchar, nextchar = d.prev.char, d.next.char -- == start.char
+ -- local tfm = fti[lastfont].characters[prevchar]
+ -- local ickern = tfm.kerns
+ -- if ickern and ickern[nextchar] then
+ -- krn = scale(ickern[nextchar]+fontids[lastfont].parameters[6],krn)
+ -- else
+ -- krn = scale(fontids[lastfont].parameters[6],krn)
+ -- end
+ -- node.insert_before(head,start,nodes.kern(krn))
+ -- d.replace = d.replace + 1
+ --
+ -- untested:
+ --
+ local disc = start.prev -- disc
+ local pre, post, replace = disc.pre, disc.post, disc.replace
+ if pre then -- must pair with start.prev
+ local before = node.copy(disc.prev)
+ pre.prev = before
+ before.next = pre
+ before.prev = nil
+ pre = kerns.process(namespace,attribute,before)
pre = pre.next
pre.prev = nil
- p.prev, p.next = nn, pp
- d.pre = pre
+ disc.pre = pre
+ node.free(before)
end
- if post then
+ if post then -- must pair with start
+ local after = node.copy(disc.next)
local tail = node.slide(post)
- local nn, pp = d.next.prev, d.next.next
- d.next.next, d.next.prev = nil, tail
- tail.next = start.next -- hijack node
+ tail.next = after
+ after.prev = tail
+ after.next = nil
post = kerns.process(namespace,attribute,post)
tail.next = nil
- d.next.prev, d.next.next = nn, pp
- d.post = post
+ disc.post = post
+ node.free(after)
end
- local prevchar, nextchar = d.prev.char, d.next.char -- == start.char
- local tfm = fti[lastfont].characters[prevchar]
- local ickern = tfm.kerns
- if ickern and ickern[nextchar] then
- krn = scale(ickern[nextchar]+fontids[lastfont].parameters[6],krn)
- else
- krn = scale(fontids[lastfont].parameters[6],krn)
+ if replace then -- must pair with start and start.prev
+ local before = node.copy(disc.prev)
+ local after = node.copy(disc.next)
+ local tail = node.slide(post)
+ replace.prev = before
+ before.next = replace
+ before.prev = nil
+ tail.next = after
+ after.prev = tail
+ after.next = nil
+ replace = kerns.process(namespace,attribute,before)
+ replace = replace.next
+ replace.prev = nil
+ tail.next = nil
+ disc.replace = replace
+ node.free(after)
+ node.free(before)
end
- node.insert_before(head,start,nodes.kern(krn))
- d.replace = d.replace + 1
end
end
elseif id == glue and start.subtype == 0 then
@@ -534,7 +554,7 @@ do
start.kern = scale(sk,krn)
done = true
end
- elseif lastfont and id == hlist or id == vlist then -- todo: lookahead
+ elseif lastfont and (id == hlist or id == vlist) then -- todo: lookahead
if start.prev then
node.insert_before(head,start,nodes.kern(scale(fontids[lastfont].parameters[6],krn)))
done = true
@@ -562,7 +582,7 @@ do
-- relocate node and attribute stuff once it's more complete !!
cases = cases or { }
- cases.enabled = true
+ cases.enabled = false
cases.actions = { }
-- hm needs to be run before glyphs: chars.plugins
@@ -581,7 +601,7 @@ do
local function lower(start)
local data, char = characters.data, start.char
if data[char] then
- local ul = data[char].ulcode
+ local lc = data[char].lccode
if lc and fonts.tfm.id[start.font].characters[lc] then
start.char = lc
return start, true
@@ -656,7 +676,7 @@ do
function cases.process(namespace,attribute,head) -- not real fast but also not used on much data
local done, actions = false, cases.actions
for start in node.traverse_id(glyph,head) do
- local attr = contains(start,attribute)
+ local attr = has_attribute(start,attribute)
if attr then
unset(start,attribute)
local action = actions[attr]
@@ -676,7 +696,8 @@ do
breakpoints = breakpoints or { }
breakpoints.mapping = breakpoints.mapping or { }
- breakpoints.enabled = true
+ breakpoints.methods = breakpoints.methods or { }
+ breakpoints.enabled = false
input.storage.register(false,"breakpoints/mapping", breakpoints.mapping, "breakpoints.mapping")
@@ -689,39 +710,84 @@ do
mapping[char] = { kind or 1, before or 1, after or 1 }
end
+ breakpoints.methods[1] = function(head,start)
+ -- no discretionary needed
+ -- \def\prewordbreak {\penalty\plustenthousand\hskip\zeropoint\relax}
+ -- \def\postwordbreak {\penalty\zerocount\hskip\zeropoint\relax}
+ -- texio.write_nl(string.format("injecting replacement type %s for character %s",map[1],utf.char(start.char)))
+ if start.prev and start.next then
+ node.insert_before(head,start,nodes.penalty(10000))
+ node.insert_before(head,start,nodes.glue(0))
+ node.insert_after(head,start,nodes.glue(0))
+ node.insert_after(head,start,nodes.penalty(0))
+ end
+ return head, start
+ end
+ breakpoints.methods[2] = function(head,start) -- ( => (-
+ if start.prev and start.next then
+ local tmp = start
+ start = nodes.disc()
+ start.prev, start.next = tmp.prev, tmp.next
+ tmp.prev.next, tmp.next.prev = start, start
+ tmp.prev, tmp.next = nil, nil
+ start.replace = tmp
+ local tmp, hyphen = node.copy(tmp), node.copy(tmp)
+ hyphen.char = languages.prehyphenchar(tmp.lang)
+ tmp.next, hyphen.prev = hyphen, tmp
+ start.post = tmp
+ node.insert_before(head,start,nodes.penalty(10000))
+ node.insert_before(head,start,nodes.glue(0))
+ node.insert_after(head,start,nodes.glue(0))
+ node.insert_after(head,start,nodes.penalty(10000))
+ end
+ return head, start
+ end
+ breakpoints.methods[3] = function(head,start) -- ) => -)
+ if start.prev and start.next then
+ local tmp = start
+ start = nodes.disc()
+ start.prev, start.next = tmp.prev, tmp.next
+ tmp.prev.next, tmp.next.prev = start, start
+ tmp.prev, tmp.next = nil, nil
+ start.replace = tmp
+ local tmp, hyphen = node.copy(tmp), node.copy(tmp)
+ hyphen.char = languages.prehyphenchar(tmp.lang)
+ tmp.prev, hyphen.next = hyphen, tmp
+ start.pre = hyphen
+ node.insert_before(head,start,nodes.penalty(10000))
+ node.insert_before(head,start,nodes.glue(0))
+ node.insert_after(head,start,nodes.glue(0))
+ node.insert_after(head,start,nodes.penalty(10000))
+ end
+ return head, start
+ end
+
function breakpoints.process(namespace,attribute,head)
local done, mapping, fontids = false, breakpoints.mapping, fonts.tfm.id
local start, n = head, 0
while start do
local id = start.id
if id == glyph then
- local attr = contains(start,attribute)
+ local attr = has_attribute(start,attribute)
if attr then
- unset(start,attribute)
+ unset(start,attribute) -- maybe test for subtype > 256 (faster)
-- look ahead and back n chars
local map = mapping[attr]
if map then
- map = map[start.char]
- if map then
- if n >= map[2] then
- local m = map[3]
+ local smap = map[start.char]
+ if smap then
+ if n >= smap[2] then
+ local m = smap[3]
local next = start.next
while next do -- gamble on same attribute
local id = next.id
if id == glyph then -- gamble on same attribute
- if m == 1 then
- if map[1] == 1 then
- -- no discretionary needed
- -- \def\prewordbreak {\penalty\plustenthousand\hskip\zeropoint\relax}
- -- \def\postwordbreak {\penalty\zerocount\hskip\zeropoint\relax}
- -- texio.write_nl(string.format("injecting replacement type %s for character %s",map[1],utf.char(start.char)))
- local g, p = nodes.glue(0), nodes.penalty(10000)
- node.insert_before(head,start,g)
- node.insert_before(head,g,p)
- g, p = nodes.glue(0), nodes.penalty(0)
- node.insert_after(head,start,p)
- node.insert_after(head,p,g)
- start = g
+ if map[next.char] then
+ break
+ elseif m == 1 then
+ local method = breakpoints.methods[smap[1]]
+ if method then
+ head, start = method(head,start)
done = true
end
break