diff options
Diffstat (limited to 'tex/context/base/core-spa.lua')
-rw-r--r-- | tex/context/base/core-spa.lua | 290 |
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 |