diff options
author | Taco Hoekwater <taco@elvenkind.com> | 2011-06-01 08:54:21 +0000 |
---|---|---|
committer | Taco Hoekwater <taco@elvenkind.com> | 2011-06-01 08:54:21 +0000 |
commit | d7ccb42582f85acf30568913610ccf4d602023fb (patch) | |
tree | 7292e3545a420676878e7451b68892d360c62cb6 /Master/texmf-dist/tex/context/base/spac-ver.lua | |
parent | 2d62a6fe9b80def59c392268022f1f9a2d6e358f (diff) |
commit context 2011.05.18
git-svn-id: svn://tug.org/texlive/trunk@22719 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/tex/context/base/spac-ver.lua')
-rw-r--r-- | Master/texmf-dist/tex/context/base/spac-ver.lua | 839 |
1 files changed, 498 insertions, 341 deletions
diff --git a/Master/texmf-dist/tex/context/base/spac-ver.lua b/Master/texmf-dist/tex/context/base/spac-ver.lua index c75eb1baa68..83ee6e49208 100644 --- a/Master/texmf-dist/tex/context/base/spac-ver.lua +++ b/Master/texmf-dist/tex/context/base/spac-ver.lua @@ -20,69 +20,89 @@ if not modules then modules = { } end modules ['spac-ver'] = { -- todo: strip baselineskip around display math local next, type, tonumber = next, type, tonumber -local format, gmatch, concat, match = string.format, string.gmatch, table.concat, string.match -local ceil, floor, max, min, round = math.ceil, math.floor, math.max, math.min, math.round -local texsprint, texlists, texdimen, texbox = tex.sprint, tex.lists, tex.dimen, tex.box +local format, gmatch, concat, match, rep = string.format, string.gmatch, table.concat, string.match, string.rep +local ceil, floor, max, min, round, abs = math.ceil, math.floor, math.max, math.min, math.round, math.abs +local texlists, texdimen, texbox = tex.lists, tex.dimen, tex.box local lpegmatch = lpeg.match local unpack = unpack or table.unpack +local points = number.points +local allocate = utilities.storage.allocate -local ctxcatcodes = tex.ctxcatcodes -local variables = interfaces.variables +local P, C, R, S, Cc = lpeg.P, lpeg.C, lpeg.R, lpeg.S, lpeg.Cc -local starttiming, stoptiming = statistics.starttiming, statistics.stoptiming +local nodes, node, trackers, attributes, context = nodes, node, trackers, attributes, context + +local variables = interfaces.variables + +local starttiming = statistics.starttiming +local stoptiming = statistics.stoptiming -- vertical space handler -local trace_vbox_vspacing = false trackers.register("nodes.vbox_vspacing", function(v) trace_vbox_vspacing = v end) -local trace_page_vspacing = false trackers.register("nodes.page_vspacing", function(v) trace_page_vspacing = v end) -local trace_collect_vspacing = false trackers.register("nodes.collect_vspacing", function(v) trace_collect_vspacing = v end) -local trace_vspacing = false trackers.register("nodes.vspacing", function(v) trace_vspacing = v end) -local trace_vsnapping = false trackers.register("nodes.vsnapping", function(v) trace_vsnapping = v end) - -local skip_category = attributes.private('skip-category') -local skip_penalty = attributes.private('skip-penalty') -local skip_order = attributes.private('skip-order') -local snap_category = attributes.private('snap-category') -local display_math = attributes.private('display-math') -local snap_method = attributes.private('snap-method') -local snap_done = attributes.private('snap-done') - -local has_attribute = node.has_attribute -local unset_attribute = node.unset_attribute -local set_attribute = node.set_attribute -local find_node_tail = node.tail -local free_node = node.free -local copy_node = node.copy -local traverse_nodes = node.traverse -local traverse_nodes_id = node.traverse_id -local insert_node_before = node.insert_before -local insert_node_after = node.insert_after -local remove_node = nodes.remove -local make_penalty_node = nodes.penalty -local make_kern_node = nodes.kern -local make_rule_node = nodes.rule -local count_nodes = nodes.count -local node_ids_to_string = nodes.ids_to_string -local hpack_node = node.hpack -local vpack_node = node.vpack -local writable_spec = nodes.writable_spec - -local glyph = node.id("glyph") -local penalty = node.id("penalty") -local kern = node.id("kern") -local glue = node.id('glue') -local hlist = node.id('hlist') -local vlist = node.id('vlist') -local adjust = node.id('adjust') - -vspacing = vspacing or { } -vspacing.data = vspacing.data or { } +local trace_vbox_vspacing = false trackers.register("builders.vbox_vspacing", function(v) trace_vbox_vspacing = v end) +local trace_page_vspacing = false trackers.register("builders.page_vspacing", function(v) trace_page_vspacing = v end) +local trace_collect_vspacing = false trackers.register("builders.collect_vspacing", function(v) trace_collect_vspacing = v end) +local trace_vspacing = false trackers.register("builders.vspacing", function(v) trace_vspacing = v end) +local trace_vsnapping = false trackers.register("builders.vsnapping", function(v) trace_vsnapping = v end) +local trace_vpacking = false trackers.register("builders.vpacking", function(v) trace_vpacking = v end) + +local report_vspacing = logs.reporter("vspacing","spacing") +local report_collapser = logs.reporter("vspacing","collapsing") +local report_snapper = logs.reporter("vspacing","snapping") + +local a_skipcategory = attributes.private('skipcategory') +local a_skippenalty = attributes.private('skippenalty') +local a_skiporder = attributes.private('skiporder') +----- snap_category = attributes.private('snapcategory') +local a_snapmethod = attributes.private('snapmethod') +local a_snapvbox = attributes.private('snapvbox') + +local has_attribute = node.has_attribute +local unset_attribute = node.unset_attribute +local set_attribute = node.set_attribute +local find_node_tail = node.tail +local free_node = node.free +local copy_node = node.copy +local traverse_nodes = node.traverse +local traverse_nodes_id = node.traverse_id +local insert_node_before = node.insert_before +local insert_node_after = node.insert_after +local remove_node = nodes.remove +local count_nodes = nodes.count +local nodeidstostring = nodes.idstostring +local hpack_node = node.hpack +local vpack_node = node.vpack +local writable_spec = nodes.writable_spec +local listtoutf = nodes.listtoutf + +local nodepool = nodes.pool + +local new_penalty = nodepool.penalty +local new_kern = nodepool.kern +local new_rule = nodepool.rule +local new_gluespec = nodepool.gluespec + +local nodecodes = nodes.nodecodes +local skipcodes = nodes.skipcodes +local fillcodes = nodes.fillcodes + +local penalty_code = nodecodes.penalty +local kern_code = nodecodes.kern +local glue_code = nodecodes.glue +local hlist_code = nodecodes.hlist +local vlist_code = nodecodes.vlist +local whatsit_code = nodecodes.whatsit + +local userskip_code = skipcodes.userskip + +builders.vspacing = builders.vspacing or { } +local vspacing = builders.vspacing +vspacing.data = vspacing.data or { } vspacing.data.snapmethods = vspacing.data.snapmethods or { } +local snapmethods = vspacing.data.snapmethods --maybe some older code can go -storage.register("vspacing/data/snapmethods", vspacing.data.snapmethods, "vspacing.data.snapmethods") - -local snapmethods = vspacing.data.snapmethods --maybe some older code can go +storage.register("builders/vspacing/data/snapmethods", snapmethods, "builders.vspacing.data.snapmethods") local default = { maxheight = true, @@ -144,7 +164,7 @@ local function listtohash(str) end end -function vspacing.define_snap_method(name,method) +function vspacing.definesnapmethod(name,method) local n = #snapmethods + 1 local t = listtohash(method) snapmethods[n] = t @@ -152,8 +172,8 @@ function vspacing.define_snap_method(name,method) tex.write(n) end ---~ local rule_id = node.id("rule") ---~ local vlist_id = node.id("vlist") +--~ local rule_id = nodecodes.rule +--~ local vlist_id = nodecodes.vlist --~ function nodes.makevtop(n) --~ if n.id == vlist_id then --~ local list = n.list @@ -163,14 +183,111 @@ end --~ end --~ end -local function snap_hlist(current,method,height,depth) -- method.strut is default - local snapht, snapdp +local reference = nodes.reference + +local function validvbox(parentid,list) + if parentid == hlist_code then + local id = list.id + if id == whatsit_code then -- check for initial par subtype + list = list.next + if not next then + return nil + end + end + local done = nil + for n in traverse_nodes(list) do + local id = n.id + if id == vlist_code or id == hlist_code then + if done then + return nil + else + done = n + end + elseif id == penalty_code or id == glue_code then + -- go on + else + return nil -- whatever + end + end + if done and done.id == hlist_code then + return validvbox(done.id,done.list) + end + return done -- only one vbox + end +end + +local function already_done(parentid,list,a_snapmethod) -- todo: done when only boxes and all snapped + -- problem: any snapped vbox ends up in a line + if list and parentid == hlist_code then + local id = list.id + if id == whatsit_code then -- check for initial par subtype + list = list.next + if not next then + return false + end + end +--~ local i = 0 + for n in traverse_nodes(list) do + local id = n.id +--~ i = i + 1 print(i,nodecodes[id],has_attribute(n,a_snapmethod)) + if id == hlist_code or id == vlist_code then + local a = has_attribute(n,a_snapmethod) + if not a then + -- return true -- not snapped at all + elseif a == 0 then + return true -- already snapped + end + elseif id == penalty_code or id == glue_code then -- whatsit is weak spot + -- go on + else + return false -- whatever + end + end + end + return false +end + + +-- quite tricky: ceil(-something) => -0 + +local function ceiled(n) + if n < 0 or n < 0.01 then + return 0 + else + return ceil(n) + end +end + +local function floored(n) + if n < 0 or n < 0.01 then + return 0 + else + return floor(n) + end +end + +local function snap_hlist(where,current,method,height,depth) -- method.strut is default + local list = current.list --~ print(table.serialize(method)) + local t = trace_vsnapping and { } + if t then + t[#t+1] = format("list content: %s",nodes.toutf(list)) + t[#t+1] = format("parent id: %s",reference(current)) + t[#t+1] = format("snap method: %s",method.name) + t[#t+1] = format("specification: %s",method.specification) + end + local snapht, snapdp if method["local"] then -- snapping is done immediately here snapht, snapdp = texdimen.bodyfontstrutheight, texdimen.bodyfontstrutdepth + if t then + t[#t+1] = format("local: snapht %s snapdp %s",points(snapht),points(snapdp)) + end elseif method["global"] then snapht, snapdp = texdimen.globalbodyfontstrutheight, texdimen.globalbodyfontstrutdepth + if t then + t[#t+1] = format("global: snapht %s snapdp %s",points(snapht),points(snapdp)) + end else -- maybe autolocal -- snapping might happen later in the otr @@ -179,110 +296,207 @@ local function snap_hlist(current,method,height,depth) -- method.strut is defaul if snapht ~= lsnapht and snapdp ~= lsnapdp then snapht, snapdp = lsnapht, lsnapdp end + if t then + t[#t+1] = format("auto: snapht %s snapdp %s",points(snapht),points(snapdp)) + end end local h, d = height or current.height, depth or current.depth local hr, dr, ch, cd = method.hfraction or 1, method.dfraction or 1, h, d local tlines, blines = method.tlines or 1, method.blines or 1 local done, plusht, plusdp = false, snapht, snapdp local snaphtdp = snapht + snapdp + if method.none then plusht, plusdp = 0, 0 + if t then + t[#t+1] = format("none: plusht 0pt plusdp 0pt") + end end - if method.halfline then + if method.halfline then -- extra halfline plusht, plusdp = plusht + snaphtdp/2, plusdp + snaphtdp/2 + if t then + t[#t+1] = format("halfline: plusht %s plusdp %s",points(plusht),points(plusdp)) + end end - if method.line then + if method.line then -- extra line plusht, plusdp = plusht + snaphtdp, plusdp + snaphtdp + if t then + t[#t+1] = format("line: plusht %s plusdp %s",points(plusht),points(plusdp)) + end end if method.first then - if current.id == vlist then - local list, lh, ld = current.list - for n in traverse_nodes_id(hlist,list) do + local thebox = current + local id = thebox.id + if id == hlist_code then + thebox = validvbox(id,thebox.list) + id = thebox and thebox.id + end + if thebox and id == vlist_code then + local list, lh, ld = thebox.list + for n in traverse_nodes_id(hlist_code,list) do lh, ld = n.height, n.depth break end if lh then - local x = max(ceil((lh-hr*snapht)/snaphtdp),0)*snaphtdp + plusht - local n = make_kern_node(x-lh) - n.next, list.prev, current.list = list, n, n - ch = x + snaphtdp - cd = max(ceil((d+h-lh-dr*snapdp-hr*snapht)/snaphtdp),0)*snaphtdp + plusdp + local ht, dp = thebox.height, thebox.depth + if t then + t[#t+1] = format("first line: height %s depth %s",points(lh),points(ld)) + t[#t+1] = format("dimensions: height %s depth %s",points(ht),points(dp)) + end + local delta = h - lh + ch, cd = lh, delta + d +--~ ch = ch + plusht +--~ cd = cd + plusdp +h, d = ch, cd + local shifted = hpack_node(current.list) + shifted.shift = delta + current.list = shifted done = true + if t then + t[#t+1] = format("first: height %s depth %s shift %s",points(ch),points(cd),points(delta)) + end + elseif t then + t[#t+1] = "first: not done, no content" end + elseif t then + t[#t+1] = "first: not done, no vbox" end elseif method.last then - if current.id == vlist then - local list, lh, ld = current.list - for n in traverse_nodes_id(hlist,list) do + local thebox = current + local id = thebox.id + if id == hlist_code then + thebox = validvbox(id,thebox.list) + id = thebox and thebox.id + end + if thebox and id == vlist_code then + local list, lh, ld = thebox.list + for n in traverse_nodes_id(hlist_code,list) do lh, ld = n.height, n.depth end if lh then - local baseline_till_top = h + d - ld - local x = max(ceil((baseline_till_top-hr*snapht)/snaphtdp),0)*snaphtdp + plusht - local n = make_kern_node(x-baseline_till_top) - n.next, list.prev, current.list = list, n, n - ch = x - cd = max(ceil((ld-dr*snapdp)/snaphtdp),0)*snaphtdp + plusdp + local ht, dp = thebox.height, thebox.depth + if t then + t[#t+1] = format("last line: height %s depth %s",points(lh),points(ld)) + t[#t+1] = format("dimensions: height %s depth %s",points(ht),points(dp)) + end + local delta = d - ld + cd, ch = ld, delta + h +--~ ch = ch + plusht +--~ cd = cd + plusdp +h, d = ch, cd + local shifted = hpack_node(current.list) + shifted.shift = delta + current.list = shifted done = true + if t then + t[#t+1] = format("last: height %s depth %s shift %s",points(ch),points(cd),points(delta)) + end + elseif t then + t[#t+1] = "last: not done, no content" end + elseif t then + t[#t+1] = "last: not done, no vbox" end end - if done then - -- first or last - elseif method.minheight then - ch = max(floor((h-hr*snapht)/snaphtdp),0)*snaphtdp + plusht +--~ if done then +--~ -- first or last +--~ else + if method.minheight then + -- ch = max(floor((h-hr*snapht)/snaphtdp),0)*snaphtdp + plusht + ch = floored((h-hr*snapht)/snaphtdp)*snaphtdp + plusht + if t then + t[#t+1] = format("minheight: %s",points(ch)) + end elseif method.maxheight then - ch = max(ceil((h-hr*snapht)/snaphtdp),0)*snaphtdp + plusht + -- ch = max(ceil((h-hr*snapht)/snaphtdp),0)*snaphtdp + plusht + ch = ceiled((h-hr*snapht)/snaphtdp)*snaphtdp + plusht + if t then + t[#t+1] = format("maxheight: %s",points(ch)) + end else ch = plusht + if t then + t[#t+1] = format("set height: %s",points(ch)) + end end - if done then - -- first or last - elseif method.mindepth then - cd = max(floor((d-dr*snapdp)/snaphtdp),0)*snaphtdp + plusdp +--~ if done then +--~ -- first or last +--~ else + if method.mindepth then + -- cd = max(floor((d-dr*snapdp)/snaphtdp),0)*snaphtdp + plusdp + cd = floored((d-dr*snapdp)/snaphtdp)*snaphtdp + plusdp + if t then + t[#t+1] = format("mindepth: %s",points(cd)) + end elseif method.maxdepth then - cd = max(ceil((d-dr*snapdp)/snaphtdp),0)*snaphtdp + plusdp + -- cd = max(ceil((d-dr*snapdp)/snaphtdp),0)*snaphtdp + plusdp + cd = ceiled((d-dr*snapdp)/snaphtdp)*snaphtdp + plusdp + if t then + t[#t+1] = format("maxdepth: %s",points(cd)) + end else cd = plusdp + if t then + t[#t+1] = format("set depth: %s",points(cd)) + end end if method.top then ch = ch + tlines * snaphtdp + if t then + t[#t+1] = format("top height: %s",points(ch)) + end end if method.bottom then cd = cd + blines * snaphtdp + if t then + t[#t+1] = format("bottom depth: %s",points(cd)) + end end local offset = method.offset if offset then -- we need to set the attr - local shifted = vpack_node(current.list) + if t then + t[#t+1] = format("before offset: %s (width %s height %s depth %s)", + points(offset),points(current.width),points(current.height),points(current.depth)) + end + local shifted = hpack_node(current.list) shifted.shift = offset current.list = shifted + if t then + t[#t+1] = format("after offset: %s (width %s height %s depth %s)", + points(offset),points(current.width),points(current.height),points(current.depth)) + end + set_attribute(shifted,a_snapmethod,0) + set_attribute(current,a_snapmethod,0) end if not height then current.height = ch + if t then + t[#t+1] = format("forced height: %s",points(ch)) + end end if not depth then current.depth = cd + if t then + t[#t+1] = format("forced depth: %s",points(cd)) + end + end + local lines = (ch+cd)/snaphtdp + if t then + local original = (h+d)/snaphtdp + t[#t+1] = format("final lines: %s -> %s",original,lines) + t[#t+1] = format("final height: %s -> %s",points(h),points(ch)) + t[#t+1] = format("final depth: %s -> %s",points(d),points(cd)) + end + if t then + report_snapper("trace: %s type %s\n\t%s",where,nodecodes[current.id],concat(t,"\n\t")) end - -- set_attribute(current,snap_method,0) - return h, d, ch, cd, (ch+cd)/snaphtdp + return h, d, ch, cd, lines end ---~ local function snap_topskip(current,method) ---~ local spec = current.spec ---~ local w = spec.width ---~ local wd = w ---~ if spec then ---~ wd = 0 ---~ spec = writable_spec(current) ---~ spec.width = wd ---~ end ---~ return w, wd ---~ end - local function snap_topskip(current,method) local spec = current.spec local w = spec.width @@ -293,7 +507,7 @@ local function snap_topskip(current,method) return w, wd end -vspacing.categories = { +local categories = allocate { [0] = 'discard', [1] = 'largest', [2] = 'force' , @@ -305,7 +519,7 @@ vspacing.categories = { [8] = 'together' } -local categories = vspacing.categories +vspacing.categories = categories function vspacing.tocategories(str) local t = { } @@ -328,73 +542,68 @@ function vspacing.tocategory(str) end end -vspacing.data.map = vspacing.data.map or { } -vspacing.data.skip = vspacing.data.skip or { } +vspacing.data.map = vspacing.data.map or { } -- allocate ? +vspacing.data.skip = vspacing.data.skip or { } -- allocate ? -storage.register("vspacing/data/map", vspacing.data.map, "vspacing.data.map") -storage.register("vspacing/data/skip", vspacing.data.skip, "vspacing.data.skip") +storage.register("builders/vspacing/data/map", vspacing.data.map, "builders.vspacing.data.map") +storage.register("builders/vspacing/data/skip", vspacing.data.skip, "builders.vspacing.data.skip") do -- todo: interface.variables - local function logger(c,...) - logs.report("vspacing",concat {...}) - texsprint(c,...) - end - vspacing.fixed = false local map = vspacing.data.map local skip = vspacing.data.skip - local multiplier = lpeg.C(lpeg.S("+-")^0 * lpeg.R("09")^1) * lpeg.P("*") - local category = lpeg.P(":") * lpeg.C(lpeg.P(1)^1) - local keyword = lpeg.C((1-category)^1) - local splitter = (multiplier + lpeg.Cc(1)) * keyword * (category + lpeg.Cc(false)) + local multiplier = C(S("+-")^0 * R("09")^1) * P("*") + local category = P(":") * C(P(1)^1) + local keyword = C((1-category)^1) + local splitter = (multiplier + Cc(1)) * keyword * (category + Cc(false)) local k_fixed, k_flexible, k_category, k_penalty, k_order = variables.fixed, variables.flexible, "category", "penalty", "order" -- This will change: just node.write and we can store the values in skips which -- then obeys grouping - local function analyse(str,oldcategory,texsprint) -- we could use shorter names + local function analyze(str,oldcategory) -- we could use shorter names for s in gmatch(str,"([^ ,]+)") do local amount, keyword, detail = lpegmatch(splitter,s) if not keyword then - logs.report("vspacing","unknown directive: %s",s) + report_vspacing("unknown directive: %s",s) else local mk = map[keyword] if mk then - category = analyse(mk,category,texsprint) + category = analyze(mk,category) elseif keyword == k_fixed then - texsprint(ctxcatcodes,"\\fixedblankskip") + context.fixedblankskip() elseif keyword == k_flexible then - texsprint(ctxcatcodes,"\\flexibleblankskip") + context.flexibleblankskip() elseif keyword == k_category then local category = tonumber(detail) if category then - texsprint(ctxcatcodes,"\\setblankcategory{",category,"}") + context.setblankcategory(category) if category ~= oldcategory then - texsprint(ctxcatcodes,"\\flushblankhandling") + context.flushblankhandling() oldcategory = category end end elseif keyword == k_order and detail then local order = tonumber(detail) if order then - texsprint(ctxcatcodes,"\\setblankorder{",order,"}") + context.setblankorder(order) end elseif keyword == k_penalty and detail then local penalty = tonumber(detail) if penalty then - texsprint(ctxcatcodes,"\\setblankpenalty{",penalty,"}") + context.setblankpenalty(penalty) end else amount = tonumber(amount) or 1 local sk = skip[keyword] if sk then - texsprint(ctxcatcodes,"\\addpredefinedblankskip{",amount,"}{",keyword,"}") + context.addpredefinedblankskip(amount,keyword) else -- no check - texsprint(ctxcatcodes,"\\addaskedblankskip{",amount,"}{",keyword,"}") + context.addaskedblankskip(amount,keyword) end end end @@ -402,11 +611,16 @@ do -- todo: interface.variables return category end - function vspacing.analyse(str) - local texsprint = (trace_vspacing and logger) or texsprint - texsprint(ctxcatcodes,"\\startblankhandling") - analyse(str,1,texsprint) - texsprint(ctxcatcodes,"\\stopblankhandling") + function vspacing.analyze(str) + if trace_vspacing then + context.pushlogger(report_vspacing) + end + context.startblankhandling() + analyze(str,1) + context.stopblankhandling() + if trace_vspacing then + context.poplogger() + end end -- @@ -434,19 +648,20 @@ end local trace_list, tracing_info, before, after = { }, false, "", "" +local stripzeros, topoints = utilities.formatters.stripzeros, number.topoints + local function glue_to_string(glue) local spec = glue.spec - local t = { } - t[#t+1] = aux.strip_zeros(number.topoints(spec.width)) + local t = { points(spec.width) } if spec.stretch_order and spec.stretch_order ~= 0 then - t[#t+1] = format("plus -%sfi%s",spec.stretch/65536,string.rep("l",math.abs(spec.stretch_order)-1)) + t[#t+1] = format("plus %s%s",spec.stretch/65536,fillcodes[spec.stretch_order]) elseif spec.stretch and spec.stretch ~= 0 then - t[#t+1] = format("plus %s",aux.strip_zeros(number.topoints(spec.stretch))) + t[#t+1] = format("plus %s",stripzeros(topoints(spec.stretch))) end if spec.shrink_order and spec.shrink_order ~= 0 then - t[#t+1] = format("minus -%sfi%s",spec.shrink/65536,string.rep("l",math.abs(spec.shrink_order)-1)) + t[#t+1] = format("minus %s%s",spec.shrink/65536,fillcodes[spec.shrink_order]) elseif spec.shrink and spec.shrink ~= 0 then - t[#t+1] = format("minus %s",aux.strip_zeros(number.topoints(spec.shrink))) + t[#t+1] = format("minus %s",stripzeros(topoints(spec.shrink))) end return concat(t," ") end @@ -455,13 +670,13 @@ local function nodes_to_string(head) local current, t = head, { } while current do local id = current.id - local ty = node.type(id) - if id == penalty then + local ty = nodecodes[id] + if id == penalty_code then t[#t+1] = format("%s:%s",ty,current.penalty) - elseif id == glue then - t[#t+1] = format("%s:%s",ty,aux.strip_zeros(number.topoints(current.spec.width))) - elseif id == kern then - t[#t+1] = format("%s:%s",ty,aux.strip_zeros(number.topoints(current.kern))) + elseif id == glue_code then + t[#t+1] = format("%s:%s",ty,stripzeros(topoints(current.spec.width))) + elseif id == kern_code then + t[#t+1] = format("%s:%s",ty,stripzeros(topoints(current.kern))) else t[#t+1] = ty end @@ -489,7 +704,7 @@ local function trace_info(message, where, what) end local function trace_node(what) - local nt = node.type(what.id) + local nt = nodecodes[what.id] local tl = trace_list[#trace_list] if tl and tl[1] == "node" then trace_list[#trace_list] = { "node", tl[2] .. " + " .. nt } @@ -499,7 +714,7 @@ local function trace_node(what) end local function trace_done(str,data) - if data.id == penalty then + if data.id == penalty_code then trace_list[#trace_list+1] = { "penalty", format("%s | %s", str, data.penalty) } else trace_list[#trace_list+1] = { "glue", format("%s | %s", str, glue_to_string(data)) } @@ -513,84 +728,72 @@ local function show_tracing(head) for i=1,#trace_list do local tag, text = unpack(trace_list[i]) if tag == "info" then - logs.report("collapse",text) + report_collapser(text) else - logs.report("collapse"," %s: %s",tag,text) + report_collapser(" %s: %s",tag,text) end end - logs.report("collapse","before: %s",before) - logs.report("collapse","after : %s",after) + report_collapser("before: %s",before) + report_collapser("after : %s",after) end end -- alignment box begin_of_par vmode_par hmode_par insert penalty before_display after_display -local user_skip = 0 -local line_skip = 1 -local baseline_skip = 2 -local par_skip = 3 -local above_display_skip = 4 -local below_display_skip = 5 -local above_display_short_skip = 6 -local below_display_short_skip = 7 -local left_skip_code = 8 -local right_skip_code = 9 -local top_skip_code = 10 -local split_top_skip_code = 11 -local tab_skip_code = 12 -local space_skip_code = 13 -local xspace_skip_code = 14 -local par_fill_skip_code = 15 -local thin_mu_skip_code = 16 -local med_mu_skip_code = 17 -local thick_mu_skip_code = 18 - -local skips = { - [ 0] = "user_skip", - [ 1] = "line_skip", - [ 2] = "baseline_skip", - [ 3] = "par_skip", - [ 4] = "above_display_skip", - [ 5] = "below_display_skip", - [ 6] = "above_display_short_skip", - [ 7] = "below_display_short_skip", - [ 8] = "left_skip_code", - [ 9] = "right_skip_code", - [10] = "top_skip_code", - [11] = "split_top_skip_code", - [12] = "tab_skip_code", - [13] = "space_skip_code", - [14] = "xspace_skip_code", - [15] = "par_fill_skip_code", - [16] = "thin_mu_skip_code", - [17] = "med_mu_skip_code", - [18] = "thick_mu_skip_code", -} +local skipcodes = nodes.skipcodes + +local userskip_code = skipcodes.userskip +local lineskip_code = skipcodes.lineskip +local baselineskip_code = skipcodes.baselineskip +local parskip_code = skipcodes.parskip +local abovedisplayskip_code = skipcodes.abovedisplayskip +local belowdisplayskip_code = skipcodes.belowdisplayskip +local abovedisplayshortskip_code = skipcodes.abovedisplayshortskip +local belowdisplayshortskip_code = skipcodes.belowdisplayshortskip +local topskip_code = skipcodes.topskip +local splittopskip_code = skipcodes.splittopskip local free_glue_node = free_node local discard, largest, force, penalty, add, disable, nowhite, goback, together = 0, 1, 2, 3, 4, 5, 6, 7, 8 ---~ local function free_glue_node(n) free_node(n.spec) free_node(n) end +--~ local function free_glue_node(n) +--~ -- free_node(n.spec) +--~ print("before",n) +--~ logs.flush() +--~ free_node(n) +--~ print("after") +--~ logs.flush() +--~ end -function vspacing.snap_box(n,how) +function vspacing.snapbox(n,how) local sv = snapmethods[how] if sv then local box = texbox[n] local list = box.list ---~ if list and (list.id == hlist or list.id == vlist) then if list then - local s = has_attribute(list,snap_method) + local s = has_attribute(list,a_snapmethod) if s == 0 then if trace_vsnapping then - -- logs.report("snapper", "hlist not snapped, already done") + -- report_snapper("box list not snapped, already done") end else - local h, d, ch, cd, lines = snap_hlist(box,sv,box.height,box.depth) - box.height, box.depth = ch, cd - if trace_vsnapping then - logs.report("snapper", "hlist snapped from (%s,%s) to (%s,%s) using method '%s' (%s) for '%s' (%s lines)",h,d,ch,cd,sv.name,sv.specification,"direct",lines) + local ht, dp = box.height, box.depth + if false then -- todo: already_done + -- assume that the box is already snapped + if trace_vsnapping then + report_snapper("box list already snapped at (%s,%s): %s", + ht,dp,listtoutf(list)) + end + else + local h, d, ch, cd, lines = snap_hlist("box",box,sv,ht,dp) + box.height, box.depth = ch, cd + if trace_vsnapping then + report_snapper("box list snapped from (%s,%s) to (%s,%s) using method '%s' (%s) for '%s' (%s lines): %s", + h,d,ch,cd,sv.name,sv.specification,"direct",lines,listtoutf(list)) + end + set_attribute(box, a_snapmethod,0) -- + set_attribute(list,a_snapmethod,0) -- yes or no end - set_attribute(list,snap_method,0) end end end @@ -598,23 +801,23 @@ end local function forced_skip(head,current,width,where,trace) if where == "after" then - head, current = insert_node_after(head,current,make_rule_node(0,0,0)) - head, current = insert_node_after(head,current,make_kern_node(width)) - head, current = insert_node_after(head,current,make_rule_node(0,0,0)) + head, current = insert_node_after(head,current,new_rule(0,0,0)) + head, current = insert_node_after(head,current,new_kern(width)) + head, current = insert_node_after(head,current,new_rule(0,0,0)) else local c = current - head, current = insert_node_before(head,current,make_rule_node(0,0,0)) - head, current = insert_node_before(head,current,make_kern_node(width)) - head, current = insert_node_before(head,current,make_rule_node(0,0,0)) + head, current = insert_node_before(head,current,new_rule(0,0,0)) + head, current = insert_node_before(head,current,new_kern(width)) + head, current = insert_node_before(head,current,new_rule(0,0,0)) current = c end if trace then - logs.report("vspacing", "inserting forced skip of %s",width) + report_vspacing("inserting forced skip of %s",width) end return head, current end -local function collapser(head,where,what,trace,snap) -- maybe also pass tail +local function collapser(head,where,what,trace,snap,a_snapmethod) -- maybe also pass tail if trace then reset_tracing(head) end @@ -627,18 +830,18 @@ local function collapser(head,where,what,trace,snap) -- maybe also pass tail -- local function flush(why) if penalty_data then - local p = make_penalty_node(penalty_data) + local p = new_penalty(penalty_data) if trace then trace_done("flushed due to " .. why,p) end - head, _ = insert_node_before(head,current,p) + head = insert_node_before(head,current,p) end if glue_data then if force_glue then if trace then trace_done("flushed due to " .. why,glue_data) end - head, _ = forced_skip(head,current,glue_data.spec.width,"before",trace) + head = forced_skip(head,current,glue_data.spec.width,"before",trace) free_glue_node(glue_data) elseif glue_data.spec.writable then if trace then trace_done("flushed due to " .. why,glue_data) end - head, _ = insert_node_before(head,current,glue_data) + head = insert_node_before(head,current,glue_data) else free_glue_node(glue_data) end @@ -649,36 +852,47 @@ local function collapser(head,where,what,trace,snap) -- maybe also pass tail parskip, ignore_parskip, ignore_following, ignore_whitespace = nil, false, false, false end if trace_vsnapping then - logs.report("snapper", "global ht/dp = %s/%s, local ht/dp = %s/%s", + report_snapper("global ht/dp = %s/%s, local ht/dp = %s/%s", texdimen.globalbodyfontstrutheight, texdimen.globalbodyfontstrutdepth, texdimen.bodyfontstrutheight, texdimen.bodyfontstrutdepth) end if trace then trace_info("start analyzing",where,what) end while current do local id, subtype = current.id, current.subtype - if id == hlist or id == vlist then --- needs checking, why so many calls + if id == hlist_code or id == vlist_code then + -- needs checking, why so many calls if snap then - local s = has_attribute(current,snap_method) + local list = current.list + local s = has_attribute(current,a_snapmethod) if not s then -- if trace_vsnapping then - -- logs.report("snapper", "hlist not snapped") + -- report_snapper("mvl list not snapped") -- end elseif s == 0 then if trace_vsnapping then - -- logs.report("snapper", "hlist not snapped, already done") + report_snapper("mvl %s not snapped, already done: %s",nodecodes[id],listtoutf(list)) end else local sv = snapmethods[s] if sv then - local h, d, ch, cd, lines = snap_hlist(current,sv) - if trace_vsnapping then - logs.report("snapper", "hlist snapped from (%s,%s) to (%s,%s) using method '%s' (%s) for '%s' (%s lines)",h,d,ch,cd,sv.name,sv.specification,where,lines) + -- check if already snapped + if list and already_done(id,list,a_snapmethod) then + local ht, dp = current.height, current.depth + -- assume that the box is already snapped + if trace_vsnapping then + report_snapper("mvl list already snapped at (%s,%s): %s",ht,dp,listtoutf(list)) + end + else + local h, d, ch, cd, lines = snap_hlist("mvl",current,sv) + if trace_vsnapping then + report_snapper("mvl %s snapped from (%s,%s) to (%s,%s) using method '%s' (%s) for '%s' (%s lines): %s", + nodecodes[id],h,d,ch,cd,sv.name,sv.specification,where,lines,listtoutf(list)) + end end elseif trace_vsnapping then - logs.report("snapper", "hlist not snapped due to unknown snap specification") + report_snapper("mvl %s not snapped due to unknown snap specification: %s",nodecodes[id],listtoutf(list)) end - set_attribute(current,snap_method,0) + set_attribute(current,a_snapmethod,0) end else -- @@ -686,25 +900,25 @@ local function collapser(head,where,what,trace,snap) -- maybe also pass tail -- tex.prevdepth = 0 flush("list") current = current.next - elseif id == penalty then + elseif id == penalty_code then --~ natural_penalty = current.penalty --~ if trace then trace_done("removed penalty",current) end --~ head, current = remove_node(head, current, true) current = current.next - elseif id == kern then + elseif id == kern_code then if snap and trace_vsnapping and current.kern ~= 0 then --~ current.kern = 0 - logs.report("snapper", "kern of %s (kept)",current.kern) + report_snapper("kern of %s (kept)",current.kern) end flush("kern") current = current.next - elseif id ~= glue then + elseif id ~= glue_code then flush("something else") current = current.next - elseif subtype == user_skip then -- todo, other subtypes, like math - local sc = has_attribute(current,skip_category) -- has no default, no unset (yet) - local so = has_attribute(current,skip_order ) or 1 -- has 1 default, no unset (yet) - local sp = has_attribute(current,skip_penalty ) -- has no default, no unset (yet) + elseif subtype == userskip_code then + local sc = has_attribute(current,a_skipcategory) -- has no default, no unset (yet) + local so = has_attribute(current,a_skiporder ) or 1 -- has 1 default, no unset (yet) + local sp = has_attribute(current,a_skippenalty ) -- has no default, no unset (yet) if sp and sc == penalty then if not penalty_data then penalty_data = sp @@ -718,21 +932,22 @@ local function collapser(head,where,what,trace,snap) -- maybe also pass tail elseif not sc then -- if not sc then if glue_data then if trace then trace_done("flush",glue_data) end - head, current = nodes.before(head,current,glue_data) + head = insert_node_before(head,current,glue_data) if trace then trace_natural("natural",current) end current = current.next else -- not look back across head local previous = current.prev - if previous and previous.id == glue and previous.subtype == 0 then + if previous and previous.id == glue_code and previous.subtype == userskip_code then local ps = previous.spec if ps.writable then local cs = current.spec if cs.writable and ps.stretch_order == 0 and ps.shrink_order == 0 and cs.stretch_order == 0 and cs.shrink_order == 0 then local pw, pp, pm = ps.width, ps.stretch, ps.shrink local cw, cp, cm = cs.width, cs.stretch, cs.shrink - ps = writable_spec(previous) -- no writable needed here - ps.width, ps.stretch, ps.shrink = pw + cw, pp + cp, pm + cm +--~ ps = writable_spec(previous) -- no writable needed here +--~ ps.width, ps.stretch, ps.shrink = pw + cw, pp + cp, pm + cm +previous.spec = new_gluespec(pw + cw, pp + cp, pm + cm) -- else topskip can disappear if trace then trace_natural("removed",current) end head, current = remove_node(head, current, true) -- current = previous @@ -809,7 +1024,7 @@ local function collapser(head,where,what,trace,snap) -- maybe also pass tail head, current = remove_node(head, current, true) elseif sc == add then if trace then trace_skip('add',sc,so,sp,current) end ---~ local old, new = glue_data.spec, current.spec + -- local old, new = glue_data.spec, current.spec local old, new = writable_spec(glue_data), current.spec old.width = old.width + new.width old.stretch = old.stretch + new.stretch @@ -827,16 +1042,16 @@ local function collapser(head,where,what,trace,snap) -- maybe also pass tail if sc == force then force_glue = true end - elseif subtype == line_skip then + elseif subtype == lineskip_code then if snap then - local s = has_attribute(current,snap_method) + local s = has_attribute(current,a_snapmethod) if s and s ~= 0 then - set_attribute(current,snap_method,0) + set_attribute(current,a_snapmethod,0) if current.spec.writable then local spec = writable_spec(current) spec.width = 0 if trace_vsnapping then - logs.report("snapper", "lineskip set to zero") + report_snapper("lineskip set to zero") end end else @@ -848,16 +1063,16 @@ local function collapser(head,where,what,trace,snap) -- maybe also pass tail flush("lineskip") end current = current.next - elseif subtype == baseline_skip then + elseif subtype == baselineskip_code then if snap then - local s = has_attribute(current,snap_method) + local s = has_attribute(current,a_snapmethod) if s and s ~= 0 then - set_attribute(current,snap_method,0) + set_attribute(current,a_snapmethod,0) if current.spec.writable then local spec = writable_spec(current) spec.width = 0 if trace_vsnapping then - logs.report("snapper", "baselineskip set to zero") + report_snapper("baselineskip set to zero") end end else @@ -869,7 +1084,7 @@ local function collapser(head,where,what,trace,snap) -- maybe also pass tail flush("baselineskip") end current = current.next - elseif subtype == par_skip then + elseif subtype == parskip_code then -- parskip always comes later if ignore_whitespace then if trace then trace_natural("ignored parskip",current) end @@ -887,15 +1102,15 @@ local function collapser(head,where,what,trace,snap) -- maybe also pass tail if trace then trace_natural("honored parskip",current) end head, current, glue_data = remove_node(head, current) end - elseif subtype == top_skip_code or subtype == split_top_skip_code then + elseif subtype == topskip_code or subtype == splittopskip_code then if snap then - local s = has_attribute(current,snap_method) + local s = has_attribute(current,a_snapmethod) if s and s ~= 0 then - set_attribute(current,snap_method,0) + set_attribute(current,a_snapmethod,0) local sv = snapmethods[s] local w, cw = snap_topskip(current,sv) if trace_vsnapping then - logs.report("snapper", "topskip snapped from %s to %s for '%s'",w,cw,where) + report_snapper("topskip snapped from %s to %s for '%s'",w,cw,where) end else if trace then trace_skip("topskip",sc,so,sp,current) end @@ -906,25 +1121,25 @@ local function collapser(head,where,what,trace,snap) -- maybe also pass tail flush("topskip") end current = current.next - elseif subtype == above_display_skip then + elseif subtype == abovedisplayskip_code then -- if trace then trace_skip("above display skip (normal)",sc,so,sp,current) end flush("above display skip (normal)") current = current.next -- - elseif subtype == below_display_skip then + elseif subtype == belowdisplayskip_code then -- if trace then trace_skip("below display skip (normal)",sc,so,sp,current) end flush("below display skip (normal)") current = current.next -- - elseif subtype == above_display_short_skip then + elseif subtype == abovedisplayshortskip_code then -- if trace then trace_skip("above display skip (short)",sc,so,sp,current) end flush("above display skip (short)") current = current.next -- - elseif subtype == below_display_short_skip then + elseif subtype == belowdisplayshortskip_code then -- if trace then trace_skip("below display skip (short)",sc,so,sp,current) end flush("below display skip (short)") @@ -932,7 +1147,7 @@ local function collapser(head,where,what,trace,snap) -- maybe also pass tail -- else -- other glue if snap and trace_vsnapping and current.spec.writable and current.spec.width ~= 0 then - logs.report("snapper", "%s of %s (kept)",skips[subtype],current.spec.width) + report_snapper("%s of %s (kept)",skipcodes[subtype],current.spec.width) --~ current.spec.width = 0 end if trace then trace_skip(format("some glue (%s)",subtype),sc,so,sp,current) end @@ -950,7 +1165,7 @@ local function collapser(head,where,what,trace,snap) -- maybe also pass tail local tail if penalty_data then tail = find_node_tail(head) - local p = make_penalty_node(penalty_data) + local p = new_penalty(penalty_data) if trace then trace_done("result",p) end head, tail = insert_node_after(head,tail,p) end @@ -970,7 +1185,7 @@ local function collapser(head,where,what,trace,snap) -- maybe also pass tail end show_tracing(head) if oldhead ~= head then - trace_info("head has been changed from '%s' to '%s'",node.type(oldhead.id),node.type(head.id)) + trace_info("head has been changed from '%s' to '%s'",nodecodes[oldhead.id],nodecodes[head.id]) end end return head, true @@ -989,21 +1204,21 @@ end local stackhead, stacktail, stackhack = nil, nil, false local function report(message,lst) - logs.report("vspacing",message,count_nodes(lst,true),node_ids_to_string(lst)) + report_vspacing(message,count_nodes(lst,true),nodeidstostring(lst)) end -function nodes.handle_page_spacing(newhead,where) ---~ local newhead = texlists.contrib_head +function vspacing.pagehandler(newhead,where) + -- local newhead = texlists.contrib_head if newhead then ---~ starttiming(vspacing) + -- starttiming(vspacing) local newtail = find_node_tail(newhead) local flush = false stackhack = true -- todo: only when grid snapping once enabled for n in traverse_nodes(newhead) do -- we could just look for glue nodes local id = n.id - if id == glue then - if n.subtype == 0 then - if has_attribute(n,skip_category) then + if id == glue_code then + if n.subtype == userskip_code then + if has_attribute(n,a_skipcategory) then stackhack = true else flush = true @@ -1026,8 +1241,8 @@ function nodes.handle_page_spacing(newhead,where) if stackhack then stackhack = false if trace_collect_vspacing then report("processing %s nodes: %s",newhead) end ---~ texlists.contrib_head = collapser(newhead,"page",where,trace_page_vspacing,true) -newhead = collapser(newhead,"page",where,trace_page_vspacing,true) +--~ texlists.contrib_head = collapser(newhead,"page",where,trace_page_vspacing,true,a_snapmethod) + newhead = collapser(newhead,"page",where,trace_page_vspacing,true,a_snapmethod) else if trace_collect_vspacing then report("flushing %s nodes: %s",newhead) end --~ texlists.contrib_head = newhead @@ -1042,12 +1257,12 @@ newhead = collapser(newhead,"page",where,trace_page_vspacing,true) stackhead = newhead end stacktail = newtail ---~ texlists.contrib_head = nil -newhead = nil + -- texlists.contrib_head = nil + newhead = nil end ---~ stoptiming(vspacing) + -- stoptiming(vspacing) end -return newhead + return newhead end local ignore = table.tohash { @@ -1056,102 +1271,44 @@ local ignore = table.tohash { -- "vbox", } -function nodes.handle_vbox_spacing(head,where) +function vspacing.vboxhandler(head,where) if head and not ignore[where] and head.next then -- starttiming(vspacing) - head = collapser(head,"vbox",where,trace_vbox_vspacing,false) + head = collapser(head,"vbox",where,trace_vbox_vspacing,true,a_snapvbox) -- todo: local snapper -- stoptiming(vspacing) end return head end -function nodes.collapse_vbox(n) -- for boxes +function vspacing.collapsevbox(n) -- for boxes but using global a_snapmethod local list = texbox[n].list if list then -- starttiming(vspacing) - texbox[n].list = vpack_node(collapser(list,"snapper","vbox",trace_vbox_vspacing,true)) + texbox[n].list = vpack_node(collapser(list,"snapper","vbox",trace_vbox_vspacing,true,a_snapmethod)) -- stoptiming(vspacing) end end --- we will split this module hence the locals - -local attribute = attributes.private('graphicvadjust') - -local hlist = node.id('hlist') -local vlist = node.id('vlist') - -local remove_node = nodes.remove -local hpack_node = node.hpack -local vpack_node = node.vpack -local has_attribute = node.has_attribute - -function nodes.repackage_graphicvadjust(head,groupcode) -- we can make an actionchain for mvl only - if groupcode == "" then -- mvl only - local h, p, done = head, nil, false - while h do - local id = h.id - if id == hlist or id == vlist then - local a = has_attribute(h,attribute) - if a then - if p then - local n - head, h, n = remove_node(head,h) - local pl = p.list - if n.width ~= 0 then - n = hpack_node(n,0,'exactly') -- todo: dir - end - if pl then - pl.prev = n - n.next = pl - end - p.list = n - done = true - else - -- can't happen - end - else - p = h - h = h.next - end - else - h = h.next - end - end - return head, done - else - return head, false - end -end - ---~ function nodes.repackage_graphicvadjust(head,groupcode) -- we can make an actionchain for mvl only ---~ if groupcode == "" then -- mvl only ---~ return head, false ---~ else ---~ return head, false ---~ end ---~ end - ---~ tasks.appendaction("finalizers", "lists", "nodes.repackage_graphicvadjust") +-- We will split this module so a few locals are repeated. Also this will be +-- rewritten. nodes.builders = nodes.builder or { } - local builders = nodes.builders -local actions = tasks.actions("vboxbuilders",5) +local actions = nodes.tasks.actions("vboxbuilders") function nodes.builders.vpack_filter(head,groupcode,size,packtype,maxdepth,direction) local done = false if head then starttiming(builders) - if trace_callbacks then + if trace_vpacking then local before = nodes.count(head) head, done = actions(head,groupcode,size,packtype,maxdepth,direction) local after = nodes.count(head) if done then - tracer("vpack","changed",head,groupcode,before,after,true) + nodes.processors.tracer("vpack","changed",head,groupcode,before,after,true) else - tracer("vpack","unchanged",head,groupcode,before,after,true) + nodes.processors.tracer("vpack","unchanged",head,groupcode,before,after,true) end stoptiming(builders) else @@ -1166,7 +1323,7 @@ end -- and we operate on the mlv. Also, we need to do the -- vspacing last as it removes items from the mvl. -local actions = tasks.actions("mvlbuilders",1) +local actions = nodes.tasks.actions("mvlbuilders") function nodes.builders.buildpage_filter(groupcode) starttiming(builders) @@ -1177,7 +1334,7 @@ function nodes.builders.buildpage_filter(groupcode) return (done and head) or true end -callbacks.register('vpack_filter', nodes.builders.vpack_filter, "vertical spacing etc") +callbacks.register('vpack_filter', nodes.builders.vpack_filter, "vertical spacing etc") callbacks.register('buildpage_filter', nodes.builders.buildpage_filter, "vertical spacing etc (mvl)") statistics.register("v-node processing time", function() |