From c30a841cef093918b475e0ea95ecf9fc9f30697d Mon Sep 17 00:00:00 2001 From: Marius Date: Tue, 17 Jul 2012 13:16:14 +0300 Subject: beta 2012.07.17 00:23 --- tex/context/base/buff-ver.mkiv | 2 +- tex/context/base/char-ini.lua | 31 +- tex/context/base/chem-str.mkiv | 25 +- tex/context/base/cont-new.mkii | 2 +- tex/context/base/cont-new.mkiv | 4 +- tex/context/base/context-version.pdf | Bin 4141 -> 4083 bytes tex/context/base/context-version.png | Bin 106433 -> 106557 bytes tex/context/base/context.mkii | 2 +- tex/context/base/context.mkiv | 9 +- tex/context/base/font-sol.lua | 283 ++- tex/context/base/grph-inc.mkiv | 28 +- tex/context/base/grph-trf.mkiv | 4 +- tex/context/base/luat-sto.lua | 3 +- tex/context/base/m-visual.mkiv | 3 +- tex/context/base/mult-def.mkiv | 1 + tex/context/base/mult-low.lua | 7 + tex/context/base/mult-sys.mkiv | 3 + tex/context/base/node-res.lua | 12 +- tex/context/base/pack-rul.mkiv | 2 +- tex/context/base/page-brk.mkiv | 14 +- tex/context/base/page-col.mkiv | 174 +- tex/context/base/page-flt.mkiv | 17 +- tex/context/base/page-ins.lua | 65 + tex/context/base/page-ins.mkiv | 175 +- tex/context/base/page-mix.lua | 629 ++++++ tex/context/base/page-mix.mkiv | 754 +++++++ tex/context/base/page-mul.mkiv | 2209 ++++++++++---------- tex/context/base/page-not.mkiv | 10 +- tex/context/base/page-one.mkiv | 56 +- tex/context/base/page-otr.mkvi | 4 +- tex/context/base/page-pst.mkiv | 4 +- tex/context/base/page-set.mkiv | 87 +- tex/context/base/page-sid.mkiv | 5 +- tex/context/base/s-art-01.mkiv | 4 + tex/context/base/spac-ver.mkiv | 10 +- tex/context/base/status-files.pdf | Bin 24464 -> 24333 bytes tex/context/base/status-lua.pdf | Bin 182732 -> 184231 bytes tex/context/base/status-mkiv.lua | 23 +- tex/context/base/strc-itm.mkvi | 36 +- tex/context/base/strc-not.mkvi | 95 +- tex/context/base/strc-reg.lua | 11 +- tex/context/base/strc-reg.mkiv | 10 +- tex/context/base/syst-aux.mkiv | 14 +- tex/context/base/trac-ctx.lua | 36 + tex/context/base/trac-ctx.mkiv | 28 + tex/context/base/typo-txt.mkvi | 8 +- tex/context/fonts/demo.lfg | 29 +- tex/generic/context/luatex/luatex-fonts-merged.lua | 2 +- 48 files changed, 3389 insertions(+), 1541 deletions(-) create mode 100644 tex/context/base/page-ins.lua create mode 100644 tex/context/base/page-mix.lua create mode 100644 tex/context/base/page-mix.mkiv create mode 100644 tex/context/base/trac-ctx.lua create mode 100644 tex/context/base/trac-ctx.mkiv (limited to 'tex') diff --git a/tex/context/base/buff-ver.mkiv b/tex/context/base/buff-ver.mkiv index d1385ebd2..5ba0487e9 100644 --- a/tex/context/base/buff-ver.mkiv +++ b/tex/context/base/buff-ver.mkiv @@ -366,7 +366,7 @@ \let\inlinemathmarker \textdollar \def\displaymathmarker{\textdollar\textdollar} -\def\buff_verbatim_special_type#1#2% +\def\buff_verbatim_special_type#1#2#% # gobbles spaces {\dontleavehmode\bgroup \buff_verbatim_initialize_type_one \catcode\leftbraceasciicode \begingroupcatcode diff --git a/tex/context/base/char-ini.lua b/tex/context/base/char-ini.lua index 244b8d2a7..90e36bc7b 100644 --- a/tex/context/base/char-ini.lua +++ b/tex/context/base/char-ini.lua @@ -455,28 +455,37 @@ table we derive a few more.

if not characters.fallbacks then - -- we could the definition by using a metatable + characters.fallbacks = { } -- not than many - characters.fallbacks = { } - characters.directions = { } + local fallbacks = characters.fallbacks - local fallbacks = characters.fallbacks - local directions = characters.directions - - for k,v in next, data do - local specials = v.specials + for k, d in next, data do + local specials = d.specials if specials and specials[1] == "compat" and specials[2] == 0x0020 and specials[3] then local s = specials[3] fallbacks[k] = s fallbacks[s] = k end - directions[k] = v.direction end end -storage.register("characters/fallbacks", characters.fallbacks, "characters.fallbacks") -- accents and such -storage.register("characters/directions", characters.directions, "characters.directions") +storage.register("characters/fallbacks", characters.fallbacks, "characters.fallbacks") -- accents and such + +characters.directions = { } + +setmetatableindex(characters.directions,function(t,k) + local d = data[k] + if d then + local v = d.direction + if v then + t[k] = v + return v + end + end + t[k] = false -- maybe 'l' + return v +end) --[[ldx--

The context namespace is used to store methods and data diff --git a/tex/context/base/chem-str.mkiv b/tex/context/base/chem-str.mkiv index de1a13bca..aa244d75a 100644 --- a/tex/context/base/chem-str.mkiv +++ b/tex/context/base/chem-str.mkiv @@ -58,11 +58,13 @@ \let\setupchemicals\setupchemical -\unexpanded\def\setupchemicalframed - {\dosingleempty\dosetupchemicalframed} +\defineframed + [\??chemicalframed] + [\c!align=\v!normal, + \c!strut=\v!no] -\def\dosetupchemicalframed - {\getparameters[\??chemicalframed]} +\unexpanded\def\setupchemicalframed + {\setupframed[\??chemicalframed]} \unexpanded\def\definechemical % is global (so we don't use the commandhandler) {\dosingleargument\chem_define} @@ -171,15 +173,16 @@ \doifelsenothing{\chemicalparameter\c!frame}\chem_framed_nop\chem_framed_yes \egroup} -\def\chem_framed_yes - {\localframed% +\unexpanded\def\chem_framed_yes + {\localframedwithsettings [\??chemicalframed]% - [\c!frame=\chemicalparameter\c!frame,\c!align=\v!normal,\c!strut=\v!no]{\vbox{\box\b_chem_result\vss}}} % remove depth + [\c!frame=\chemicalparameter\c!frame]% + {\vbox{\box\b_chem_result\vss}}} % remove depth -\def\chem_framed_nop - {\localframed% +\unexpanded\def\chem_framed_nop + {\directlocalframed [\??chemicalframed]% - [\c!align=\v!normal,\c!strut=\v!no]{\vbox{\box\b_chem_result\vss}}} % remove depth + {\vbox{\box\b_chem_result\vss}}} % remove depth \let\startstructurechemical\startchemical \let\stopstructurechemical \stopchemical @@ -545,7 +548,7 @@ [\c!align=\v!normal, \c!strut=\v!no, \c!offset=\v!overlay, - \c!frame=off] + \c!frame=\v!off] \setupchemical [\c!frame=, diff --git a/tex/context/base/cont-new.mkii b/tex/context/base/cont-new.mkii index e85610718..9a3834e56 100644 --- a/tex/context/base/cont-new.mkii +++ b/tex/context/base/cont-new.mkii @@ -11,7 +11,7 @@ %C therefore copyrighted by \PRAGMA. See mreadme.pdf for %C details. -\newcontextversion{2012.07.10 09:52} +\newcontextversion{2012.07.17 00:23} %D This file is loaded at runtime, thereby providing an %D excellent place for hacks, patches, extensions and new diff --git a/tex/context/base/cont-new.mkiv b/tex/context/base/cont-new.mkiv index 4c75f02cd..03f998078 100644 --- a/tex/context/base/cont-new.mkiv +++ b/tex/context/base/cont-new.mkiv @@ -11,7 +11,7 @@ %C therefore copyrighted by \PRAGMA. See mreadme.pdf for %C details. -\newcontextversion{2012.07.10 09:52} +\newcontextversion{2012.07.17 00:23} %D This file is loaded at runtime, thereby providing an %D excellent place for hacks, patches, extensions and new @@ -215,7 +215,7 @@ #2\expandafter\expandafter\expandafter\doxprecurse\expandafter \fi\expandafter{\the\numexpr#1-1\relax}{#2}} -\unexpanded\def\buttonframed{\dodoubleempty\localframed[\??bt]} % goodie +% \unexpanded\def\buttonframed{\dodoubleempty\localframed[\??bt]} % goodie \unexpanded\def\asciistr#1{\dontleavehmode{\defconvertedargument\ascii{#1}\verbatimfont\ascii}} diff --git a/tex/context/base/context-version.pdf b/tex/context/base/context-version.pdf index 82301750c..3268979c2 100644 Binary files a/tex/context/base/context-version.pdf and b/tex/context/base/context-version.pdf differ diff --git a/tex/context/base/context-version.png b/tex/context/base/context-version.png index 225fefee9..7e7b3e6d5 100644 Binary files a/tex/context/base/context-version.png and b/tex/context/base/context-version.png differ diff --git a/tex/context/base/context.mkii b/tex/context/base/context.mkii index 5dfb83608..8cd630ac1 100644 --- a/tex/context/base/context.mkii +++ b/tex/context/base/context.mkii @@ -20,7 +20,7 @@ %D your styles an modules. \edef\contextformat {\jobname} -\edef\contextversion{2012.07.10 09:52} +\edef\contextversion{2012.07.17 00:23} %D For those who want to use this: diff --git a/tex/context/base/context.mkiv b/tex/context/base/context.mkiv index 42e18a410..0eb100895 100644 --- a/tex/context/base/context.mkiv +++ b/tex/context/base/context.mkiv @@ -25,7 +25,7 @@ %D up and the dependencies are more consistent. \edef\contextformat {\jobname} -\edef\contextversion{2012.07.10 09:52} +\edef\contextversion{2012.07.17 00:23} %D For those who want to use this: @@ -146,6 +146,7 @@ \loadmarkfile{trac-tex} \loadmarkfile{trac-deb} +\loadmarkfile{trac-ctx} % maybe move up %loadmarkfile{blob-ini} % not to be used, we only use a helper @@ -161,8 +162,6 @@ \loadmarkfile{typo-ini} -\loadmarkfile{page-ins} - \loadmkvifile{file-syn} \loadmkvifile{file-mod} @@ -261,6 +260,7 @@ \loadmarkfile{page-var} \loadmkvifile{page-otr} \loadmarkfile{page-ini} +\loadmarkfile{page-ins} \loadmarkfile{page-fac} \loadmarkfile{page-brk} \loadmarkfile{page-col} @@ -279,7 +279,8 @@ \loadmarkfile{page-pst} \loadmkvifile{page-mbk} -\loadmarkfile{page-mul} +\loadmarkfile{page-mul} % partly overloaded +\loadmarkfile{page-mix} % new \loadmarkfile{page-set} \loadmarkfile{pack-lyr} \loadmarkfile{pack-pos} diff --git a/tex/context/base/font-sol.lua b/tex/context/base/font-sol.lua index 861331785..e97e627b4 100644 --- a/tex/context/base/font-sol.lua +++ b/tex/context/base/font-sol.lua @@ -41,6 +41,7 @@ local v_normal = variables.normal local v_reverse = variables.reverse local v_preroll = variables.preroll local v_random = variables.random +local v_split = variables.split local settings_to_array = utilities.parsers.settings_to_array local settings_to_hash = utilities.parsers.settings_to_hash @@ -108,7 +109,8 @@ local preroll = true local criterium = 0 local randomseed = nil local optimize = nil -- set later -local variant = "normal" +local variant = v_normal +local splitwords = true local cache = { } local variants = { } @@ -125,23 +127,29 @@ local dummy = { criterium = 0, preroll = false, optimize = nil, - variant = "normal", + splitwords = false, + variant = v_normal, } local function checksettings(r,settings) local s = r.settings local method = settings_to_hash(settings.method or "") - local optimize + local optimize, preroll, splitwords for k, v in next, method do - if variants[k] then + if k == v_preroll then + preroll = true + elseif k == v_split then + splitwords = true + elseif variants[k] then variant = k - optimize = variants[k] -- last? + optimize = variants[k] -- last one wins end end r.randomseed = tonumber(settings.randomseed) or s.randomseed or r.randomseed or 0 r.criterium = tonumber(settings.criterium ) or s.criterium or r.criterium or 0 - r.preroll = method[v_preroll] and true or false - r.optimize = optimize or s.optimize or r.optimize + r.preroll = preroll or false + r.splitwords = splitwords or false + r.optimize = optimize or s.optimize or r.optimize or variants[v_normal] end local function pushsplitter(name,settings) @@ -159,6 +167,7 @@ local function pushsplitter(name,settings) criterium = r.criterium or 0 preroll = r.preroll or false optimize = r.optimize or nil + splitwords = r.splitwords or nil -- texsetattribute(a_split,r.attribute) return #stack @@ -327,22 +336,33 @@ function splitters.split(head) if m > max_more then max_more = m end start, stop, done = nil, nil, true end - while current do + while current do -- also nextid + local next = current.next local id = current.id - if id == glyph_code and current.subtype < 256 then - local a = has_attribute(current,a_split) - if not a then - start, stop = nil, nil - elseif not start then - start, stop, attribute = current, current, a - elseif a ~= attribute then - start, stop = nil, nil - else - stop = current + if id == glyph_code then + if current.subtype < 256 then + local a = has_attribute(current,a_split) + if not a then + start, stop = nil, nil + elseif not start then + start, stop, attribute = current, current, a + elseif a ~= attribute then + start, stop = nil, nil + else + stop = current + end end - current = current.next elseif id == disc_code then - start, stop, current = nil, nil, current.next + if splitwords then + if start then + flush() + end + elseif start and next and next.id == glyph_code and next.subtype < 256 then + -- beware: we can cross future lines + stop = next + else + start, stop = nil, nil + end elseif id == whatsit_code then if start then flush() @@ -351,13 +371,12 @@ function splitters.split(head) if subtype == dir_code or subtype == localpar_code then rlmode = current.dir end - current = current.next else if start then flush() end - current = current.next end + current = next end if start then flush() @@ -370,14 +389,18 @@ end local function collect_words(list) local words, w, word = { }, 0, nil for current in traverse_ids(whatsit_code,list) do - if current.subtype == userdefined_code then + if current.subtype == userdefined_code then -- hm local user_id = current.user_id if user_id == splitter_one then word = { current.value, current, current } w = w + 1 words[w] = word elseif user_id == splitter_two then - word[3] = current + if word then + word[3] = current + else + -- something is wrong + end end end end @@ -386,11 +409,36 @@ end -- we could avoid a hpack but hpack is not that slow + + local function doit(word,list,best,width,badness,line,set,listdir) local changed = 0 local n = word[1] local found = cache[n] if found then + + local h = word[2].next -- head of current word + local t = word[3].prev -- tail of current word + + if splitwords then + -- there are no lines crossed in a word + else + local ok = false + local c = h + while c do + if c == t then + ok = true + break + else + c = c.next + end + end + if not ok then + report_solutions("skipping hyphenated word (for now)") + return false, changed + end + end + local original, attribute, direction = found.original, found.attribute, found.direction local solution = solutions[attribute] local features = solution and solution[set] @@ -436,8 +484,8 @@ local function doit(word,list,best,width,badness,line,set,listdir) report_solutions("fatal error, no dynamics for font %s",font) end first = inject_kerns(first) - local h = word[2].next -- head of current word - local t = word[3].prev -- tail of current word +-- local h = word[2].next -- head of current word +-- local t = word[3].prev -- tail of current word if first.id == whatsit_code then local temp = first first = first.next @@ -555,112 +603,117 @@ local function show_quality(current,what,line) end function splitters.optimize(head) + if not optimize then + report_optimizers("no optimizer set") + return + end local nc = #cache - if nc > 0 then - starttiming(splitters) - local listdir = nil -- todo ! ! ! - if randomseed then - math.setrandomseedi(randomseed) - randomseed = nil - end - local line = 0 - local tex_hbadness, tex_hfuzz = tex.hbadness, tex.hfuzz - tex.hbadness, tex.hfuzz = 10000, number.maxdimen - if trace_optimize then - report_optimizers("preroll: %s, variant: %s, preroll criterium: %s, cache size: %s", - tostring(preroll),variant,criterium,nc) - end - for current in traverse_ids(hlist_code,head) do - -- report_splitters("before: [%s] => %s",current.dir,nodes.tosequence(current.list,nil)) - line = line + 1 - local sign, dir, list, width = current.glue_sign, current.dir, current.list, current.width - local temp, badness = repack_hlist(list,width,'exactly',dir) -- it would be nice if the badness was stored in the node - if badness > 0 then - if sign == 0 then + if nc == 0 then + return + end + starttiming(splitters) + local listdir = nil -- todo ! ! ! + if randomseed then + math.setrandomseedi(randomseed) + randomseed = nil + end + local line = 0 + local tex_hbadness, tex_hfuzz = tex.hbadness, tex.hfuzz + tex.hbadness, tex.hfuzz = 10000, number.maxdimen + if trace_optimize then + report_optimizers("preroll: %s, variant: %s, preroll criterium: %s, cache size: %s", + tostring(preroll),variant,criterium,nc) + end + for current in traverse_ids(hlist_code,head) do + -- report_splitters("before: [%s] => %s",current.dir,nodes.tosequence(current.list,nil)) + line = line + 1 + local sign, dir, list, width = current.glue_sign, current.dir, current.list, current.width + local temp, badness = repack_hlist(list,width,'exactly',dir) -- it would be nice if the badness was stored in the node + if badness > 0 then + if sign == 0 then + if trace_optimize then + report_optimizers("line %s, badness %s, okay",line,badness) + end + else + local set, max + if sign == 1 then if trace_optimize then - report_optimizers("line %s, badness %s, okay",line,badness) + report_optimizers("line %s, badness %s, underfull, trying more",line,badness) end + set, max = "more", max_more else - local set, max - if sign == 1 then - if trace_optimize then - report_optimizers("line %s, badness %s, underfull, trying more",line,badness) - end - set, max = "more", max_more - else - if trace_optimize then - report_optimizers("line %s, badness %s, overfull, trying less",line,badness) - end - set, max = "less", max_less + if trace_optimize then + report_optimizers("line %s, badness %s, overfull, trying less",line,badness) end - -- we can keep the best variants - local lastbest, lastbadness = nil, badness - if preroll then - local bb, base - for i=1,max do - if base then - free_nodelist(base) - end - base = copy_nodelist(list) - local words = collect_words(base) -- beware: words is adapted - for j=i,max do - local temp, done, changes, b = optimize(words,base,j,width,badness,line,set,dir) - base = temp - if trace_optimize then - report_optimizers("line %s, alternative: %s.%s, changes: %s, badness %s",line,i,j,changes,b) - end - bb = b - if b <= criterium then - break - end - -- if done then - -- break - -- end + set, max = "less", max_less + end + -- we can keep the best variants + local lastbest, lastbadness = nil, badness + if preroll then + local bb, base + for i=1,max do + if base then + free_nodelist(base) + end + base = copy_nodelist(list) + local words = collect_words(base) -- beware: words is adapted + for j=i,max do + local temp, done, changes, b = optimize(words,base,j,width,badness,line,set,dir) + base = temp + if trace_optimize then + report_optimizers("line %s, alternative: %s.%s, changes: %s, badness %s",line,i,j,changes,b) end - if bb and bb > criterium then -- needs checking - if not lastbest then - lastbest, lastbadness = i, bb - elseif bb > lastbadness then - lastbest, lastbadness = i, bb - end - else + bb = b + if b <= criterium then break end + -- if done then + -- break + -- end end - free_nodelist(base) - end - local words = collect_words(list) - for best=lastbest or 1,max do - local temp, done, changes, b = optimize(words,list,best,width,badness,line,set,dir) - current.list = temp - if trace_optimize then - report_optimizers("line %s, alternative: %s, changes: %s, badness %s",line,best,changes,b) - end - if done then - if b <= criterium then -- was == 0 - protect_glyphs(list) - break + if bb and bb > criterium then -- needs checking + if not lastbest then + lastbest, lastbadness = i, bb + elseif bb > lastbadness then + lastbest, lastbadness = i, bb end + else + break end end + free_nodelist(base) end - else - if trace_optimize then - report_optimizers("line %s, not bad enough",line) + local words = collect_words(list) + for best=lastbest or 1,max do + local temp, done, changes, b = optimize(words,list,best,width,badness,line,set,dir) + current.list = temp + if trace_optimize then + report_optimizers("line %s, alternative: %s, changes: %s, badness %s",line,best,changes,b) + end + if done then + if b <= criterium then -- was == 0 + protect_glyphs(list) + break + end + end end end - -- we pack inside the outer hpack and that way keep the original wd/ht/dp as bonus - current.list = hpack_nodes(current.list,width,'exactly',listdir) - -- report_splitters("after: [%s] => %s",temp.dir,nodes.tosequence(temp.list,nil)) - end - for i=1,nc do - local ci = cache[i] - free_nodelist(ci.original) + else + if trace_optimize then + report_optimizers("line %s, not bad enough",line) + end end - cache = { } - tex.hbadness, tex.hfuzz = tex_hbadness, tex_hfuzz - stoptiming(splitters) + -- we pack inside the outer hpack and that way keep the original wd/ht/dp as bonus + current.list = hpack_nodes(current.list,width,'exactly',listdir) + -- report_splitters("after: [%s] => %s",temp.dir,nodes.tosequence(temp.list,nil)) + end + for i=1,nc do + local ci = cache[i] + free_nodelist(ci.original) end + cache = { } + tex.hbadness, tex.hfuzz = tex_hbadness, tex_hfuzz + stoptiming(splitters) end statistics.register("optimizer statistics", function() diff --git a/tex/context/base/grph-inc.mkiv b/tex/context/base/grph-inc.mkiv index 50dab55f0..cc3989491 100644 --- a/tex/context/base/grph-inc.mkiv +++ b/tex/context/base/grph-inc.mkiv @@ -264,19 +264,21 @@ \definescale % some day we will inherit [\v!figure] - [\c!hfactor =\externalfiguresparameter\c!hfactor, - \c!wfactor =\externalfiguresparameter\c!wfactor, - \c!factor =\externalfiguresparameter\c!factor, - \c!maxwidth =\externalfiguresparameter\c!maxwidth , - \c!maxheight=\externalfiguresparameter\c!maxheight, - \c!xscale =\externalfiguresparameter\c!xscale, - \c!yscale =\externalfiguresparameter\c!yscale, - \c!scale =\externalfiguresparameter\c!scale, - \c!sx =\externalfiguresparameter\c!sx, - \c!sy =\externalfiguresparameter\c!sy, - \c!width =\externalfiguresparameter\c!width, - \c!height =\externalfiguresparameter\c!height, - \c!lines =\externalfiguresparameter\c!lines] + [\c!hfactor =\externalfiguresparameter\c!hfactor, + \c!wfactor =\externalfiguresparameter\c!wfactor, + \c!factor =\externalfiguresparameter\c!factor, + \c!maxwidth =\externalfiguresparameter\c!maxwidth , + \c!maxheight =\externalfiguresparameter\c!maxheight, + \c!equalwidth =\externalfiguresparameter\c!equalwidth , + \c!equalheight=\externalfiguresparameter\c!equalheight, + \c!xscale =\externalfiguresparameter\c!xscale, + \c!yscale =\externalfiguresparameter\c!yscale, + \c!scale =\externalfiguresparameter\c!scale, + \c!sx =\externalfiguresparameter\c!sx, + \c!sy =\externalfiguresparameter\c!sy, + \c!width =\externalfiguresparameter\c!width, + \c!height =\externalfiguresparameter\c!height, + \c!lines =\externalfiguresparameter\c!lines] %D You can register additional suffixes with the following command: %D diff --git a/tex/context/base/grph-trf.mkiv b/tex/context/base/grph-trf.mkiv index 87193ae4d..dd28f56fb 100644 --- a/tex/context/base/grph-trf.mkiv +++ b/tex/context/base/grph-trf.mkiv @@ -506,8 +506,8 @@ \edef#4{\withoutpt\the\scratchdimen}} % \startcombination -% {\externalfigure[cow.pdf] [frame=on,height=3cm,equalwidth=6cm]} {} -% {\externalfigure[mill.png][frame=on,height=3cm,equalwidth=6cm]} {} +% {\externalfigure[cow.pdf] [frame=on,height=3cm,equalwidth=6cm]} {a cow} +% {\externalfigure[mill.png][frame=on,height=3cm,equalwidth=6cm]} {a mill} % \stopcombination \def\grph_scale_position diff --git a/tex/context/base/luat-sto.lua b/tex/context/base/luat-sto.lua index 30bb7d5bb..860aa1121 100644 --- a/tex/context/base/luat-sto.lua +++ b/tex/context/base/luat-sto.lua @@ -13,6 +13,7 @@ local gmatch, format, write_nl = string.gmatch, string.format, texio.write_nl local serialize, concat, sortedhash = table.serialize, table.concat, table.sortedhash local bytecode = lua.bytecode +local trace_storage = false local report_storage = logs.reporter("system","storage") storage = storage or { } @@ -63,7 +64,7 @@ local function dump() max = max + 1 if trace_storage then report_storage('saving %s in slot %s',message,max) - c = c + 1 ; code[c] = format("report_storage('restoring %s from slot %s')",message,max) + c = c + 1 ; code[c] = format("print('restoring %s from slot %s')",message,max) end c = c + 1 ; code[c] = serialize(original,name) bytecode[max] = loadstring(concat(code,"\n")) diff --git a/tex/context/base/m-visual.mkiv b/tex/context/base/m-visual.mkiv index 988276a53..af6bb72fd 100644 --- a/tex/context/base/m-visual.mkiv +++ b/tex/context/base/m-visual.mkiv @@ -439,8 +439,7 @@ {\normalhskip -48\points \normalhbox to 24\points {\normalhss - {\ttxx#1}% - \ruledbaselines + {\ttxx\ruledbaselines}% \normalhskip6\points}% \raise\scratchdimen\box\scratchbox}% \smashbox\scratchbox diff --git a/tex/context/base/mult-def.mkiv b/tex/context/base/mult-def.mkiv index 433eae9f9..4d3570318 100644 --- a/tex/context/base/mult-def.mkiv +++ b/tex/context/base/mult-def.mkiv @@ -71,6 +71,7 @@ \ifdefined\v!stretched \else \def\v!stretched {stretched} \fi \ifdefined\v!vulgarfraction\else \def\v!vulgarfraction{vulgarfraction} \fi \ifdefined\v!block \else \def\v!block {block} \fi +\ifdefined\v!rule \else \def\v!rule {rule} \fi % stop todo diff --git a/tex/context/base/mult-low.lua b/tex/context/base/mult-low.lua index a32d4fe31..fd9493ba1 100644 --- a/tex/context/base/mult-low.lua +++ b/tex/context/base/mult-low.lua @@ -137,6 +137,13 @@ return { -- "then", -- + "firstargumentfalse", "firstargumenttrue", + "secondargumentfalse", "secondargumenttrue", + "thirdargumentfalse", "thirdargumenttrue", + "fourthargumentfalse", "fourthargumenttrue", + "fifthargumentfalse", "fifthsargumenttrue", + "sixthargumentfalse", "sixtsargumenttrue", + -- "doglobal", "dodoglobal", "redoglobal", "resetglobal", -- "donothing", "dontcomplain", "forgetall", diff --git a/tex/context/base/mult-sys.mkiv b/tex/context/base/mult-sys.mkiv index de72b5b80..be653f643 100644 --- a/tex/context/base/mult-sys.mkiv +++ b/tex/context/base/mult-sys.mkiv @@ -153,6 +153,9 @@ %definesystemconstant {mnem} % kind of generic short tag +\definesystemconstant {otr} +\definesystemconstant {box} + \definesystemconstant {file} \definesystemconstant {name} \definesystemconstant {spec} diff --git a/tex/context/base/node-res.lua b/tex/context/base/node-res.lua index 5b2b32a51..4bf4610cd 100644 --- a/tex/context/base/node-res.lua +++ b/tex/context/base/node-res.lua @@ -83,7 +83,6 @@ local glue = register_node(new_node("glue")) -- glue.spec = nil local glue_spec = register_node(new_node("glue_spec")) local glyph = register_node(new_node("glyph",0)) local textdir = register_node(new_node("whatsit",whatsitcodes.dir)) -local rule = register_node(new_node("rule")) local latelua = register_node(new_node("whatsit",whatsitcodes.latelua)) local special = register_node(new_node("whatsit",whatsitcodes.special)) local user_n = register_node(new_node("whatsit",whatsitcodes.userdefined)) user_n.type = 100 -- 44 @@ -98,8 +97,12 @@ local leftskip = register_node(new_node("glue",skipcodes.leftskip)) local rightskip = register_node(new_node("glue",skipcodes.rightskip)) local temp = register_node(new_node("temp",0)) local noad = register_node(new_node("noad")) -local hlist = register_node(new_node("hlist")) -local vlist = register_node(new_node("vlist")) + +-- the dir field needs to be set otherwise crash: + +local rule = register_node(new_node("rule")) rule .dir = "TLT" +local hlist = register_node(new_node("hlist")) hlist.dir = "TLT" +local vlist = register_node(new_node("vlist")) vlist.dir = "TLT" function pool.zeroglue(n) local s = n.spec @@ -230,8 +233,7 @@ function pool.rule(width,height,depth,dir) if width then n.width = width end if height then n.height = height end if depth then n.depth = depth end --- if dir then n.dir = dir end - n.dir = dir or "TLT" -- bug in luatex + if dir then n.dir = dir end return n end diff --git a/tex/context/base/pack-rul.mkiv b/tex/context/base/pack-rul.mkiv index c3ac12b1b..2a1f430ba 100644 --- a/tex/context/base/pack-rul.mkiv +++ b/tex/context/base/pack-rul.mkiv @@ -938,7 +938,7 @@ {\bgroup \dodoubleempty\pack_framed_local} -\unexpanded\def\localframed[#1][#2]% +\unexpanded\def\pack_framed_local[#1][#2]% {\bgroup \edef\currentframed{#1}% \pack_framed_initialize diff --git a/tex/context/base/page-brk.mkiv b/tex/context/base/page-brk.mkiv index 722556760..ac1fffd6b 100644 --- a/tex/context/base/page-brk.mkiv +++ b/tex/context/base/page-brk.mkiv @@ -53,9 +53,9 @@ \def\page_breaks_handle#1% {\edef\page_breaks_current_options{#1}% handy for tracing - \processcommacommand[\page_breaks_current_options]\page_breaks_handle_indeed} + \processcommacommand[\page_breaks_current_options]\page_breaks_handle_step} -\def\page_breaks_handle_indeed#1% +\def\page_breaks_handle_step#1% {\edef\page_breaks_current_option{#1}% can be used in handler \ifcsname\??pagebreakmethod\page_breaks_current_option\endcsname \csname\??pagebreakmethod\page_breaks_current_option\endcsname @@ -80,7 +80,8 @@ {\setvalue{\??pagebreaks#1}{#2}} \unexpanded\def\pagebreak - {\dosingleempty\page_breaks_process} + {\par % else no vertical penalties + \dosingleempty\page_breaks_process} \let\page\pagebreak @@ -269,9 +270,9 @@ \def\page_breaks_columns_handle#1% {\edef\page_breaks_columns_current_options{#1}% - \processcommacommand[#1]\page_breaks_columns_handle_indeed} + \processcommacommand[#1]\page_breaks_columns_handle_step} -\def\page_breaks_columns_handle_indeed#1% +\def\page_breaks_columns_handle_step#1% {\edef\page_breaks_columns_current_option{#1}% \ifcsname\??columnbreakmethod\currentoutputroutine:\page_breaks_columns_current_option\endcsname \csname\??columnbreakmethod\currentoutputroutine:\page_breaks_columns_current_option\endcsname @@ -296,7 +297,8 @@ {\setvalue{\??columnbreaks#1}{#2}} \unexpanded\def\columnbreak - {\dosingleempty\page_breaks_columns_process} + {\par % else no vertical penalties + \dosingleempty\page_breaks_columns_process} \let\column\columnbreak diff --git a/tex/context/base/page-col.mkiv b/tex/context/base/page-col.mkiv index 3143cadd2..54cf27bc5 100644 --- a/tex/context/base/page-col.mkiv +++ b/tex/context/base/page-col.mkiv @@ -19,65 +19,23 @@ \unprotect -%D The next two registers can be used to store pre column material as well -%D as footnotes or so. - -\newbox\precolumnbox \newdimen\precolumnboxheight -\newbox\postcolumnbox \newdimen\postcolumnboxheight - %D We reserve a counter for the number of columns as well as the current %D column. Both are not to be changed by users! \newcount\nofcolumns \nofcolumns\plusone \newcount\mofcolumns \mofcolumns\plusone -\setnewconstant\maxnofcolumns 50 -\setnewconstant\allocatednofcolumns 0 - -%D The next dimensions reports the final column height - -\newdimen\finalcolumnheights -\newcount\finalcolumnlines - -%D This register can be used as a temporary storage for page content. - -\newbox\restofpage - -%D A few more (some might go away): - -\newif\ifintermediatefootnotes % seems to be obsolete -\newif\ifcarryoverfootnotes %\carryoverfootnotestrue -\newif\iflastcolumnfootnotes %\lastcolumnfootnotestrue -\newif\ifbalancecolumns %\balancecolumnstrue -\newif\ifbalancetoheight %\balancetoheighttrue -\newif\ifforcecolumngrid \forcecolumngridtrue -\newif\ifstretchcolumns \stretchcolumnsfalse -\newif\ifinheritcolumns \inheritcolumnsfalse -\newif\ifheightencolumns \heightencolumnsfalse - -\newif\ifbalancingcolumns -\newif\ifcollectingcontent -\newif\ifcolumnoverflow - -\newdimen\intercolumnwidth -\newdimen\localcolumnwidth -\newdimen\savedpagetotal - \newconstant\columndirection % 0:lr 1:rl -\def\minbalancetoplines {1} -\def\minfreecolumnlines {2} - -\newif\ifrecentercolumnbox \recentercolumnboxtrue -\newif\ifrerecentercolumnbox \rerecentercolumnboxtrue +\setnewconstant\maxnofcolumns 50 +\setnewconstant\allocatednofcolumns 0 -%D During initialization the temporary boxes are allocated. -%D This enables us to use as much columns as we want, without -%D exhausting the pool of boxes too fast. We could have packed -%D them in one box, but we've got enough boxes. +%D During initialization the temporary boxes are allocated. This enables us to +%D use as much columns as we want, without exhausting the pool of boxes too +%D fast. We could have packed them in one box, but we've got enough boxes. %D -%D Two sets of boxes are declared, the txtboxes are used for -%D the text, the topboxes are for moved column floats. +%D Two sets of boxes are declared, the txtboxes are used for the text, the +%D topboxes are for moved column floats. \installcorenamespace{columntext} \installcorenamespace{columnfooter} @@ -92,15 +50,20 @@ \nofcolumns#1\relax \fi \ifnum\nofcolumns>\allocatednofcolumns - \dorecurse\nofcolumns - {\ifnum\recurselevel>\allocatednofcolumns\relax + \page_columns_allocate + \fi} + +\def\page_columns_allocate + {\dorecurse\nofcolumns + {\ifnum\recurselevel>\allocatednofcolumns\relax + \ifcsname\??columntext\recurselevel\endcsname \else \expandafter\newbox\csname\??columntext \recurselevel\endcsname % text \expandafter\newbox\csname\??columnfooter\recurselevel\endcsname % footer \expandafter\newbox\csname\??columntop \recurselevel\endcsname % top insert \expandafter\newbox\csname\??columnbottom\recurselevel\endcsname % bottom insert - \fi}% - \global\allocatednofcolumns\nofcolumns - \fi} + \fi + \fi}% + \global\allocatednofcolumns\nofcolumns} \def\firstcolumnbox {\columntextbox\plusone} \def\currentcolumnbox {\columntextbox\mofcolumns} @@ -115,15 +78,15 @@ \def\columntopbox #1{\csname\??columntop \number#1\endcsname} \def\columnbotbox #1{\csname\??columnbottom\number#1\endcsname} -\def\columnsettextbox {\global\setbox\columntextbox} -\def\columnsetfootbox {\global\setbox\columnfootbox} -\def\columnsettopbox {\global\setbox\columntopbox} -\def\columnsetbotbox {\global\setbox\columnbotbox} +\unexpanded\def\columnsettextbox {\global\setbox\columntextbox} +\unexpanded\def\columnsetfootbox {\global\setbox\columnfootbox} +\unexpanded\def\columnsettopbox {\global\setbox\columntopbox} +\unexpanded\def\columnsetbotbox {\global\setbox\columnbotbox} -\def\columngettextbox {\copy\columntextbox} -\def\columngetfootbox {\copy\columnfootbox} -\def\columngettopbox {\copy\columntopbox} -\def\columngetbotbox {\copy\columnbotbox} +\unexpanded\def\columngettextbox {\copy\columntextbox} +\unexpanded\def\columngetfootbox {\copy\columnfootbox} +\unexpanded\def\columngettopbox {\copy\columntopbox} +\unexpanded\def\columngetbotbox {\copy\columnbotbox} \unexpanded\def\columnerasetextboxes{\dorecurse\allocatednofcolumns{\columnsettextbox\recurselevel\emptybox}} \unexpanded\def\columnerasefootboxes{\dorecurse\allocatednofcolumns{\columnsetfootbox\recurselevel\emptybox}} @@ -135,25 +98,80 @@ %D with \type {\currentcolumnbox}. In case of the mid columns, \type %D {\firstcolumnbox} and \type {\lastcolumnbox} are handled outside these macro's. -%D If needed these can be sped up by using a dedicated loop macro. +% \unexpanded\def\dohandlecolumn#1% +% {\mofcolumns\recurselevel +% \let\currentcolumn\recurselevel +% #1\relax} +% +% \unexpanded\def\dohandleallcolumns#1% +% {\dorecurse\nofcolumns{\dohandlecolumn{#1}}} +% +% \unexpanded\def\dohandlerevcolumns#1% +% {\dostepwiserecurse\nofcolumns\plusone\minusone{\dohandlecolumn{#1}}} +% +% \unexpanded\def\dohandlemidcolumns#1% +% {\dohandleallcolumns +% {\ifnum\recurselevel>\plusone +% \ifnum\recurselevel<\nofcolumns +% \dohandlecolumn{#1}% +% \fi +% \fi}} +% +% As we don't nest we can use a fast variant: + +\unexpanded\def\dohandleallcolumnscs#1{\let\page_columns_action #1\page_columns_all_indeed} +\unexpanded\def\dohandleallcolumns #1{\def\page_columns_action{#1}\page_columns_all_indeed} + +\unexpanded\def\dohandlerevcolumnscs#1{\let\page_columns_action #1\page_columns_rev_indeed} +\unexpanded\def\dohandlerevcolumns #1{\def\page_columns_action{#1}\page_columns_rev_indeed} + +\unexpanded\def\dohandlemidcolumnscs#1{\let\page_columns_action #1\page_columns_mid_indeed} +\unexpanded\def\dohandlemidcolumns #1{\def\page_columns_action{#1}\page_columns_mid_indeed} + +\unexpanded\def\page_columns_all_indeed + {\mofcolumns\plusone + \edef\currentcolumn{\the\mofcolumns}% + \page_columns_action\relax + \ifnum\mofcolumns<\nofcolumns + \expandafter\page_columns_all_next + \fi} + +\unexpanded\def\page_columns_all_next + {\advance\mofcolumns\plusone + \edef\currentcolumn{\the\mofcolumns}% + \page_columns_action\relax + \ifnum\mofcolumns<\nofcolumns + \expandafter\page_columns_all_next + \fi} -\unexpanded\def\dohandlecolumn#1% - {\mofcolumns\recurselevel - \let\currentcolumn\recurselevel - #1\relax} +\unexpanded\def\page_columns_rev_indeed + {\mofcolumns\nofcolumns + \edef\currentcolumn{\the\mofcolumns}% + \page_columns_action\relax + \ifnum\mofcolumns>\plusone + \expandafter\page_columns_rev_prev + \fi} -\unexpanded\def\dohandleallcolumns#1% - {\dorecurse\nofcolumns{\dohandlecolumn{#1}}} +\unexpanded\def\page_columns_rev_prev + {\advance\mofcolumns\minusone + \edef\currentcolumn{\the\mofcolumns}% + \page_columns_action\relax + \ifnum\mofcolumns>\plusone + \expandafter\page_columns_rev_prev + \fi} -\unexpanded\def\dohandlerevcolumns#1% - {\dostepwiserecurse\nofcolumns\plusone\minusone{\dohandlecolumn{#1}}} +\unexpanded\def\page_columns_mid_indeed + {\mofcolumns\plustwo + \ifnum\mofcolumns<\nofcolumns + \expandafter\page_columns_mid_next + \fi} -\unexpanded\def\dohandlemidcolumns#1% - {\dohandleallcolumns - {\ifnum\recurselevel>\plusone - \ifnum\recurselevel<\nofcolumns - \dohandlecolumn{#1}% - \fi - \fi}} +\unexpanded\def\page_columns_mid_next + {\edef\currentcolumn{\the\mofcolumns}% + \page_columns_action\relax + \advance\mofcolumns\plusone + \ifnum\mofcolumns<\nofcolumns + \expandafter\page_columns_mid_next + \fi} \protect \endinput diff --git a/tex/context/base/page-flt.mkiv b/tex/context/base/page-flt.mkiv index c745290d1..56d801072 100644 --- a/tex/context/base/page-flt.mkiv +++ b/tex/context/base/page-flt.mkiv @@ -20,15 +20,18 @@ \unprotect -\installinsertion\c_page_floats_insertions_top -\installinsertion\c_page_floats_insertions_bottom +\ifdefined\s!topfloat \else \def\s!topfloat {topfloat} \fi +\ifdefined\s!bottomfloat \else \def\s!bottomfloat{bottomfloat} \fi -\newdimen \d_page_floats_inserted_bottom -\newdimen \d_page_floats_inserted_top -\newcount \c_page_floats_n_of_top \c_page_floats_n_of_top \plustwo -\newcount \c_page_floats_n_of_bottom \c_page_floats_n_of_bottom\zerocount +\defineinsertion[\s!topfloat] +\defineinsertion[\s!bottomfloat] -\newconstant \c_page_floats_insertions_topskip_mode % 1 = no topskip +\newdimen \d_page_floats_inserted_bottom +\newdimen \d_page_floats_inserted_top +\newcount \c_page_floats_n_of_top \c_page_floats_n_of_top \plustwo +\newcount \c_page_floats_n_of_bottom \c_page_floats_n_of_bottom\zerocount + +\newconstant\c_page_floats_insertions_topskip_mode % 1 = no topskip %def\page_floats_report_saved {\showmessage\m!floatblocks2{\the\totalnoffloats}} \def\page_floats_report_total {\showmessage\m!floatblocks4{\the\totalnoffloats}} diff --git a/tex/context/base/page-ins.lua b/tex/context/base/page-ins.lua new file mode 100644 index 000000000..1b8b8583b --- /dev/null +++ b/tex/context/base/page-ins.lua @@ -0,0 +1,65 @@ +if not modules then modules = { } end modules ['page-mix'] = { + version = 1.001, + comment = "companion to page-mix.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files", + -- public = { + -- functions = { + -- "inserts.define", + -- "inserts.getdata", + -- }, + -- commands = { + -- "defineinsertion", + -- "inserttionnumber", + -- } + -- } +} + +-- Maybe we should only register in lua and forget about the tex end. + +structures = structures or { } +structures.inserts = structures.inserts or { } +local inserts = structures.inserts + +local report_inserts = logs.reporter("inserts") + +inserts.stored = inserts.stored or { } -- combining them in one is inefficient in the +inserts.data = inserts.data or { } -- bytecode storage pool + +storage.register("structures/inserts/stored", inserts.stored, "structures.inserts.stored") + +local data = inserts.data +local stored = inserts.stored + +for name, specification in next, stored do + data[specification.number] = specification + data[name] = specification +end + +function inserts.define(specification) + local name = specification.name or "unknown" + local number = specification.number or 0 + data[name] = specification + data[number] = specification + -- only needed at runtime as this get stored in a bytecode register + stored[name] = specification +end + +function inserts.getdata(name) -- or number + return data[name] +end + +function inserts.getname(number) + return data[name].name +end + +function inserts.getnumber(name) + return data[name].number +end + +-- interface + +commands.defineinsertion = inserts.define +commands.insertionnumber = function(name) context(data[name].number or 0) end + diff --git a/tex/context/base/page-ins.mkiv b/tex/context/base/page-ins.mkiv index 33c50451b..cb952e6e7 100644 --- a/tex/context/base/page-ins.mkiv +++ b/tex/context/base/page-ins.mkiv @@ -17,23 +17,56 @@ %D page builder. When multiple footnote classes were introduced, I decided to %D isolate some of the functionality in a module. +\registerctxluafile{page-ins}{1.001} + \unprotect +%D Because we need to deal with inserts at the \LUA\ end as well, +%D we provide a proper installer. + +% Not yet used as we need to adapt some code to this. + +\installcorenamespace{insertion} +\installcorenamespace{insertionnumber} + +\installcommandhandler \??insertion {insertion} \??insertion + +\newcount\currentinsertionnumber % This is a count and not a macro ! + \newtoks\t_page_inserts_list -\let\doprocessinsert\gobbleoneargument +\let\doprocessinsert\relax -\unexpanded\def\installinsertion#1% - {\ifdefined#1\else - \let#1\relax - \fi - \ifx#1\relax % permits \csname...\endcsname - \newinsert#1% - \count#1\plusthousand - \skip #1\zeropoint - \dimen#1\maxdimen - \appendtoks\doprocessinsert#1\to\t_page_inserts_list - \fi} +%D Maybe some day we will move settings here. + +\unexpanded\def\setcurrentinsertion#1% + {\edef\currentinsertion{#1}% + \currentinsertionnumber\csname\??insertionnumber\currentinsertion\endcsname} + +\def\namedinsertionnumber#1{\csname\??insertionnumber#1\endcsname} + +\unexpanded\def\page_inserts_synchronize_registers + {\currentinsertionnumber\csname\??insertionnumber\currentinsertion\endcsname} + +\appendtoks + \page_inserts_synchronize_registers +\to \everysetupinsertion + +% \setupinsertion +% [\c!distance=\zeropoint, +% \c!maxheight=\maxdimen, +% \c!factor=\plusthousand] +% +% \unexpanded\def\page_inserts_synchronize_registers +% {\currentinsertionnumber\csname\??insertionnumber\currentinsertion\endcsname +% \global\count\currentinsertionnumber\insertionparameter\c!factor \relax +% \global\skip \currentinsertionnumber\insertionparameter\c!distance \relax +% \global\dimen\currentinsertionnumber\insertionparameter\c!maxheight\relax} + +\unexpanded\def\page_inserts_process#1% + {\edef\currentinsertion{#1}% + \currentinsertionnumber\csname\??insertionnumber\currentinsertion\endcsname + \doprocessinsert\currentinsertionnumber} % old method \unexpanded\def\processinsertions {\the\t_page_inserts_list} @@ -42,54 +75,92 @@ {\let\doprocessinsert\page_inserts_synchronize \processinsertions} -\def\page_inserts_synchronize#1% +\unexpanded\def\page_inserts_synchronize#1% yes or no {\ifvoid#1\else \insert#1{\unvbox#1}% \fi} -%D For instance, when we postpone footnotes, we need to save some data related to -%D the inserts. The next methods are far from ideal, but better than nothing. We -%D save and restore box content and associated data independently. The box content -%D is only restores when non||void. - -\installcorenamespace{insertionbackup} - -\unexpanded\def\installbackupinsertion#1% - {\ifcsname\??insertionbackup\string#1\endcsname \else - \expandafter\newinsert\csname\??insertionbackup\string#1\endcsname - \count\csname\??insertionbackup\string#1\endcsname\zerocount - \skip \csname\??insertionbackup\string#1\endcsname\zeropoint - \dimen\csname\??insertionbackup\string#1\endcsname\maxdimen - \fi} - -\unexpanded\def\saveinsertionbox#1% hm, actually unknown - {\global\setbox\csname\??insertionbackup\string#1\endcsname - \ifdim\ht#1>\zeropoint\box#1\else\emptybox\fi} - -\unexpanded\def\restoreinsertionbox#1% - {\ifvoid\backupinsertion#1\else % if void, we keep the content - \global\setbox#1\box\csname\??insertionbackup\string#1\endcsname +\unexpanded\def\doifinsertionelse#1% + {\ifcsname\??insertionnumber#1\endcsname + \expandafter\firstoftwoarguments + \else + \expandafter\secondoftwoarguments \fi} -\unexpanded\def\eraseinsertionbackup#1% - {\global\setbox\csname\??insertionbackup\string#1\endcsname\emptybox} - -\unexpanded\def\saveinsertiondata#1% - {\global\skip \csname\??insertionbackup\string#1\endcsname\skip #1% - \global\count\csname\??insertionbackup\string#1\endcsname\count#1% - \global\dimen\csname\??insertionbackup\string#1\endcsname\dimen#1} - -\unexpanded\def\restoreinsertiondata#1% - {\global\skip #1\skip \csname\??insertionbackup\string#1\endcsname - \global\count#1\count\csname\??insertionbackup\string#1\endcsname - \global\dimen#1\dimen\csname\??insertionbackup\string#1\endcsname} +% \unexpanded\def\startinsertion[#1]% +% {\insert\csname\??insertionnumber#1\endcsname\bgroup} +% +% \unexpanded\def\stopinsertion +% {\egroup} + +% For the moment we use the regular insertion allocator so that users can +% still define their own insertions (not that they will play nicely with +% all context mechanisms then). We can use the dimensions at the \LUA\ end +% so we don't need to pass pass them explicitly. Actually, when we see an +% insertion node at that end, we already know the number. + +\appendtoks + \ifcsname\??insertionnumber\currentinsertion\endcsname + % bad news + \else + \expandafter\newinsert\csname\??insertionnumber\currentinsertion\endcsname + \page_inserts_synchronize_registers + \ctxcommand{defineinsertion + { + name = "\currentinsertion", + number = \number\currentinsertionnumber, + } + }% + % + \t_page_inserts_list\expandafter\expandafter\expandafter + {\expandafter\the\expandafter\t_page_inserts_list + \expandafter\page_inserts_process\csname\??insertionnumber\currentinsertion\endcsname}% + \count\currentinsertionnumber\plusthousand + \skip \currentinsertionnumber\zeropoint + \dimen\currentinsertionnumber\maxdimen + \fi +\to \everydefineinsertion %D Auxiliary macros: -\unexpanded\def\addinsertionheight#1\to#2% - {\ifvoid#1\else - \advance#2 1\skip#1\relax - \advance#2 \ht #1\relax - \fi} +\def\page_insert_insertion_height#1% + {\dimexpr\expandafter\page_insert_insertion_height_indeed\csname\??insertionnumber#1\endcsname\relax} + +\def\page_insert_insertion_height_indeed#1% + {\ifvoid#1\zeropoint\else1\skip#1+\ht#1\fi} + +%D Obsolete: + +% \installcorenamespace{insertionbackup} +% +% \unexpanded\def\installbackupinsertion#1% +% {\ifcsname\??insertionbackup\string#1\endcsname \else +% \expandafter\newinsert\csname\??insertionbackup\string#1\endcsname +% \count\csname\??insertionbackup\string#1\endcsname\zerocount +% \skip \csname\??insertionbackup\string#1\endcsname\zeropoint +% \dimen\csname\??insertionbackup\string#1\endcsname\maxdimen +% \fi} +% +% \unexpanded\def\saveinsertionbox#1% hm, actually unknown +% {\global\setbox\csname\??insertionbackup\string#1\endcsname +% \ifdim\ht#1>\zeropoint\box#1\else\emptybox\fi} +% +% \unexpanded\def\restoreinsertionbox#1% +% {\ifvoid\backupinsertion#1\else % if void, we keep the content +% \global\setbox#1\box\csname\??insertionbackup\string#1\endcsname +% \fi} +% +% \unexpanded\def\eraseinsertionbackup#1% +% {\global\setbox\csname\??insertionbackup\string#1\endcsname\emptybox} +% +% \unexpanded\def\saveinsertiondata#1% +% {\global\skip \csname\??insertionbackup\string#1\endcsname\skip #1% +% \global\count\csname\??insertionbackup\string#1\endcsname\count#1% +% \global\dimen\csname\??insertionbackup\string#1\endcsname\dimen#1} +% +% \unexpanded\def\restoreinsertiondata#1% +% {\global\skip #1\skip \csname\??insertionbackup\string#1\endcsname +% \global\count#1\count\csname\??insertionbackup\string#1\endcsname +% \global\dimen#1\dimen\csname\??insertionbackup\string#1\endcsname} \protect \endinput diff --git a/tex/context/base/page-mix.lua b/tex/context/base/page-mix.lua new file mode 100644 index 000000000..75e013ce4 --- /dev/null +++ b/tex/context/base/page-mix.lua @@ -0,0 +1,629 @@ +if not modules then modules = { } end modules ['page-mix'] = { + version = 1.001, + comment = "companion to page-mix.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +-- inserts.getname(name) + +-- local node, tex = node, tex +-- local nodes, interfaces, utilities = nodes, interfaces, utilities +-- local trackers, logs, storage = trackers, logs, storage +-- local number, table = number, table + +local concat = table.concat + +local nodecodes = nodes.nodecodes +local gluecodes = nodes.gluecodes +local nodepool = nodes.pool + +local hlist_code = nodecodes.hlist +local vlist_code = nodecodes.vlist +local kern_code = nodecodes.kern +local glue_code = nodecodes.glue +local penalty_code = nodecodes.penalty +local insert_code = nodecodes.ins +local mark_code = nodecodes.mark + +local new_hlist = nodepool.hlist +local new_vlist = nodepool.vlist +local new_glue = nodepool.glue + +local hpack = node.hpack +local vpack = node.vpack +local freenode = node.free + +local texbox = tex.box +local texskip = tex.skip +local texdimen = tex.dimen +local points = number.points +local settings_to_hash = utilities.parsers.settings_to_hash + +local variables = interfaces.variables +local v_yes = variables.yes +local v_global = variables["global"] +local v_local = variables["local"] + +local trace_state = false trackers.register("mixedcolumns.trace", function(v) trace_state = v end) +local trace_detail = false trackers.register("mixedcolumns.detail", function(v) trace_detail = v end) + +local report_state = logs.reporter("mixed columns") + +pagebuilders = pagebuilders or { } +pagebuilders.mixedcolumns = pagebuilders.mixedcolumns or { } +local mixedcolumns = pagebuilders.mixedcolumns + +local forcedbreak = -123 + +-- initializesplitter(specification) +-- cleanupsplitter() + +local function collectinserts(result,nxt,nxtid) + local inserts, currentskips, nextskips, inserttotal = { }, 0, 0, 0 + while nxt do + if nxtid == insert_code then + inserttotal = inserttotal + nxt.height + nxt.depth + local s = nxt.subtype + local c = inserts[s] + if not c then + c = { } + inserts[s] = c + local width = texskip[s].width + if not result.inserts[s] then + currentskips = currentskips + width + end + nextskips = nextskips + width + end + c[#c+1] = nxt + if trace_detail then + report_state("insert of class %s found",s) + end + elseif nxtid == mark_code then + if trace_detail then + report_state("mark found") + end + else + break + end + nxt = nxt.next + if nxt then + nxtid = nxt.id + else + break + end + end + return nxt, inserts, currentskips, nextskips, inserttotal +end + +local function appendinserts(ri,inserts) + for class, collected in next, inserts do + local ric = ri[class] + if not ric then + -- assign to collected + ri[class] = collected + else + -- append to collected + for j=1,#collected do + ric[#ric+1] = collected[j] + end + end + end +end + +local function discardtopglue(current,discarded) + while current do + local id = current.id + if id == glue_code or (id == penalty_code and current.penalty ~= forcedbreak) then + discarded[#discarded+1] = current + current = current.next + else + break + end + end + return current +end + +local function stripbottomglue(results,discarded) + local height = 0 + for i=1,#results do + local r = results[i] + local t = r.tail + while t and t ~= r.head do + local prev = t.prev + if not prev then + break + elseif t.id == penalty_code then + if t.penalty == forcedbreak then + break + else + discarded[#discarded+1] = t + r.tail = prev + t = prev + end + elseif t.id == glue_code then + discarded[#discarded+1] = t + r.height = r.height - t.spec.width + r.tail = prev + t = prev + else + break + end + end + if r.height > height then + height = r.height + end + end + return height +end + +local function setsplit(specification) -- a rather large function + local box = specification.box + if not box then + report_state("fatal error, no box") + return + end + local list = texbox[box] + if not list then + report_state("fatal error, no list") + return + end + local head = list.head or specification.originalhead + if not head then + report_state("fatal error, no head") + return + end + local discarded = { } + local originalhead = head + local originalwidth = specification.originalwidth or list.width + local originalheight = specification.originalheight or list.height + local current = head + local height = 0 + local depth = 0 + local skip = 0 + local options = settings_to_hash(specification.option or "") + local stripbottom = specification.alternative == v_local + local cycle = specification.cycle or 1 + local nofcolumns = specification.nofcolumns or 1 + if nofcolumns == 0 then + nofcolumns = 1 + end + local preheight = specification.preheight or 0 + local extra = specification.extra or 0 + local maxheight = specification.maxheight + local optimal = originalheight/nofcolumns + if specification.balance ~= v_yes then + optimal = maxheight + end + local target = optimal + extra + local overflow = target > maxheight - preheight + local threshold = specification.threshold or 0 + if overflow then + target = maxheight - preheight + end + if trace_state then + report_state("cycle: %s, maxheight: %s, preheight: %s, target: %s, overflow: %s, extra: %s", + cycle, points(maxheight),points(preheight),points(target),tostring(overflow),points(extra)) + end + local results = { } + for i=1,nofcolumns do + results[i] = { + head = false, + tail = false, + height = 0, + depth = 0, + inserts = { }, + delta = 0, + } + end + local column = 1 + local result = results[column] + local lasthead = nil + local rest = nil + local function gotonext() + if head == lasthead then + if trace_state then + report_state("empty column %s, needs more work",column) + end +rest = current +return false + else + lasthead = head + result.head = head + if current == head then + result.tail = head + else + result.tail = current.prev + end + result.height = height + result.depth = depth + end + head = current + height = 0 + depth = 0 + skip = 0 + if column == nofcolumns then + column = 0 -- nicer in trace + rest = head +-- lasthead = head + return false + else + column = column + 1 + result = results[column] + current = discardtopglue(current,discarded) + head = current +-- lasthead = head + return true + end + end + local function checked(advance) + local total = skip + height + depth + advance + local delta = total - target + if trace_detail then + local currentcolumn = column + local state + if delta > threshold then + result.delta = delta + if gotonext() then + state = "next" + else + state = "quit" + end + else + state = "same" + end + if trace_detail then + report_state("check > column %s, advance: %s, total: %s, target: %s => %s (height: %s, depth: %s, skip: %s)", + currentcolumn,points(advance),points(total),points(target),state,points(height),points(depth),points(skip)) + end + return state + else + if delta > threshold then + result.delta = delta + if gotonext() then + return "next" + else + return "quit" + end + else + return "same" + end + end + end + current = discardtopglue(current,discarded) + head = current + while current do + local id = current.id + local nxt = current.next + if id == hlist_code or id == vlist_code then + local nxtid = nxt and nxt.id + local inserts, currentskips, nextskips, inserttotal = nil, 0, 0, 0 + local advance = current.height -- + current.depth + if nxt and (nxtid == insert_code or nxtid == mark_code) then + nxt, inserts, localskips, insertskips, inserttotal = collectinserts(result,nxt,nxtid) + end + local state = checked(advance+inserttotal+currentskips) + if trace_state then + report_state('line > column %s, advance: %s, insert: %s, height: %s, state: %s', + column,points(advance),points(inserttotal),points(height),state) + end + if state == "quit" then + break + else + height = height + depth + skip + advance + inserttotal + if state == "next" then + height = height + nextskips + else + height = height + currentskips + end + end + depth = current.depth + skip = 0 + if inserts then + appendinserts(result.inserts,inserts) + end + elseif id == glue_code then + local advance = current.spec.width + if advance ~= 0 then + local state = checked(advance) + if trace_state then + report_state('glue > column %s, advance: %s, height: %s, state: %s', + column,points(advance),points(height),state) + end + if state == "quit" then + break + end + height = height + depth + skip + depth = 0 + skip = height > 0 and advance or 0 + end + elseif id == kern_code then + local advance = current.kern + if advance ~= 0 then + local state = checked(advance) + if trace_state then + report_state('kern > column %s, advance: %s, height: %s, state: %s', + column,points(advance),points(height),state) + end + if state == "quit" then + break + end + height = height + depth + skip + advance + depth = 0 + skip = 0 + end + elseif id == penalty_code then + local penalty = current.penalty + if penalty == 0 then + -- don't bother + elseif penalty == forcedbreak then + if gotonext() then + if trace_state then + report_state("cycle: %s, forced column break (same page)",cycle) + end + else + if trace_state then + report_state("cycle: %s, forced column break (next page)",cycle) + end + break + end + else + -- club and widow and such i.e. resulting penalties (if we care) + end + end + if nxt then + current = nxt + elseif head == lasthead then +-- if trace_state then +-- report_state("quit as head is lasthead") +-- end +-- break + else + local r = results[column] + r.head = head + r.tail = current + r.height = height + r.depth = depth + break + end + end + if not current then + if trace_state then + report_state("nilling rest") + end + rest = nil + elseif rest == lasthead then + if trace_state then + report_state("nilling rest as rest is lasthead") + end + rest = nil + end + + if stripbottom then + local height = stripbottomglue(results,discarded) + if height > 0 then + target = height + end + end + + specification.results = results + specification.height = target + specification.originalheight = originalheight + specification.originalwidth = originalwidth + specification.originalhead = originalhead + specification.targetheight = target or 0 + specification.rest = rest + specification.overflow = overflow + specification.discarded = discarded + + texbox[specification.box].head = nil + + return specification +end + +function mixedcolumns.finalize(result) + if result then + local results = result.results + for i=1,result.nofcolumns do + local r = results[i] + local h = r.head + if h then + h.prev = nil + local t = r.tail + if t then + t.next = nil + else + h.next = nil + r.tail = h + end + for c, list in next, r.inserts do + local t = { } + for i=1,#list do + local l = list[i] + local h = new_hlist() + t[i] = h + h.head = l.head + h.height = l.height + h.depth = l.depth + l.head = nil + end + t[1].prev = nil -- needs checking + t[#t].next = nil -- needs checking + r.inserts[c] = t + end + end + end + end +end + +local splitruns = 0 + +local function report_deltas(result,str) + local t = { } + for i=1,result.nofcolumns do + t[#t+1] = points(result.results[i].delta or 0) + end + report_state("%s, cycles: %s, deltas: %s",str,result.cycle or 1,concat(t," | ")) +end + +function mixedcolumns.setsplit(specification) + splitruns = splitruns + 1 + if trace_state then + report_state("split run %s",splitruns) + end + local result = setsplit(specification) + if result then + if result.overflow then + if trace_state then + report_deltas(result,"overflow") + end + -- we might have some rest + elseif result.rest and specification.balance == v_yes then + local step = specification.step or 65536*2 + local cycle = 1 + local cycles = specification.cycles or 100 + while result.rest and cycle <= cycles do + specification.extra = cycle * step + result = setsplit(specification) or result + if trace_state then + report_state("cycle: %s.%s, original height: %s, total height: %s", + splitruns,cycle,points(result.originalheight),points(result.nofcolumns*result.targetheight)) + end + cycle = cycle + 1 + specification.cycle = cycle + end + if cycle > cycles then + report_deltas(result,"too many balancing cycles") + elseif trace_state then + report_deltas(result,"balanced") + end + elseif trace_state then + report_deltas(result,"done") + end + return result + elseif trace_state then + report_state("no result") + end +end + +local topskip_code = gluecodes.topskip +local baselineskip_code = gluecodes.baselineskip + +function mixedcolumns.getsplit(result,n) + if not result then + report_state("flush, column: %s, no result",n) + return + end + local r = result.results[n] + if not r then + report_state("flush, column: %s, empty",n) + end + local h = r.head + if not h then + return new_glue(result.originalwidth) + end + + if trace_state then + local id = h.id + if id == hlist_code then + report_state("flush, column: %s, top line: %s",n,nodes.toutf(h.list)) + else + report_state("flush, column: %s, head node: %s",n,nodecodes[id]) + end + end + + h.prev = nil -- move up + local strutht = result.strutht + local strutdp = result.strutdp + local lineheight = strutht + strutdp + + local v = new_vlist() + v.head = h + + -- local v = vpack(h,"exactly",height) + + v.width = result.originalwidth + if result.alternative == v_global then -- option + result.height = result.maxheight + end + v.height = lineheight * math.ceil(result.height/lineheight) - strutdp + v.depth = strutdp + + for c, list in next, r.inserts do + -- tex.setbox("global",c,vpack(nodes.concat(list))) + -- tex.setbox(c,vpack(nodes.concat(list))) + texbox[c] = vpack(nodes.concat(list)) + r.inserts[c] = nil + end + return v +end + +function mixedcolumns.getrest(result) + local rest = result and result.rest + result.rest = nil -- to be sure + return rest +end + +function mixedcolumns.getlist(result) + local originalhead = result and result.originalhead + result.originalhead = nil -- to be sure + return originalhead +end + +function mixedcolumns.cleanup(result) + local discarded = result.discarded + for i=1,#discarded do + freenode(discarded[i]) + end +end + +-- interface -- + +local result + +function commands.mixsetsplit(specification) + if result then + for k, v in next, specification do + result[k] = v + end + result = mixedcolumns.setsplit(result) + else + result = mixedcolumns.setsplit(specification) + end +end + +function commands.mixgetsplit(n) + if result then + context(mixedcolumns.getsplit(result,n)) + end +end + +function commands.mixfinalize() + if result then + mixedcolumns.finalize(result) + end +end + +function commands.mixflushrest() + if result then + context(mixedcolumns.getrest(result)) + end +end + +function commands.mixflushlist() + if result then + context(mixedcolumns.getlist(result)) + end +end + +function commands.mixstate() + context(result and result.rest and 1 or 0) +end + +function commands.mixcleanup() + if result then + mixedcolumns.cleanup(result) + result = nil + end +end diff --git a/tex/context/base/page-mix.mkiv b/tex/context/base/page-mix.mkiv new file mode 100644 index 000000000..58bc24f33 --- /dev/null +++ b/tex/context/base/page-mix.mkiv @@ -0,0 +1,754 @@ +%D \module +%D [ file=page-mix, +%D version=2012.07.12, +%D title=\CONTEXT\ Page Macros, +%D subtitle=Mixed Columns, +%D author=Hans Hagen, +%D date=\currentdate, +%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] +%C +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA. See mreadme.pdf for +%C details. + +\writestatus{loading}{ConTeXt Page Macros / Mixed Columns} + +%D This is a very experimental module. Eventually it will replace the current +%D multi column mechanism (that then will be an instance). The \LUA\ part of +%D the interface will quite probably change so don't use that one directly +%D (yet). + +% todo: +% +% consult note class +% notes per page +% notes in each column +% notes in last column +% notes local/global +% top and bottom inserts +% wide floats +% move floats + +% luatex buglet: +% +% \ctxlua{tex.setbox("global",0,node.hpack(nodes.pool.glyph("a",font.current())))}\box0 + +\registerctxluafile{page-mix}{1.001} + +\unprotect + +%D The mixed output routine replaces the traditional multi column handler that +%D started out in \MKII. One of the complications of a routine is that it needs +%D to align nicely when mixed in a single column layout. Instead of using all +%D kind of shift juggling in this mechanism we simply switch to grid mode +%D locally. After all, columns don't look nice when not on a grid. As the grid +%D snapper in \MKIV\ is more advanced not that much extra code is needed. + +%D We use the command handler but the parent settings are not to be changed. +%D Instead we could have used a dedicated root setup, but it's not worth the +%D trouble. + +\installcorenamespace{mixedcolumns} + +\def\s!mixedcolumn{mixedcolumn} + +\installframedcommandhandler \??mixedcolumns {mixedcolumns} \??mixedcolumns + +\setupmixedcolumns + [\c!distance=1.5\bodyfontsize, + \c!n=\plustwo, + %\c!rule=\v!none, + \c!frame=\v!off, + \c!strut=\v!no, + \c!offset=\v!overlay, + \c!alternative=\v!local, + \c!maxheight=\textheight, + \c!maxwidth=\makeupwidth, + \c!step=.25\lineheight, % needs some experimenting + \c!method=\ifinner\s!box\else\s!otr\fi] % automatic as suggested by WS + +\let\startmixedcolumns\relax % defined later +\let\stopmixedcolumns \relax % defined later + +\appendtoks + \setuevalue{\e!start\currentmixedcolumns}{\startmixedcolumns[\currentmixedcolumns]}% + \setuevalue{\e!stop \currentmixedcolumns}{\stopmixedcolumns}% +\to \everydefinemixedcolumns + +%D In order to avoid a mixup we use quite some local registers. + +\newdimen \d_page_mix_column_width +\newdimen \d_page_mix_max_height +\newdimen \d_page_mix_max_width +\newdimen \d_page_mix_distance +\newcount \c_page_mix_n_of_columns +\newdimen \d_page_mix_threshold +\newdimen \d_page_mix_leftskip +\newdimen \d_page_mix_rightskip + +\newdimen \d_page_mix_balance_step +\setnewconstant\c_page_mix_balance_cycles 500 + +\setnewconstant\c_page_mix_break_forced -123 + +\newbox \b_page_mix_preceding +\newdimen \d_page_mix_preceding_height + +\newbox \b_page_mix_collected + +\newconstant \c_page_mix_routine + +\setnewconstant\c_page_mix_routine_regular \zerocount +\setnewconstant\c_page_mix_routine_intercept\plusone +\setnewconstant\c_page_mix_routine_continue \plustwo +\setnewconstant\c_page_mix_routine_balance \plusthree +\setnewconstant\c_page_mix_routine_error \plusfour + +%D The main environment is called as follows: +%D +%D \starttyping +%D \startmixedcolumns[instance][settings] +%D \startmixedcolumns[instance] +%D \startmixedcolumns[settings] +%D \stoptyping +%D +%D However, best is not to use this one directly but define an instance and +%D use that one. + +% % For the moment only on my machine: +% +% \definemixedcolumns +% [\v!columns] +% +% \unexpanded\def\setupcolumns +% {\setupmixedcolumns[\v!columns]} + +%D In itemizations we also need columns, so let's define a apecial instance +%D for them. These need to work well in situations like this: +%D +%D \starttyping +%D \input zapf +%D +%D \startnarrower +%D \startitemize[columns,two,packed][before=,after=] +%D \dorecurse{10}{\startitem item #1 \stopitem} +%D \stopitemize +%D \stopnarrower +%D +%D \input zapf +%D +%D \startnarrower +%D \startitemize[columns,two][before=,after=] +%D \dorecurse{10}{\startitem item #1 \stopitem} +%D \stopitemize +%D \stopnarrower +%D +%D \input zapf +%D +%D \startnarrower +%D \startitemize[columns,two] +%D \dorecurse{10}{\startitem item #1 \stopitem} +%D \stopitemize +%D \stopnarrower +%D +%D \input zapf +%D \stoptyping + +\ifdefined\s!itemgroupcolumns \else \def\s!itemgroupcolumns{itemgroupcolumns} \fi + +\definemixedcolumns + [\s!itemgroupcolumns] + [\c!n=\itemgroupparameter\c!n, + \c!rule=\v!off, + \c!balance=\v!yes] + +\unexpanded\def\strc_itemgroups_start_columns + {\startmixedcolumns[\s!itemgroupcolumns]} % we could have a fast one + +\unexpanded\def\strc_itemgroups_stop_columns + {\stopmixedcolumns} + +%D The mixed output routine can be in different states. First we need to intercept +%D the already present content. This permits mixed single and multi column usage. +%D Then we have the continuous routine, one that intercepts pages in sequence. +%D Finally, when we finish the mixed columns mode, we can (optionally) balance the +%D last page. + +\unexpanded\def\page_mix_command_routine + {\ifcase\c_page_mix_routine + \page_one_command_routine + \or + \page_mix_routine_intercept + \or + \page_mix_routine_continue + \or + \page_mix_routine_balance + \or + \page_mix_routine_error + \fi} + +%D The interceptor is quite simple, at least for the moment. + +\def\page_mix_routine_intercept + {\global\setbox\b_page_mix_preceding\vbox + {\page_otr_command_flush_top_insertions + \unvbox\normalpagebox}} + +%D The error routine is there but unlikely to be called. It is a left-over from +%D the traditional routine that might come in handy some day. + +\def\page_mix_routine_error + {\showmessage\m!columns3\empty + \page_otr_construct_and_shipout\unvbox\normalpagebox} + +%D Some settings (and actions) depend on the current output routine and setting the +%D hsize and vsize is among them. The calculation of the hsize is done elsewhere. + +\unexpanded\def\page_mix_command_set_hsize + {\hsize\d_page_mix_column_width} + +%D When setting the vsize we make sure that we collect a few more lines than needed +%D so that we have enough to split over the columns. Collecting too much is somewhat +%D tricky as they will spill over to the next page. + +\unexpanded\def\page_mix_command_set_vsize + {\vsize\dimexpr\c_page_mix_n_of_columns\textheight+\c_page_mix_n_of_columns\lineheight\relax + \pagegoal\vsize} + +%D As we use \LUA\ there is the usual amount of tracing at that end. At the tex end +%D we only visualize boxes. + +\let\page_mix_hbox\hbox +\let\page_mix_vbox\vbox + +\installtextracker + {mixedcolumns.boxes} + {\let\page_mix_hbox\ruledhbox + \let\page_mix_vbox\ruledvbox} + {\let\page_mix_hbox\hbox + \let\page_mix_vbox\vbox} + +%D We provide a few column break options. Interesting is that while forcing a new +%D column in the traditional mechanism was a pain, here it works quite well. + +\installcolumnbreakmethod \s!mixedcolumn \v!preference + {\goodbreak} + +\installcolumnbreakmethod \s!mixedcolumn \v!yes + {\penalty\c_page_mix_break_forced\relax} + +%D As we operate in grid snapping mode, we use a dedicated macro to enable this +%D mechamism. + +\def\page_mix_enable_grid_snapping + {\gridsnappingtrue + \setsystemmode\v!grid + \spac_grids_snap_value_set\v!yes} + +%D Between columns there is normally just spacing unless one enforces a rule. +%D +%D \starttyping +%D \input zapf +%D +%D \startnarrower +%D \startmixedcolumns[n=2,background=color,backgroundcolor=red,rulethickness=1mm,rulecolor=green,separator=rule] +%D \input zapf +%D \stopmixedcolumns +%D \stopnarrower +%D +%D \input zapf +%D \stoptyping + +\installcorenamespace{mixedcolumnsseparator} + +\setvalue{\??mixedcolumnsseparator\v!rule}% + {\starttextproperties + \usemixedcolumnscolorparameter\c!rulecolor + \vrule\!!width\mixedcolumnsparameter\c!rulethickness + \stoptextproperties} + +\unexpanded\def\page_mix_command_inject_separator + {\bgroup + \hss + \csname\??mixedcolumnsseparator\mixedcolumnsparameter\c!separator\endcsname + \hss + \egroup} + +%D We've now arrived at the real code. The start command mostly sets up the +%D environment and variables that are used in the splitter. One of the last +%D things happening at the start is switching over to the mixed continuous +%D routine. + +\installcorenamespace{mixedcolumnsbefore} +\installcorenamespace{mixedcolumnsstart} +\installcorenamespace{mixedcolumnsstop} +\installcorenamespace{mixedcolumnsafter} + +%D For practical reasons there is always a first argument needed that +%D indicates the class. +%D +%D \starttyping +%D \startmixedcolumns[n=3,alternative=global] +%D \dorecurse{200}{Zomaar wat #1 met een footnote\footnote{note #1}. } +%D \stopmixedcolumns +%D \stoptyping + +\unexpanded\def\startmixedcolumns + {\dodoubleempty\page_mix_start_columns} + +\unexpanded\def\page_mix_start_columns + {\pushmacro\currentmixedcolumns + \pushmacro\currentmixedcolumnsmethod + \ifsecondargument + \singleexpandafter\page_mix_start_columns_a + \else\iffirstargument + \doubleexpandafter\page_mix_start_columns_b + \else + \doubleexpandafter\page_mix_start_columns_c + \fi\fi} + +\def\page_mix_start_columns_a[#1][#2]% + {\edef\currentmixedcolumns{#1}% + \edef\currentmixedcolumnsmethod{\mixedcolumnsparameter\c!method}% + \mixedcolumnsparameter\c!before\relax + \csname\??mixedcolumnsbefore\currentmixedcolumnsmethod\endcsname\relax + \begingroup + \setupcurrentmixedcolumns[#2]% + \page_mix_initialize_columns + \csname\??mixedcolumnsstart\currentmixedcolumnsmethod\endcsname} + +\def\page_mix_start_columns_b[#1][#2]% + {\doifassignmentelse{#1}% + {\let\currentmixedcolumns\empty + \page_mix_error_b} + {\edef\currentmixedcolumns{#1}% + \firstargumentfalse}% + \edef\currentmixedcolumnsmethod{\mixedcolumnsparameter\c!method}% + \mixedcolumnsparameter\c!before\relax % so, it doesn't list to local settings ! + \csname\??mixedcolumnsbefore\currentmixedcolumnsmethod\endcsname\relax + \begingroup + \iffirstargument + \setupcurrentmixedcolumns[#1]% + \fi + \page_mix_initialize_columns + \csname\??mixedcolumnsstart\currentmixedcolumnsmethod\endcsname} % no \relax + +\def\page_mix_error_b + {\writestatus\m!columns{best use an instance of mixed columns}} + +\def\page_mix_start_columns_c[#1][#2]% + {\let\currentmixedcolumns\empty + \edef\currentmixedcolumnsmethod{\mixedcolumnsparameter\c!method}% + \mixedcolumnsparameter\c!before\relax + \csname\??mixedcolumnsbefore\currentmixedcolumnsmethod\endcsname\relax + \begingroup + \page_mix_initialize_columns + \csname\??mixedcolumnsstart\currentmixedcolumnsmethod\endcsname} + +\unexpanded\def\page_mix_fast_columns_start#1% + {\pushmacro\currentmixedcolumns + \pushmacro\currentmixedcolumnsmethod + \edef\currentmixedcolumns{#1}% + \edef\currentmixedcolumnsmethod{\mixedcolumnsparameter\c!method}% + \mixedcolumnsparameter\c!before\relax % so, it doesn't list to local settings ! + \csname\??mixedcolumnsbefore\currentmixedcolumnsmethod\endcsname\relax + \begingroup + \page_mix_initialize_columns + \csname\??mixedcolumnsstart\currentmixedcolumnsmethod\endcsname} % no \relax + +%D When we stop, we switch over to the balancing routine. After we're done we +%D make sure to set the sizes are set, a somewhat redundant action when we +%D already have flushed but better be safe. + +\unexpanded\def\stopmixedcolumns + {\csname\??mixedcolumnsstop \currentmixedcolumnsmethod\endcsname % no \relax + \endgroup + \csname\??mixedcolumnsafter\currentmixedcolumnsmethod\endcsname\relax + \mixedcolumnsparameter\c!after\relax + \popmacro\currentmixedcolumnsmethod + \popmacro\currentmixedcolumns} + +\let\page_mix_fast_columns_stop\stopmixedcolumns + +%D This is how the fast one is used: + +\unexpanded\def\strc_itemgroups_start_columns + {\page_mix_fast_columns_start\s!itemgroupcolumns} + +\let\strc_itemgroups_stop_columns\page_mix_fast_columns_stop + +%D The common initialization: + +\def\page_mix_initialize_columns + {\page_mix_enable_grid_snapping + % + \holdinginserts\maxdimen + % + \d_page_mix_distance \mixedcolumnsparameter\c!distance + \c_page_mix_n_of_columns\mixedcolumnsparameter\c!n + \d_page_mix_max_height \mixedcolumnsparameter\c!maxheight + \d_page_mix_max_width \mixedcolumnsparameter\c!maxwidth + \d_page_mix_balance_step\mixedcolumnsparameter\c!step + % + \d_page_mix_max_width\dimexpr\d_page_mix_max_width-\leftskip-\rightskip\relax + \d_page_mix_leftskip \leftskip + \d_page_mix_rightskip\rightskip + \leftskip \zeropoint + \rightskip\zeropoint + % + \d_page_mix_threshold\zeropoint + % + \d_page_mix_column_width\dimexpr(\d_page_mix_max_width-\d_page_mix_distance*\numexpr(\c_page_mix_n_of_columns-\plusone)\relax)/\c_page_mix_n_of_columns\relax + % + \usemixedcolumnscolorparameter\c!color + % + \nofcolumns\c_page_mix_n_of_columns} % public + +%D The otr method related hooks are defined next: + +% \setvalue{\??mixedcolumnsbefore\s!otr}% +% {\par +% \ifdim\pagetotal=\zeropoint \else +% \verticalstrut % probably no longer needed +% \vskip-\struttotal % probably no longer needed +% \fi} + +\newcount\c_page_mix_otr_nesting + +\setvalue{\??mixedcolumnsbefore\s!otr}% + {\par + \global\advance\c_page_mix_otr_nesting\plusone + \ifcase\c_page_mix_otr_nesting\or + \ifdim\pagetotal=\zeropoint \else + \obeydepth % we could handle this in pre material + \fi + \fi} + +\setvalue{\??mixedcolumnsstart\s!otr}% + {\ifcase\c_page_mix_otr_nesting\or + \setupoutputroutine[\s!mixedcolumn]% + \c_page_mix_routine\c_page_mix_routine_intercept + \page_otr_trigger_output_routine + \global\d_page_mix_preceding_height\ht\b_page_mix_preceding + \c_page_mix_routine\c_page_mix_routine_continue + % + \page_mix_command_set_vsize + \page_mix_command_set_hsize + \fi} + +\setvalue{\??mixedcolumnsstop\s!otr}% + {\par + \ifcase\c_page_mix_otr_nesting\or + \c_page_mix_routine\c_page_mix_routine_balance + \page_otr_trigger_output_routine + \fi} + +\setvalue{\??mixedcolumnsafter\s!otr}% + {\ifcase\c_page_mix_otr_nesting\or + \prevdepth\strutdp + \page_otr_command_set_vsize + \page_otr_command_set_hsize + \fi + \global\advance\c_page_mix_otr_nesting\minusone} + +%D The splitting and therefore balancing is done at the \LUA\ end. This gives +%D more readable code and also makes it easier to deal with insertions like +%D footnotes. Eventually we will have multiple strategies available. + +\unexpanded\def\page_mix_routine_construct#1% + {\ctxcommand{mixsetsplit { + box = \number\b_page_mix_collected, + nofcolumns = \number\c_page_mix_n_of_columns, + maxheight = \number\d_page_mix_max_height, + step = \number\d_page_mix_balance_step, + cycles = \number\c_page_mix_balance_cycles, + preheight = \number\d_page_mix_preceding_height, + prebox = \number\b_page_mix_preceding, + strutht = \number\strutht, + strutdp = \number\strutdp, + threshold = \number\d_page_mix_threshold, + balance = "#1", + alternative = "\mixedcolumnsparameter\c!alternative", + }}% + \deadcycles\zerocount} + +\unexpanded\def\page_mix_routine_package + {\ctxcommand{mixfinalize()}% + \setbox\b_page_mix_collected\vbox \bgroup + \ifvoid\b_page_mix_preceding \else + \box\b_page_mix_preceding + \global\d_page_mix_preceding_height\zeropoint + \nointerlineskip + \fi + \hskip\d_page_mix_leftskip + \page_mix_hbox to \d_page_mix_max_width \bgroup + \letmixedcolumnsparameter\c!strut\v!no + % maybe use \c_page_mix_used_of_columns + \dorecurse\c_page_mix_n_of_columns {% + \inheritedmixedcolumnsframed{\page_mix_command_package_column}% + \ifnum\recurselevel<\c_page_mix_n_of_columns + \page_mix_command_inject_separator + \fi + }% + \egroup + \egroup} + +\unexpanded\def\page_mix_command_package_column + {\page_mix_hbox to \d_page_mix_column_width \bgroup + % maybe intercept empty + \ctxcommand{mixgetsplit(\recurselevel)}% + \hskip-\d_page_mix_column_width + \page_mix_hbox to \d_page_mix_column_width \bgroup + \placenoteinserts + \hss + \egroup + \egroup} + +\unexpanded\def\page_mix_routine_continue + {\bgroup + \forgetall + \dontcomplain + \setbox\b_page_mix_collected\vbox{\unvbox\normalpagebox}% brrr we need to make a tight box (combine this in lua) + \page_mix_routine_construct\v!no + \page_mix_routine_package + \page_otr_construct_and_shipout\box\b_page_mix_collected + \ctxcommand{mixflushrest()}% + \ctxcommand{mixcleanup()}% + \egroup} + +\unexpanded\def\page_mix_routine_balance + {\bgroup + \forgetall + \dontcomplain + \setbox\b_page_mix_collected\vbox{\unvbox\normalpagebox}% brrr we need to make a tight box (combine this in lua) + \doloop + {%writestatus\m!columns{construct continue (\the\htdp\b_page_mix_collected)}% + \page_mix_routine_construct\v!no + \ifcase\ctxcommand{mixstate()}\relax + % 0 = okay, we can balance + \setbox\b_page_mix_collected\vbox{\ctxcommand{mixflushlist()}}% we could avoid this + %writestatus\m!columns{construct balance}% + \page_mix_routine_construct\v!yes + \page_mix_routine_package + \c_page_mix_routine\c_page_mix_routine_regular + % \setupoutputroutine[\s!singlecolumn]% + \page_otr_command_set_vsize + \page_otr_command_set_hsize + \par + %writestatus\m!columns{flush balance}% + \box\b_page_mix_collected + \par + \nointerlineskip + \prevdepth\strutdp + \ctxcommand{mixflushrest()}% rubish + \ctxcommand{mixcleanup()}% rubish + \exitloop + \or + % 1 = we have stuff left, so flush and rebalance + %writestatus\m!columns{flush continue}% + \page_mix_routine_package + \page_otr_construct_and_shipout\box\b_page_mix_collected + \setbox\b_page_mix_collected\vbox{\ctxcommand{mixflushrest()}}% we could avoid this + \ctxcommand{mixcleanup()}% + \ifdim\ht\b_page_mix_collected=\zeropoint + \exitloop + \fi + \fi}% + \egroup} + +%D We also implement a variant compatible with the so called simple columns +%D mechanism: +%D +%D \starttyping +%D \startboxedcolumns +%D \input zapf +%D \stopboxedcolumns +%D \stoptyping +%D +%D This is a rather mininimalistic variant. + +% Maybe we also need a variant with obeydepth before and prevdepth after so +% that we get a nice spacing. + +\definemixedcolumns + [boxedcolumns] + [\c!balance=\v!yes, + \c!n=2, + \c!method=\s!box, + \c!strut=\v!yes, + \c!maxwidth=\availablehsize] + +%D Boxed columns can be used nested: +%D +%D \starttyping +%D \setupmixedcolumns +%D [boxedcolumns] +%D [n=2, +%D background=color, +%D backgroundcolor=darkred, +%D color=white, +%D backgroundoffset=1mm] +%D +%D \definemixedcolumns +%D [nestedboxedcolumns] +%D [boxedcolumns] +%D [n=2, +%D background=color, +%D backgroundcolor=white, +%D color=darkred, +%D strut=yes, +%D backgroundoffset=0mm] +%D +%D \startboxedcolumns +%D \input zapf \par \input ward \par \obeydepth +%D \startnestedboxedcolumns +%D \input zapf +%D \stopnestedboxedcolumns +%D \par \input zapf \par \obeydepth +%D \startnestedboxedcolumns +%D \input zapf +%D \stopnestedboxedcolumns +%D \par \input zapf +%D \stopboxedcolumns +%D \stoptyping + +%D Next we define the hooks: + +\letvalue{\??mixedcolumnsbefore\s!box}\donothing +\letvalue{\??mixedcolumnsafter \s!box}\donothing + +\setvalue{\??mixedcolumnsstart\s!box}% + {\edef\p_page_mix_strut{\mixedcolumnsparameter\c!strut}% + \setbox\b_page_mix_collected\vbox\bgroup + \let\currentoutputroutine\s!mixedcolumn % makes \column work + \forgetall + \page_mix_command_set_hsize + \ifx\p_page_mix_strut\v!yes + \begstrut + \ignorespaces + \fi} + +\setvalue{\??mixedcolumnsstop\s!box}% + {\ifx\p_page_mix_strut\v!yes + \removeunwantedspaces + \endstrut + \fi + \egroup + \page_mix_box_balance} + +%D The related balancer is only a few lines: + +\unexpanded\def\page_mix_box_balance + {\bgroup + \dontcomplain + \page_mix_routine_construct\v!yes + \page_mix_routine_package + \dontleavehmode\box\b_page_mix_collected + \ctxcommand{mixflushrest()}% + \ctxcommand{mixcleanup()}% + \egroup} + +%D As usual, floats complicates matters and this is where experimental code +%D starts. + +\let\page_mix_command_package_contents\page_one_command_package_contents +\let\page_mix_command_flush_float_box \page_one_command_flush_float_box + +\unexpanded\def\page_mix_command_check_if_float_fits + {\ifpostponecolumnfloats + \global\setfalse\c_page_floats_room + \else\ifconditional\c_page_floats_not_permitted + \global\setfalse\c_page_floats_room + \else +% \bgroup +% \getcolumnstatus{\count255}{\dimen0}{\dimen2}% +% \page_floats_get_info\s!text +% \setbox\scratchbox\vbox % tricky met objecten ? +% {\blank[\rootfloatparameter\c!spacebefore] +% \snaptogrid\vbox{\vskip\floatheight}}% copy? +% \advance\dimen0\dimexpr\ht\scratchbox+2\openlineheight+.5\lineheight\relax\relax % needed because goal a bit higher +% \ifdim\dimen0>\dimen2 +% \global\setfalse\c_page_floats_room +% \else + \global\settrue\c_page_floats_room + \fi + \ifdim\floatwidth>\hsize + \showmessage\m!columns{11}\empty + \global\setfalse\c_page_floats_room + \fi} + +\unexpanded\def\page_mix_command_flush_floats + {\page_one_command_flush_floats} + +\unexpanded\def\page_mix_command_flush_saved_floats + {\page_one_command_flush_saved_floats} + +% \unexpanded\def\page_mix_command_flush_top_insertions +% {\page_one_command_flush_top_insertions} + +% \unexpanded\def\page_mix_place_float_top +% {\showmessage\m!columns4\empty\page_one_place_float_here} + +% \unexpanded\def\page_mix_place_float_bottom +% {\showmessage\m!columns5\empty\page_one_place_float_here} + +\unexpanded\def\page_mix_place_float_here + {\page_one_place_float_here} + +\unexpanded\def\page_mix_place_float_force + {\page_one_place_float_force} + +\unexpanded\def\page_mix_command_side_float_output % hm + {\page_otr_construct_and_shipout\unvbox\normalpagebox} + +\unexpanded\def\page_mix_command_synchronize_side_floats % hm + {\page_sides_forget_floats} + +\unexpanded\def\page_mix_command_flush_side_floats + {\page_sides_forget_floats} + +\unexpanded\def\page_mix_command_next_page + {\page_otr_eject_page} + +\unexpanded\def\page_mix_command_next_page_and_inserts + {\page_otr_eject_page_and_flush_inserts} + +%D We need to hook some handlers into the output routine and we define +%D a dedicated one: + +\defineoutputroutine + [\s!mixedcolumn] + [\s!page_otr_command_routine =\page_mix_command_routine, + \s!page_otr_command_package_contents =\page_mix_command_package_contents, + \s!page_otr_command_set_vsize =\page_mix_command_set_vsize, + \s!page_otr_command_set_hsize =\page_mix_command_set_hsize, + \s!page_otr_command_next_page =\page_mix_command_next_page, + \s!page_otr_command_next_page_and_inserts =\page_mix_command_next_page_and_inserts, + % \s!page_otr_command_synchronize_hsize =\page_mix_command_synchronize_hsize, + % \s!page_otr_command_set_top_insertions =\page_mix_command_set_top_insertions, + % \s!page_otr_command_set_bottom_insertions =\page_mix_command_set_bottom_insertions, + % \s!page_otr_command_flush_top_insertions =\page_mix_command_flush_top_insertions, + % \s!page_otr_command_flush_bottom_insertions=\page_mix_command_flush_bottom_insertions, + % \s!page_otr_command_set_float_hsize =\page_mix_command_set_float_hsize, + \s!page_otr_command_check_if_float_fits =\page_mix_command_check_if_float_fits, + \s!page_otr_command_flush_float_box =\page_mix_command_flush_float_box, + \s!page_otr_command_synchronize_side_floats=\page_mix_command_synchronize_side_floats, + \s!page_otr_command_side_float_output =\page_mix_command_side_float_output, + \s!page_otr_command_flush_floats =\page_mix_command_flush_floats, + \s!page_otr_command_flush_side_floats =\page_mix_command_flush_side_floats, + \s!page_otr_command_flush_saved_floats =\page_mix_command_flush_saved_floats + % \s!page_otr_command_flush_margin_blocks =\page_mix_command_flush_margin_blocks, % not used + ] + +%D Only a few float placement options are supported: + +\installfloatmethod \s!mixedcolumn \v!here \page_mix_place_float_here +\installfloatmethod \s!mixedcolumn \v!force \page_mix_place_float_force +\installfloatmethod \s!mixedcolumn \v!top \page_mix_place_float_top +\installfloatmethod \s!mixedcolumn \v!bottom \page_mix_place_float_bottom + +\installfloatmethod \s!mixedcolumn \v!local \somelocalfloat + +%D It ends here. + +\protect \endinput diff --git a/tex/context/base/page-mul.mkiv b/tex/context/base/page-mul.mkiv index ba6343e6d..00075633a 100644 --- a/tex/context/base/page-mul.mkiv +++ b/tex/context/base/page-mul.mkiv @@ -11,45 +11,29 @@ %C therefore copyrighted by \PRAGMA. See mreadme.pdf for %C details. +% todo: basecolumns as parent for columns and itemize + % !!! there are some issues with hsize an vsize as well as flushing % !!! floats but this module will be redone anyway \writestatus{loading}{ConTeXt Page Macros / Simple Multi Column} -%D This module is mostly a copy from the original multi column -%D routine as implemented in \type {core-mul}. When the main -%D OTR macro's were isolated in modules and column sets were -%D introduced, this module became part of the OTR modules. As -%D a result this module is no longer generic. It also needs -%D an overhaul. +%D This module is mostly a copy from the original multi column routine as +%D implemented in \type {core-mul}. When the main OTR macro's were +%D isolated in modules and column sets were introduced, this module became +%D part of the OTR modules. As a result this module is no longer generic. \unprotect -\definesystemvariable {kl} % KoLommen \definesystemvariable {ks} % KolomSpan -\unexpanded\def\page_mul_command_side_float_output - {\page_otr_construct_and_shipout\unvbox\normalpagebox} - -\unexpanded\def\page_mul_command_flush_side_floats - {\page_sides_forget_floats} - -\unexpanded\def\page_mul_command_synchronize_side_floats - {\page_sides_forget_floats} - -\unexpanded\def\page_mul_command_next_page - {\page_otr_eject_page} - -\unexpanded\def\page_mul_command_next_page_and_inserts - {\page_otr_eject_page_and_flush_inserts} - % check \count multiplications %D The following macro's implement a multi||column output routine. The original %D implementation was based on Donald Knuth's implementation, which was adapted by %D Craig Platt to support balancing of the last page. I gradually adapted Platt's %D version to our needs but under certain circumstances things still went wrong. I -%D considered all calls to Platt's \type{\balancingerror} as undesirable. +%D considered all calls to Platt's \type{\page_mul_routine_error} as undesirable. %D %D This completely new implementation can handle enough situations for everyday %D documents, but is still far from perfect. While at the moment the routine doesn't @@ -58,7 +42,7 @@ %D \startitemize[packed] %D \item an unlimitted number of columns %D \item ragged or not ragged bottoms -%D \item optional balancing without \type{\balancingerrors} +%D \item optional balancing without \type{\page_mul_routine_errors} %D \item different \type{\baselineskips}, \type{\spacing}, \type {\topskip} and %D \type {\maxdepth} %D \item left- and right indentation, e.g. within lists @@ -72,83 +56,146 @@ %D special case of multi||columns is posible but at the cost of worse float %D handling, worse page breaking, worse etc. Complicated multi||column page handling %D should be done in \cap{DTP}||systems anyway. -%D -%D There are three commands provided for entering and leaving multi||column mode and -%D for going to the next column: -%D -%D \interface \type{\beginmulticolumns} \\ \\ -%D \interface \type{\endmulticolumns} \\ \\ -%D \interface \type{\ejectcolumn} \\ \\ -\def\finalcolumntextwidth {\makeupwidth} -\def\finalcolumntextheight {\textheight} -\def\columntextwidth {\makeupwidth} -\def\columntextheight {\textheight} -\def\usercolumnwidth {\textwidth} -\def\columntextoffset {\!!zeropoint} +\installcorenamespace {columns} + +\installcommandhandler \??columns {columns} \??columns + +%D Going to a new columns is done by means of a \type {\ejectcolumn}. The +%D following definition does not always work. + + \unexpanded\def\ejectcolumn % not good enough + {\goodbreak + \showmessage\m!columns2\empty} -\def\fixedcolumnheight {\textheight} -\def\betweencolumns {\hskip\bodyfontsize} +%D The output routines plug into a more generic mechanism as can be seen at the +%D end of this file. So, occasionally we need to define some plugin code. -\let\setcolumnfloats \relax % in CONTEXT used for floats -\let\flushcolumnfloats \relax % in CONTEXT used for floats -\let\flushcolumnfloat \relax % in CONTEXT used for floats -\let\finishcolumnbox \relax % in CONTEXT used for backgrounds +\unexpanded\def\page_mul_place_float_top + {\showmessage\m!columns4\empty\page_one_place_float_here} -%D Both macros are redefined in \CONTEXT\ when backgrounds are applied to -%D columns. The final values are used when flushing the columns. +\unexpanded\def\page_mul_place_float_bottom + {\showmessage\m!columns5\empty\page_one_place_float_here} -%D It's more convenient to use \type {\columnwidth} instead of messing around -%D with boxes each time. +\unexpanded\def\page_mul_place_float_here + {\page_one_place_float_here} -\newdimen\columnwidth -\newdimen\gutterwidth +\unexpanded\def\page_mul_place_float_force + {\page_one_place_float_force} -\def\determinecolumnwidth +\unexpanded\def\page_mul_command_side_float_output + {\page_otr_construct_and_shipout\unvbox\normalpagebox} + +\unexpanded\def\page_mul_command_flush_side_floats + {\page_sides_forget_floats} + +\unexpanded\def\page_mul_command_synchronize_side_floats + {\page_sides_forget_floats} + +\unexpanded\def\page_mul_command_next_page + {\page_otr_eject_page} + +\unexpanded\def\page_mul_command_next_page_and_inserts + {\page_otr_eject_page_and_flush_inserts} + +\let\page_mul_initialize_floats\relax +\let\page_mul_flush_floats \relax +\let\page_mul_flush_float \relax + +%D A hook: + + \let\finishcolumnbox\relax + +%D This will change to a local one: + +\ifdefined\nofcolumns \else \newcount\nofcolumn \fi +\ifdefined\mofcolumns \else \newcount\mofcolumn \fi + +\appendtoks + \nofcolumns\columnsparameter\c!n\relax +\to \everysetupcolumns + +%D Columns are separated by spacing or rules or whatever suits. + +\installcorenamespace{columnseparators} + +\setvalue{\??columnseparators\v!on }{\let\page_mul_between_columns\page_mul_between_columns_rule} +\setvalue{\??columnseparators\v!off }{\let\page_mul_between_columns\page_mul_between_columns_space} +\setvalue{\??columnseparators }{\let\page_mul_between_columns\page_mul_between_columns_space} +\setvalue{\??columnseparators\s!unknown}{\let\page_mul_between_columns\p_page_mul_rule} + +\def\page_mul_between_columns_rule {\bgroup - \setbox\scratchbox\hbox - {\page_mul_command_set_hsize - \global\columnwidth\usercolumnwidth - \global\gutterwidth\intercolumnwidth}% + \starttextproperties + \scratchdistance\dimexpr\columnsparameter\c!distance/2\relax + \hskip\scratchdistance\relax + \vrule + \!!width\linewidth + \ifnum\bottomraggednessmode=\plustwo % baselinebottom + \!!depth\strutdepth + \fi + \hskip\scratchdistance\relax + \stoptextproperties \egroup} -%D Going to a new columns is done by means of a \type {\ejectcolumn}. The -%D following definition does not always work. +\def\page_mul_between_columns_space + {\hskip\columnsparameter\c!distance\relax} -\def\ejectcolumn - {\goodbreak - \showmessage\m!columns2\empty} +\let\page_mul_between_columns\page_mul_between_columns_space -\def\balancingerror - {\showmessage\m!columns3\empty - \page_otr_construct_and_shipout\unvbox\normalpagebox} +%D We declare some registers: + +\newdimen \d_page_mul_available_width +\newdimen \d_page_mul_distance +\newdimen \d_page_mul_leftskip +\newdimen \d_page_mul_rightskip +\newdimen \d_page_mul_offset +\newdimen \d_page_mul_forced_height +\newdimen \d_page_mul_used_width +\newdimen \d_page_mul_temp + +\newcount \c_page_mul_balance_minimum +\newcount \c_page_mul_n_of_lines + +\newbox \b_page_mul_preceding +\newdimen \d_page_mul_preceding_height +\newconditional\c_page_mul_preceding_present + +\newbox \b_page_mul_preceding_rest_of_page -\def\page_mul_place_float_top {\showmessage\m!columns4\empty\page_one_place_float_here} -\def\page_mul_place_float_bottom{\showmessage\m!columns5\empty\page_one_place_float_here} -\def\page_mul_place_float_here {\page_one_place_float_here} -\def\page_mul_place_float_force {\page_one_place_float_force} +\newconditional\c_page_mul_reverse -%D The local column width is available in the dimension register \type -%D {\localcolumnwidth}, which is calculated as: +\newconditional\c_page_mul_trace + +%D The next dimensions reports the final column height .. todo + + \newdimen\finalcolumnheights + \newcount\finalcolumnlines + + \newdimen\savedpagetotal % brrr + + \newif\ifstretchcolumns \stretchcolumnsfalse + \newif\ifheightencolumns \heightencolumnsfalse + \newif\ifinheritcolumns \inheritcolumnsfalse + \newif\ifbalancecolumns %\balancecolumnstrue + +%D An important one: \unexpanded\def\page_mul_command_set_hsize % beware, this one is available for use in macros - {\setbox\scratchbox\hbox{\parindent\zeropoint\betweencolumns}% - \intercolumnwidth\wd\scratchbox - \localcolumnwidth\columntextwidth - \advance\localcolumnwidth -\leftskip - \advance\localcolumnwidth -\rightskip - % new - \advance\localcolumnwidth -\colleftskip - \advance\localcolumnwidth -\colrightskip - % - \advance\localcolumnwidth -\nofcolumns\intercolumnwidth - \advance\localcolumnwidth \intercolumnwidth - \divide \localcolumnwidth \nofcolumns - \scratchdimen\columntextoffset - \multiply\scratchdimen \plustwo - \advance\localcolumnwidth -\scratchdimen - \usercolumnwidth\localcolumnwidth - \hsize\localcolumnwidth} % we don't do it \global + {\setbox\scratchbox\hbox{\page_mul_between_columns}% + \d_page_mul_distance\wd\scratchbox + \d_page_mul_available_width\dimexpr + \makeupwidth + -\d_page_mul_leftskip + -\d_page_mul_rightskip + -\nofcolumns\d_page_mul_distance + +\d_page_mul_distance + \relax + \d_page_mul_used_width\dimexpr + \d_page_mul_available_width/\nofcolumns + -\d_page_mul_offset*\plustwo + \relax + \hsize\d_page_mul_used_width} %D Torture test: %D @@ -219,122 +266,79 @@ %D in||between material, these dimensions are influenced by bodyfont switches inside %D multi||column mode. -\newdimen\mcscratchdimen -\newcount\nofcolumnlines +\setnewconstant\multicolumnlinemethod\zerocount % 0=normal 1=raw -\setnewconstant\multicolumnlinemethod\plusone % 0: overshoot (old default), 1: tight +\def\multicolumnovershootratio{.5} % {\ifgridsnapping0\else.5\fi} -\def\getmulticolumnlines - {\mcscratchdimen-\columntextoffset - \multiply\mcscratchdimen \plustwo - \advance\mcscratchdimen \columntextheight - \ifdim\precolumnboxheight>\zeropoint - \advance\mcscratchdimen -\precolumnboxheight - \fi - \settotalinsertionheight - \advance\mcscratchdimen -\totalinsertionheight - \ifcase\multicolumnlinemethod \getnoflines\mcscratchdimen - \or \getrawnoflines\mcscratchdimen - \else \getrawnoflines\mcscratchdimen +\unexpanded\def\page_mul_set_n_of_lines + {\settotalinsertionheight + \d_page_mul_temp\dimexpr + -\d_page_mul_offset*\plustwo + +\textheight + \ifdim\d_page_mul_preceding_height>\zeropoint -\d_page_mul_preceding_height \fi + -\totalinsertionheight + \relax + \ifcase\multicolumnlinemethod + \getnoflines \d_page_mul_temp \or + \getrawnoflines\d_page_mul_temp \else + \getrawnoflines\d_page_mul_temp \fi % added 30/7/2004 \ifnum\layoutlines>\zerocount \ifnum\noflines>\layoutlines \noflines\layoutlines \fi \fi - \nofcolumnlines\noflines} - -\def\multicolumnovershootratio{.5} % {\ifgridsnapping0\else.5\fi} + \c_page_mul_n_of_lines\noflines} \unexpanded\def\page_mul_command_set_vsize {\page_one_command_set_vsize % indeed? - \getmulticolumnlines - \mcscratchdimen\nofcolumnlines\openlineheight - \advance\mcscratchdimen \multicolumnovershootratio\openlineheight % collect enough data - \global\vsize\nofcolumns\mcscratchdimen - \global\pagegoal\vsize} % let's do it only here + \page_mul_set_n_of_lines + \d_page_mul_temp\nofcolumns\dimexpr + \c_page_mul_n_of_lines\openlineheight + +\multicolumnovershootratio\openlineheight % collect enough data + \relax + \global\vsize \d_page_mul_temp + \global\pagegoal\d_page_mul_temp} % let's do it only here %D It really starts here. After some checks and initializations we change the output %D routine to continous multi||column mode. This mode handles columns that fill the %D current and next full pages. The method used is (more or less) multiplying \type %D {\vsize} and dividing \type {\hsize} by \type {\nofcolumns}. More on this can be %D found in the \TeX book. We save the top of the current page in box -%D \type{\precolumnbox}. +%D \type {\b_page_mul_preceding}. %D %D We manipulate \type {\topskip} a bit, just to be shure that is has no %D flexibility. This has te be done every time a font switch takles place, because -%D \type{\topskip} can depend on this. +%D \type {\topskip} can depend on this. \newconstant\c_page_mul_routine -\setnewconstant\c_page_mul_routine_regular \zerocount -\setnewconstant\c_page_mul_routine_intercept \plusone -\setnewconstant\c_page_mul_routine_continuous \plustwo -\setnewconstant\c_page_mul_routine_balanced \plusthree -\setnewconstant\c_page_mul_routine_error \plusfour +\setnewconstant\c_page_mul_routine_regular \zerocount +\setnewconstant\c_page_mul_routine_intercept \plusone +\setnewconstant\c_page_mul_routine_continue \plustwo +\setnewconstant\c_page_mul_routine_balance \plusthree +\setnewconstant\c_page_mul_routine_error \plusfour \unexpanded\def\page_mul_command_routine {\ifcase\c_page_mul_routine \page_one_command_routine \or - \interceptmulticolumnsout + \page_mul_routine_intercept \or - \continuousmulticolumnsout + \page_mul_routine_continue \or - \balancedmulticolumnsout + \page_mul_routine_balance \or - \balancingerror + \page_mul_routine_error \fi} -\def\interceptmulticolumnsout - {\global\setbox\precolumnbox\vbox - {\page_otr_command_flush_top_insertions\unvbox\normalpagebox}} +\def\page_mul_routine_intercept + {\global\setbox\b_page_mul_preceding\vbox + {\page_otr_command_flush_top_insertions + \unvbox\normalpagebox}} -\def\beginmulticolumns - {\par - \flushnotes - \xdef\precolumndepth{\the\prevdepth}% - \begingroup - % new - \leftskip1\leftskip - \rightskip1\rightskip - \edef\colleftskip {\the\leftskip}% - \edef\colrightskip{\the\rightskip}% - \leftskip\zeropoint - \rightskip\zeropoint - % - %\setcolumntextwidth\relax - %\setcolumntextheight\relax - \widowpenalty\zerocount % is gewoon beter - \clubpenalty \zerocount % zeker bij grids - \page_floats_column_push_saved - \dimen0\dimexpr\pagetotal+\parskip+\openlineheight\relax - \ifdim\dimen0<\pagegoal - \allowbreak - \else - \break % Sometimes fails - \fi - \appendtoks\topskip1\topskip\to\everybodyfont - \the\everybodyfont % ugly here - \saveinterlinespace % ugly here - \initializecolumns\nofcolumns - \hangafter\zerocount - \hangindent\zeropoint - \reseteverypar - \ifdim\pagetotal=\zeropoint \else - \verticalstrut - \vskip-\struttotal - \fi - \global\savedpagetotal\pagetotal - \setupoutputroutine[\s!multicolumn]% - \c_page_mul_routine\c_page_mul_routine_intercept - \page_otr_trigger_output_routine % no \holdinginserts=1, can make footnote disappear ! - \global\precolumnboxheight\ht\precolumnbox - \c_page_mul_routine\c_page_mul_routine_continuous - \setcolumnfloats - \dohandleallcolumns{\global\setbox\currenttopcolumnbox\emptybox}% - \checkbegincolumnfootnotes - \page_otr_command_set_hsize - \page_otr_command_set_vsize} +\def\page_mul_routine_error + {\showmessage\m!columns3\empty + \page_otr_construct_and_shipout\unvbox\normalpagebox} %D When we leave the multi||column mode, we have to process the not yet shipped out %D part of the columns. When we don't balance, we simply force a continuous output, @@ -345,160 +349,150 @@ %D macro's. It takes some reasoning to find out what happens and maybe I'm making %D some mistake, but it works. %D -%D Voiding box \type {\precolumnbox} is sometimes necessary, e.g. when there is no +%D Voiding box \type {\b_page_mul_preceding} is sometimes necessary, e.g. when there is no %D text given between \type {\begin..} and \type {\end..}. The \type {\par} is %D needed! -\setnewconstant\multicolumnendsyncmethod\plusone % 1: old sync 2: new sync (cont-loc/project) / may fail ! ! ! ! - -\def\endmulticolumns - {%\par - \ifnum\multicolumnendsyncmethod=\plustwo - \synchronizeoutput - \else - % don't combine these - \vskip\lineheight - \vskip-\lineheight % take footnotes into account - \fi - \doflushcolumnfloat % added recently - %\doflushcolumnfloats % no, since it results in wrong top floats - \flushnotes % before start of columns - \par - \ifbalancecolumns - \ifnum\multicolumnendsyncmethod=\plusone - \c_page_mul_routine\c_page_mul_routine_continuous - \goodbreak - \fi - \c_page_mul_routine\c_page_mul_routine_balanced - \else - \goodbreak - \fi - % still the multi column routine - \page_otr_trigger_output_routine % the prevdepth is important, try e.g. toclist in - \prevdepth\zeropoint % columns before some noncolumned text text - % - \c_page_mul_routine\c_page_mul_routine_regular -% \page_otf_set_engine_output_routine{\singlecolumnout}% -% \page_otf_set_engine_output_routine{\page_otr_triggered_output_routine}% - % - \ifvoid\precolumnbox\else - \unvbox\precolumnbox - \fi - \global\precolumnboxheight\zeropoint - \endgroup % here - \nofcolumns\plusone - \page_otr_command_set_vsize % the outer vsize (NEEDS CHECKING) - \synchronizeoutput % new may 2004 / we need to: \pagegoal\vsize - \checkendcolumnfootnotes - \dosomebreak\allowbreak - \page_floats_column_pop_saved} - %D Because some initializations happen three times, we defined a macro for %D them. Erasing \type{\everypar} is needed because we don't want anything %D to interfere. -\def\setmulticolumnsout +\unexpanded\def\page_mul_initialize_variables {\reseteverypar \dontcomplain \settopskip \setmaxdepth - \topskip1\topskip - \splittopskip\topskip - \splitmaxdepth\maxdepth - \boxmaxdepth\maxdepth % dangerous - \emergencystretch\zeropoint\relax} % sometimes needed ! + \topskip 1\topskip + \splittopskip \topskip + \splitmaxdepth \maxdepth + \boxmaxdepth \maxdepth % dangerous + \emergencystretch\zeropoint + \relax} % sometimes needed ! %D Flushing the page comes to pasting the columns together and appending the result -%D to box \type {\precolumnbox}, if not void. I've seen a lot of implementations in +%D to box \type {\b_page_mul_preceding}, if not void. I've seen a lot of implementations in %D which some skip was put between normal text and multi||column text. When we don't %D want this, the baselines can be messed up. I hope the seemingly complicated %D calculation of a correction \type {\kern} is adequate to overcome this. Although %D not watertight, spacing is taken into account and even multiple mode changes on %D one page go well. But cross your fingers and don't blame me. %D -%D One of the complications of flushing out the boxes is that \type {\precolumnbox} +%D One of the complications of flushing out the boxes is that \type {\b_page_mul_preceding} %D needs to be \type {\unvbox}'ed, otherwise there is too less flexibility in the %D page when using \type {\raggedbottom}. It took a lot of time before these kind of %D problems were overcome. Using \type {\unvbox} at the wrong moment can generate -%D \type {\balancingerror}'s. +%D \type {\page_mul_routine_error}'s. %D %D One can use the macros \type {\maxcolumnheight} and \type {\maxcolumndepth} when %D generating material between columns as well as postprocessing column lines. -\let\maxcolumnheight=\zeropoint -\let\maxcolumndepth =\zeropoint +\newdimen\maxcolumnheight +\newdimen\maxcolumndepth \newbox\columnpagebox -\def\setmaxcolumndimensions - {\let\maxcolumnheight\!!zeropoint - \let\maxcolumndepth \!!zeropoint - \dohandleallcolumns - {\ifdim\ht\currentcolumnbox>\maxcolumnheight - \edef\maxcolumnheight{\the\ht\currentcolumnbox}% - \fi - \ifdim\dp\currentcolumnbox>\maxcolumndepth - \edef\maxcolumndepth{\the\dp\currentcolumnbox}% - \fi}} +\def\page_mul_calculate_column_result_dimensions + {\maxcolumnheight\zeropoint + \maxcolumndepth \zeropoint + \dohandleallcolumnscs\page_mul_calculate_column_result_dimensions_step} + +\def\page_mul_calculate_column_result_dimensions_step + {\ifdim\ht\currentcolumnbox>\maxcolumnheight + \maxcolumnheight\ht\currentcolumnbox + \fi + \ifdim\dp\currentcolumnbox>\maxcolumndepth + \maxcolumndepth\dp\currentcolumnbox + \fi} \setnewconstant\multicolumntopflushmethod\plusone % 0: no correction, 1: correction when topstuff, 2: correction, 3: correction++ \setnewconstant\multicolumntopalignmethod\plustwo % 0: nothing, 1: force grid, 2: follow grid -\def\flushprecolumnboxnogrid - {\unvbox\precolumnbox} - -\def\flushprecolumnboxongrid - {\scratchdimen\savedpagetotal - \advance\scratchdimen -\ht\precolumnbox - \advance\scratchdimen -\dp\precolumnbox - \advance\scratchdimen -\topskip - \box\precolumnbox +\def\page_mul_flush_preceding_normal + {\unvbox\b_page_mul_preceding} + +\def\page_mul_flush_preceding_ongrid + {\scratchdimen\dimexpr + \savedpagetotal + -\ht\d_page_mul_preceding_height + -\dp\d_page_mul_preceding_depth + -\topskip + \relax + \box\b_page_mul_preceding \kern\scratchdimen} -\newconditional\someprecolumncontent +\def\page_mul_flush_packaged_columns_continued + {\bgroup + \page_mul_flush_packaged_columns_indeed + \box\columnpagebox + \egroup} -\def\flushcolumnedpage#1% +\def\page_mul_flush_packaged_columns_balanced {\bgroup - \ifvoid\precolumnbox - \setfalse\someprecolumncontent % will be set elsewhere + \page_mul_flush_packaged_columns_indeed + % messy correction, we need to rewrite this module (newcolumns) + \setbox\columnpagebox\vbox + {\offinterlineskip + \scratchdimen\ht\columnpagebox + \advance\scratchdimen\dp\columnpagebox % we probably lost that one already + \box\columnpagebox + \vskip-\scratchdimen}% + \scratchdimen\noflines\openlineheight + \advance\scratchdimen-\openstrutdepth + \ifgridsnapping + % quick hack (at least it works with itemize) + \else + \advance\scratchdimen-\openlineheight + \advance\scratchdimen\topskip + \fi + \ht\columnpagebox\scratchdimen + \dp\columnpagebox\openstrutdepth + % end of mess + \box\columnpagebox + \egroup} + +\def\page_mul_flush_packaged_columns_indeed + {\ifvoid\b_page_mul_preceding + \setfalse\c_page_mul_preceding_present % will be set elsewhere \else - \settrue\someprecolumncontent - \page_postprocessors_box\precolumnbox + \settrue\c_page_mul_preceding_present + \page_postprocessors_box\b_page_mul_preceding \fi \forgetall - \setmulticolumnsout - \setmaxcolumndimensions + \page_mul_initialize_variables + \page_mul_calculate_column_result_dimensions + \page_mul_postprocess_linenumbers \dohandleallcolumns {\page_postprocessors_column\currentcolumnbox}% \dohandleallcolumns {\page_marks_synchronize_column\plusone\nofcolumns\mofcolumns\currentcolumnbox}% - \postprocesscolumns + \page_mul_postprocess_lines + \page_mul_postprocess_columns \dohandleallcolumns - {\global\setbox\currentcolumnbox\hbox to \localcolumnwidth + {\global\setbox\currentcolumnbox\hbox to \d_page_mul_used_width {\box\currentcolumnbox}% - \wd\currentcolumnbox\localcolumnwidth + \wd\currentcolumnbox\d_page_mul_used_width \ifheightencolumns - \ht\currentcolumnbox\fixedcolumnheight + \ht\currentcolumnbox\d_page_mul_forced_height \fi}% - \setmaxcolumndimensions + \page_mul_calculate_column_result_dimensions \overlaycolumnfootnotes \setbox\columnpagebox\vbox - {\hbox to \finalcolumntextwidth - {\hskip\colleftskip\relax % new, \relax needed - \ifreversecolumns - \@EA\dohandlerevcolumns + {\hbox to \makeupwidth + {\hskip\d_page_mul_leftskip\relax % new, \relax needed + \ifconditional\c_page_mul_reverse + \expandafter\dohandlerevcolumns \else - \@EA\dohandleallcolumns + \expandafter\dohandleallcolumns \fi {\finishcolumnbox {\setbox\scratchbox\hbox {\ifx\finishcolumnbox\relax\else\strut\fi - \strut\box\currentcolumnbox}% + \box\currentcolumnbox}% hm, why strut \anch_mark_column_box\scratchbox \box\scratchbox}% \hfil}% \unskip - \hskip\colrightskip}}% new + \hskip\d_page_mul_rightskip}}% new \scratchdimen\zeropoint \dohandleallcolumns {\ifdim-\ht\currenttopcolumnbox<\scratchdimen @@ -506,31 +500,31 @@ \fi \global\setbox\currenttopcolumnbox\emptybox}% \advance\scratchdimen \ht\columnpagebox - \setbox\scratchbox\hbox to \columntextwidth + \setbox\scratchbox\hbox to \makeupwidth {\vrule \!!width\zeropoint \!!height\scratchdimen \!!depth\dp\columnpagebox - \dostepwiserecurse2\nofcolumns1{\hfil\betweencolumns}\hfil}% + \dostepwiserecurse\plustwo\nofcolumns\plusone{\hfil\page_mul_between_columns}\hfil}% \setbox\columnpagebox\hbox {\box\columnpagebox - \hskip-\columntextwidth + \hskip-\makeupwidth \box\scratchbox}% - \postprocesscolumnpagebox % new, acts upon \box\columnpagebox - \ifconditional\someprecolumncontent - \settrue\someprecolumncontent + \page_mul_postprocess_page + \ifconditional\c_page_mul_preceding_present + \settrue\c_page_mul_preceding_present % next some incredible crappy code \ifcase\multicolumntopalignmethod - \flushprecolumnboxnogrid % not on grid + \page_mul_flush_preceding_normal % not on grid \or - \flushprecolumnboxongrid % force on grid - \else\ifgridsnapping % somehow this junk fails in pascal - \flushprecolumnboxongrid % obey grid settings, force on grid + \page_mul_flush_preceding_ongrid % force on grid + \else\ifgridsnapping + \page_mul_flush_preceding_ongrid % obey grid settings, force on grid \else - \flushprecolumnboxnogrid % ignore grid settings, not on grid + \page_mul_flush_preceding_normal % ignore grid settings, not on grid \fi \fi \fi - \global\precolumnboxheight\zeropoint + \global\d_page_mul_preceding_height\zeropoint \page_otr_command_set_vsize \dosomebreak\nobreak % hm, only needed when topstuff \ifgridsnapping @@ -540,7 +534,7 @@ % when we run into it again \or % \input tufte \startcolumns \showbaselines \input tufte \stopcolumns \input tufte - \ifconditional\someprecolumncontent + \ifconditional\c_page_mul_preceding_present % \scratchdimen\topskip % \advance\scratchdimen -\openstrutheight % \nointerlineskip @@ -573,29 +567,7 @@ \dp\columnpagebox\zeropoint \global\finalcolumnheights\ht\columnpagebox \getnoflines\finalcolumnheights - \global\finalcolumnlines\noflines - \ifcase#1\else - % messy correction, we need to rewrite this module (newcolumns) - \setbox\columnpagebox\vbox - {\offinterlineskip - \scratchdimen\ht\columnpagebox - \advance\scratchdimen\dp\columnpagebox % we probably lost that one already - \box\columnpagebox - \vskip-\scratchdimen}% - \scratchdimen\noflines\openlineheight - \advance\scratchdimen-\openstrutdepth - \ifgridsnapping - % quick hack (at least it works with itemize) - \else - \advance\scratchdimen-\openlineheight - \advance\scratchdimen\topskip - \fi - \ht\columnpagebox\scratchdimen - \dp\columnpagebox\openstrutdepth - % end of mess - \fi - \box\columnpagebox - \egroup} + \global\finalcolumnlines\noflines} %D In case one didn't notice, finaly \type{\finishcolumnbox} is applied to %D all boxes. One can use these hooks for special purposes. @@ -639,51 +611,55 @@ %D %D {\getbuffer} %D -%D This feature is implemented using the reshape macros -%D presented in \type{supp-box}. - -\def\postprocesscolumns - {\ifx\postprocesscolumnline\undefined \else - \dohandleallcolumns - {\global\setbox\currentcolumnbox\vtop - {\beginofshapebox - \unvbox\currentcolumnbox - \unskip\unskip - \endofshapebox - \reshapebox - {\dimen0\ht\shapebox - \dimen2\dp\shapebox - \setbox\shapebox\hbox to \hsize - {\postprocesscolumnline\shapebox}% - \ht\shapebox\dimen0 - \dp\shapebox\dimen2 - \box\shapebox}% - \flushshapebox - \reseteverypar - \parskip\zeropoint % = \forgetall - \verticalstrut - \vskip-\struttotal - \vfil}}% - \fi - \ifx\postprocesscolumnbox\undefined \else - \dohandleallcolumns - {\global\setbox\currentcolumnbox\hbox - {\postprocesscolumnbox\currentcolumnbox}} - \fi} - -%D We default to doing nothing! - -\let\postprocesscolumnline =\undefined -\let\postprocesscolumnbox =\undefined -\let\postprocesscolumnpagebox=\relax - -%D \macros -%D {reversecolumnstrue} -%D -%D We can force the macro that takes care of combining the columns, to -%D flush them in the revere order. Of course, by default we don't reverse. - -\newif\ifreversecolumns +%D This feature is implemented using the reshape macros presented +%D in \type{supp-box}. + +\ifdefined\page_postprocessors_column\else\let\page_postprocessors_column\relax\fi % operates on passed box +\ifdefined\postprocesscolumnline \else\let\postprocesscolumnline \relax\fi % operates on passed box +\ifdefined\postprocesscolumnbox \else\let\postprocesscolumnbox \relax\fi % operates on passed box +\ifdefined\postprocesscolumnpagebox \else\let\postprocesscolumnpagebox \relax\fi % operates on passed box + +\def\page_mul_postprocess_linenumbers{\ifx\page_postprocessors_column\relax\else\page_mul_postprocess_linenumbers_indeed\fi} +\def\page_mul_postprocess_lines {\ifx\postprocesscolumnline \relax\else\page_mul_postprocess_lines_indeed \fi} +\def\page_mul_postprocess_columns {\ifx\postprocesscolumnbox \relax\else\page_mul_postprocess_columns_indeed \fi} +\def\page_mul_postprocess_page {\ifx\postprocesscolumnpagebox \relax\else\page_mul_postprocess_page_indeed \fi} + +\def\page_mul_postprocess_linenumbers_indeed + {\dohandleallcolumns{\page_postprocessors_column\currentcolumnbox}} + +\def\page_mul_postprocess_lines_indeed + {\dohandleallcolumnscs\page_mul_postprocess_lines_step} + +\def\page_mul_postprocess_lines_step % TODO: use lua solution instead + {\global\setbox\currentcolumnbox\vtop + {\beginofshapebox + \unvbox\currentcolumnbox + \unskip\unskip + \endofshapebox + \reshapebox + {\scratchheight\ht\shapebox + \scratchdepth \dp\shapebox + \setbox\shapebox\hbox to \hsize + {\postprocesscolumnline\shapebox}% + \ht\shapebox\scratchheight + \dp\shapebox\scratchdepth + \box\shapebox}% + \flushshapebox + \reseteverypar + \parskip\zeropoint % = \forgetall + \verticalstrut + \vskip-\struttotal + \vfil}} + +\def\page_mul_postprocess_columns_indeed + {\dohandleallcolumnscs\page_mul_postprocess_columns_step} + +\def\page_mul_postprocess_columns_step + {\global\setbox\currentcolumnbox\hbox + {\postprocesscolumnbox\currentcolumnbox}} + +\def\page_mul_postprocess_page_indeed + {\postprocesscolumnpagebox\columnpagebox} %D Here comes the simple splitting routine. It's a bit longer than expected because %D of ragging bottoms or not. This part can be a bit shorter but I suppose that I @@ -693,46 +669,48 @@ %D First we present some auxiliary routines. Any material, like for instance floats, %D that is already present in the boxes is preserved. -\def\splitcolumn#1from \box#2to \dimen#3 top \box#4% +\newdimen\d_page_mul_split_height_used +\newdimen\d_page_mul_split_height_max + +\def\page_mul_split_column#1#2#3#4% copy or box {\bgroup \ifdim\ht#4>\zeropoint - \dimen0\dimen#3\relax - \dimen2\dimen0 - \advance\dimen0 -\ht#4% - \columnfootnotecorrection{#1}{\dimen0}% - \setbox0\vsplit#2 to \dimen0 - \global\setbox#1\vbox to \dimen2 + \d_page_mul_split_height_used#3\relax + \d_page_mul_split_height_max\d_page_mul_split_height_used + \advance\d_page_mul_split_height_used -\ht#4% + \columnfootnotecorrection{#1}\d_page_mul_split_height_used + \setbox\scratchbox\vsplit#2 to \d_page_mul_split_height_used + \global\setbox#1\vbox to \d_page_mul_split_height_max {\ifgridsnapping - \dimen0-\openstrutheight - \advance\dimen0 \topskip - \vskip\dimen0\copy#4\vskip-\dimen0 + \scratchdimen\dimexpr\topskip-\openstrutheight\relax + \vskip\scratchdimen + \copy#4% + \vskip-\scratchdimen \else \unvcopy#4% \fi - \fuzzysnappedbox\unvbox0 + \fuzzysnappedbox\unvbox\scratchbox \fakecolumnfootnotes{#1}}% + \else\ifcase\c_strc_notes_page_location + \global\setbox#1\vsplit#2 to #3% + \global\setbox#1\vbox + {\fuzzysnappedbox\unvbox{#1}}% % or \box ? \else - \ifcase\c_strc_notes_page_location - \global\setbox#1\vsplit#2 to \dimen#3% - \global\setbox#1\vbox - {\fuzzysnappedbox\unvbox{#1}}% % or \box ? - \else - \columnfootnotecorrection{#1}{\dimen#3}% - \setbox0\vsplit#2 to \dimen#3% - \global\setbox#1\vbox to \dimen#3% - {\fuzzysnappedbox\unvbox0 - \fakecolumnfootnotes{#1}}% - \fi - \fi + \columnfootnotecorrection{#1}{#3}% + \setbox\scratchbox\vsplit#2 to #3% + \global\setbox#1\vbox to #3% + {\fuzzysnappedbox\unvbox\scratchbox + \fakecolumnfootnotes{#1}}% + \fi \fi \egroup} -\def\splitcurrentcolumn from \box#1to \dimen#2% - {\splitcolumn\currentcolumnbox from \box#1 to \dimen#2 top \box\currenttopcolumnbox} +\def\page_mul_split_current_column#1#2% + {\page_mul_split_column\currentcolumnbox{#1}{#2}\currenttopcolumnbox} -\def\splitfirstcolumn from \box#1to \dimen#2% - {\splitcolumn\firstcolumnbox from \box#1 to \dimen#2 top \box\firsttopcolumnbox} +\def\page_mul_split_first_column#1#2% + {\page_mul_split_column\firstcolumnbox{#1}{#2}\firsttopcolumnbox} -\def\splitlastcolumn from \box#1to \dimen#2% +\def\page_mul_split_last_column#1#2% {\global\setbox\lastcolumnbox\vbox {\unvcopy\lasttopcolumnbox \fuzzysnappedbox\unvbox{#1}% @@ -740,128 +718,130 @@ %D NEW: still to be documented. -\def\fakecolumnfootnotes#1% - {\relax - \ifcase\c_strc_notes_page_location\else - \ifnum#1=\lastcolumnbox - \fakenotes - \fi - \fi} - -\def\columnfootnotecorrection#1#2% - {\relax - \ifcase\c_strc_notes_page_location - % page notes - \or - \ifnum#1=\firstcolumnbox\relax - \calculatetotalclevernoteheight - \advance#2 -\totalnoteheight - \fi - \else - \ifnum#1=\lastcolumnbox\relax - \calculatetotalclevernoteheight - \advance#2 -\totalnoteheight - \fi - \fi} - -\def\overlaycolumnfootnotes - {\relax - \ifcase\c_strc_notes_page_location - % page - \or - \checknotepresence \ifnotespresent \page_mul_notes_flush_first_column \fi - \or - \checknotepresence \ifnotespresent \page_mul_notes_flush_last_column \fi - \fi} - -\newbox\b_page_mul_notes - -\def\page_mul_notes_flush_first_column - {\begingroup - \setbox\b_page_mul_notes\vbox{\placenoteinserts}% - \ifzeropt\ht\b_page_mul_notes - % can't happen as we already checked - \else - \getmulticolumnlines - \advance\nofcolumnlines \minustwo - \scratchdimen\dimexpr\nofcolumnlines\lineheight+\topskip\relax - \setbox\b_page_mul_notes\hbox{\lower\scratchdimen\box\b_page_mul_notes}% - \ht\b_page_mul_notes\openstrutheight - \dp\b_page_mul_notes\openstrutdepth - \wd\b_page_mul_notes\zeropoint - \scratchdimen\ht\firstcolumnbox - \global\setbox\firstcolumnbox\vbox to \scratchdimen - {\box\firstcolumnbox - \vskip-\scratchdimen - \box\b_page_mul_notes}% - \fi - \endgroup} + \def\fakecolumnfootnotes#1% + {\relax + \ifcase\c_strc_notes_page_location\else + \ifnum#1=\lastcolumnbox + \fakenotes + \fi + \fi} + + \def\columnfootnotecorrection#1#2% + {\relax + \ifcase\c_strc_notes_page_location + % page notes + \or + \ifnum#1=\firstcolumnbox\relax + \calculatetotalclevernoteheight + \advance#2 -\totalnoteheight + \fi + \else + \ifnum#1=\lastcolumnbox\relax + \calculatetotalclevernoteheight + \advance#2 -\totalnoteheight + \fi + \fi} + + \def\overlaycolumnfootnotes + {\relax + \ifcase\c_strc_notes_page_location + % page + \or + \checknotepresence \ifnotespresent \page_mul_notes_flush_first_column \fi + \or + \checknotepresence \ifnotespresent \page_mul_notes_flush_last_column \fi + \fi} + + \newbox\b_page_mul_notes + + \def\page_mul_notes_flush_first_column + {\begingroup + \setbox\b_page_mul_notes\vbox{\placenoteinserts}% + \ifzeropt\ht\b_page_mul_notes + % can't happen as we already checked + \else + \page_mul_set_n_of_lines + \advance\c_page_mul_n_of_lines \minustwo + \scratchdimen\dimexpr\c_page_mul_n_of_lines\lineheight+\topskip\relax + \setbox\b_page_mul_notes\hbox{\lower\scratchdimen\box\b_page_mul_notes}% + \ht\b_page_mul_notes\openstrutheight + \dp\b_page_mul_notes\openstrutdepth + \wd\b_page_mul_notes\zeropoint + \scratchdimen\ht\firstcolumnbox + \global\setbox\firstcolumnbox\vbox to \scratchdimen + {\box\firstcolumnbox + \vskip-\scratchdimen + \box\b_page_mul_notes}% + \fi + \endgroup} -\def\page_mul_notes_flush_last_column - {\begingroup - \setbox\b_page_mul_notes\vbox{\placenoteinserts}% - \ifzeropt\ht\b_page_mul_notes - % can't happen as we already checked - \else - % maybe here also \getmulticolumnlines - \scratchdimen\dimexpr\ht\firstcolumnbox-\openstrutdepth\relax % \strutdp - \getnoflines\scratchdimen - \advance\noflines \minustwo - \scratchdimen\dimexpr\noflines\lineheight+\topskip\relax - \setbox\b_page_mul_notes\hbox{\lower\scratchdimen\box\b_page_mul_notes}% - \ht\b_page_mul_notes\openstrutheight - \dp\b_page_mul_notes\openstrutdepth - \wd\b_page_mul_notes\zeropoint - \scratchdimen\ht\lastcolumnbox - \global\setbox\lastcolumnbox\vbox to \scratchdimen - {\box\lastcolumnbox - \vskip-\scratchdimen - \box\b_page_mul_notes}% - \fi - \endgroup} + \def\page_mul_notes_flush_last_column + {\begingroup + \setbox\b_page_mul_notes\vbox{\placenoteinserts}% + \ifzeropt\ht\b_page_mul_notes + % can't happen as we already checked + \else + % maybe here also \page_mul_set_n_of_lines + \scratchdimen\dimexpr\ht\firstcolumnbox-\openstrutdepth\relax % \strutdp + \getnoflines\scratchdimen + \advance\noflines \minustwo + \scratchdimen\dimexpr\noflines\lineheight+\topskip\relax + \setbox\b_page_mul_notes\hbox{\lower\scratchdimen\box\b_page_mul_notes}% + \ht\b_page_mul_notes\openstrutheight + \dp\b_page_mul_notes\openstrutdepth + \wd\b_page_mul_notes\zeropoint + \scratchdimen\ht\lastcolumnbox + \global\setbox\lastcolumnbox\vbox to \scratchdimen + {\box\lastcolumnbox + \vskip-\scratchdimen + \box\b_page_mul_notes}% + \fi + \endgroup} %D Here comes the routine that splits the long box in columns. The macro \type -%D {\flushcolumnfloats} can be used to flush either floats that were present before +%D {\page_mul_flush_floats} can be used to flush either floats that were present before %D the multi||column mode was entered, or floats that migrate to next columns. %D Flushing floats is a delicate process. -\def\continuousmulticolumnsout +\def\page_mul_routine_continue {\bgroup \forgetall - \setmulticolumnsout -% \dimen0=\columntextheight -% \advance\dimen0 -\precolumnboxheight -% \settotalinsertionheight -% \advance\dimen0 -\totalinsertionheight -% \ifgridsnapping % evt altijd, nog testen -% \getnoflines{\dimen0} -% \dimen0=\noflines\openlineheight -% \fi - \getmulticolumnlines - \dimen0=\nofcolumnlines\openlineheight + \page_mul_initialize_variables + % \dimen0=\makeupheight + % \advance\dimen0 -\d_page_mul_preceding_height + % \settotalinsertionheight + % \advance\dimen0 -\totalinsertionheight + % \ifgridsnapping % evt altijd, nog testen + % \getnoflines{\dimen0} + % \dimen0=\noflines\openlineheight + % \fi + \page_mul_set_n_of_lines + \d_page_mul_balance_target\c_page_mul_n_of_lines\openlineheight + \ifconditional\c_page_mul_trace + \writestatus\m!columns{continue: lines=\the\c_page_mul_n_of_lines, target=\the\d_page_mul_balance_target, textheight=\the\textheight}% + \fi \dohandleallcolumns - {\splitcurrentcolumn from \box\normalpagebox to \dimen0}% - \setbox\restofpage\vbox{\unvbox\normalpagebox}% + {\page_mul_split_current_column\normalpagebox\d_page_mul_balance_target}% + \setbox\b_page_mul_preceding_rest_of_page\vbox{\unvbox\normalpagebox}% \ifinheritcolumns \ifcase\bottomraggednessmode % 0 = ragged \dohandleallcolumns {\global\setbox\currentcolumnbox\vbox to \ht\firstcolumnbox - {\dimen0\dp\currentcolumnbox + {\scratchdepth\dp\currentcolumnbox \unvbox\currentcolumnbox - \vskip-\dimen0 - \vskip\openstrutdepth % \strutdp + \vskip\dimexpr\openstrutdepth-\scratchdepth\relax \prevdepth\openstrutdepth % \strutdp \vfill}}% \strc_notes_check_if_bottom_present - \ifconditional\c_notes_bottom_present \else - \dimen0\ht\firstcolumnbox - \fi + %\ifconditional\c_notes_bottom_present \else + % \dimen0\ht\firstcolumnbox % ?? + %\fi \or % 1 = normal - \advance\dimen0 \maxdepth + \advance\d_page_mul_balance_target\maxdepth \dohandleallcolumns - {\global\setbox\currentcolumnbox\vbox to \dimen0 + {\global\setbox\currentcolumnbox\vbox to \d_page_mul_balance_target {\unvbox\currentcolumnbox}}% \or % 2 = baseline @@ -869,7 +849,7 @@ \fi \else \dohandleallcolumns - {\global\setbox\currentcolumnbox\vbox to \dimen0 + {\global\setbox\currentcolumnbox\vbox to \d_page_mul_balance_target {\ifstretchcolumns \unvbox\currentcolumnbox \else @@ -877,14 +857,14 @@ \vfill \fi}}% \dohandleallcolumns - {\ht\currentcolumnbox\dimen0}% redundant + {\ht\currentcolumnbox\d_page_mul_balance_target}% redundant \fi - \setbox\precolumnbox\vbox{\flushcolumnedpage\zerocount}% - \page_otr_construct_and_shipout\box\precolumnbox + \setbox\b_page_mul_preceding\vbox{\page_mul_flush_packaged_columns_continued}% + \page_otr_construct_and_shipout\box\b_page_mul_preceding \page_otr_command_set_hsize \page_otr_command_set_vsize - \flushcolumnfloats - \unvbox\restofpage + \page_mul_flush_floats + \unvbox\b_page_mul_preceding_rest_of_page % \penalty\outputpenalty % gaat gruwelijk mis in opsommingen \egroup} @@ -894,161 +874,184 @@ %D balance columns with few lines. The use of \type {\box2} and \type {\box4} %D garantees a more robust check when skips are used. -\def\multicolumnsbalancemax{250} % 100 is too small when floats are involved - -\def\balancedmulticolumnsout +\newbox \b_page_mul_balance_content +\newbox \b_page_mul_balance_first_column +\newbox \b_page_mul_balance_column +\newconstant \c_page_mul_balance_tries_max +\newcount \c_page_mul_balance_tries +\newdimen \d_page_mul_balance_target +\newdimen \d_page_mul_balance_target_less +\newdimen \d_page_mul_balance_natural_height +\newdimen \d_page_mul_balance_regular_height +\newdimen \d_page_mul_balance_step +\newdimen \d_page_mul_balance_fuzzyness +\newdimen \d_page_mul_balance_threshold +\newconditional\c_page_mul_balance_possible + +\c_page_mul_balance_tries_max 250 % 100 is too small when floats are involved + +\def\page_mul_routine_balance {\bgroup - \setmulticolumnsout + \page_mul_initialize_variables \widowpenalty\zerocount - \setbox0\vbox{\unvbox\normalpagebox}% - \ifdim\ht0>\openlineheight % at least one line - \ifnum\minbalancetoplines<2 % balance anyway - \donetrue + \setbox\b_page_mul_balance_content\vbox{\unvbox\normalpagebox}% + \ifdim\ht\b_page_mul_balance_content>\openlineheight % at least one line + \ifnum\c_page_mul_balance_minimum<\plustwo % balance anyway + \settrue\c_page_mul_balance_possible \else % check criterium to available lines - \getnoflines{\ht0}% + \getnoflines{\ht\b_page_mul_balance_content}% \divide\noflines \nofcolumns \relax - \ifnum\noflines<\minbalancetoplines \relax - % let's play safe - \ifdim\dimexpr\ht0+\ht\firsttopcolumnbox+\openlineheight\relax>\columntextheight - \donetrue % column exceeding text height + \ifnum\noflines<\c_page_mul_balance_minimum \relax + \ifdim\dimexpr\ht\b_page_mul_balance_content+\ht\firsttopcolumnbox+\openlineheight\relax>\makeupheight + \settrue\c_page_mul_balance_possible % column exceeding text height \else - \donefalse % it seems to fit + \setfalse\c_page_mul_balance_possible % it seems to fit \fi - \else % balance indeed - \donetrue + \else + \settrue\c_page_mul_balance_possible % balance indeed \fi \fi - \else % balancing does not make sense - \donefalse + \else + \setfalse\c_page_mul_balance_possible % balancing does not make sense \fi - \ifdone % start balancing, was: \ifdim\ht0>\openlineheight - \dimen0\ht0 - \advance\dimen0 \topskip - \advance\dimen0 -\baselineskip - \dohandleallcolumns - {\advance\dimen0 \ht\currenttopcolumnbox}% - \divide\dimen0 \nofcolumns - \vbadness\plustenthousand - \count255=\zerocount - \bgroup - \ifgridsnapping - \dimen2\lineheight - \else - \dimen2=\onepoint % RUBISH - \dimen2=\spacingfactor\dimen2 - \fi - \doloop - {\advance\count255 \plusone - \global\setbox\restofpage\copy0\relax - \splitfirstcolumn from \box\restofpage to \dimen0 - \dohandlemidcolumns - {\splitcurrentcolumn from \box\restofpage to \dimen0}% - \splitlastcolumn from \box\restofpage to \dimen0 - \setbox2\vbox{\unvcopy\firstcolumnbox}% - \dimen4\zeropoint - \dohandleallcolumns - {\setbox4\vbox - {\unvcopy\currentcolumnbox - %rather new, test this on pdftex-z.tex - \unpenalty\unskip\unpenalty\unskip}% maybe better in main splitter - %\writestatus{balance}{\the\currentcolumnbox: \the\ht4}% -% \dimen6\ht4 \ifdim\dimen6>\dimen4 \dimen4=\dimen6 \fi}% - \ifdim\ht4>\dimen4 \dimen4=\ht4 \fi}% - \advance\dimen4 -.0005pt % get rid of accurracy problem, pretty new - \ifnum\count255>\multicolumnsbalancemax\relax - \exitloop - \else\ifdim\dimen4>\ht2 - \advance\dimen0 \dimen2\relax - \else - \exitloop - \fi\fi}% - \dohandleallcolumns - {\global\setbox\currentcolumnbox\vbox{\unvcopy\currentcolumnbox}}% NIEUW - \ifnum\count255>\multicolumnsbalancemax\relax - \showmessage\m!columns7\empty - \else - \showmessage\m!columns8{\the\count255\space}% - \fi - \egroup + \ifconditional\c_page_mul_balance_possible % start balancing, was: \ifdim\ht\b_page_mul_balance_content>\openlineheight + \page_mul_balance_try_one \ifinheritcolumns - % We cannot assume that the first column is the tallest, if - % only because we may have an aborted balance (one line in the - % first column and a graphic in the second one). - % - % \dimen0\ht\firstcolumnbox - % \dimen2\ht\firstcolumnbox - % - \dimen0=\zeropoint - \dohandleallcolumns - {\ifdim\ht\currentcolumnbox>\dimen0 - \dimen0=\ht\currentcolumnbox - \fi}% - \dimen2\dimen0 - % so far - \advance\dimen2 -\openlineheight - \dohandleallcolumns - {\dimen4\ht\currentcolumnbox - \dimen6=10\openlineheight % funny value - \global\setbox\currentcolumnbox\vbox to \dimen0 - {\unvbox\currentcolumnbox - \ifdim\dimen4>\dimen6 - \ifdim\dimen4<\dimen0 - \ifdim\dimen4>\dimen2 - \vskip\zeropoint % !! - \else - \vskip\openlineheight - \vfill - \fi - \else - \vskip\zeropoint - \fi - \else - \vskip\openlineheight - \vfill - \fi}}% + \page_mul_balance_try_two \else - \bgroup - \ifstretchcolumns - \dimen0\ht\firstcolumnbox - \dimen2=\bottomtolerance\ht\firstcolumnbox - \setbox0\vbox{\unvcopy\lastcolumnbox}% - \advance\dimen0 -\ht0\relax - \advance\dimen0 -\dp0\relax - \ifdim\dimen0>\openlineheight\relax - \ifdim\dimen0>\dimen2\relax - % \stretchcolumnsfalse % beter goed slecht dan slecht goed - \showmessage\m!columns9\empty - \fi - \fi - \fi - \dohandleallcolumns - {\global\setbox\currentcolumnbox\vbox to \ht\firstcolumnbox - {\ifstretchcolumns - \unvbox\currentcolumnbox - \else - \box\currentcolumnbox - \vfill - \fi}}% - \egroup + \page_mul_balance_try_three \fi \else % a one liner is not properly handled here, so best rewrite the text then \showmessage\m!columns{10}\empty - \global\setbox\firstcolumnbox\vbox{\unvbox0}% + \global\setbox\firstcolumnbox\vbox{\unvbox\b_page_mul_balance_content}% \fi \c_page_mul_routine\c_page_mul_routine_error \baselinebottom % forces depth in separation rule - \flushcolumnedpage\plusone - \multicolumnseject + \page_mul_flush_packaged_columns_balanced + \page_mul_eject_page \egroup} -\def\multicolumnseject +\def\page_mul_eject_page {%\ifdim\pagetotal>\textheight % \page_otr_trigger_output_routine % new, but wrong as fails on mixed-001.tex (wrong pagetotal at this point) %\else \allowbreak }%\fi} +\def\page_mul_balance_try_one + {\d_page_mul_balance_target\dimexpr\ht\b_page_mul_balance_content+\topskip-\baselineskip\relax + \dohandleallcolumns + {\advance\d_page_mul_balance_target \ht\currenttopcolumnbox}% + \divide\d_page_mul_balance_target \nofcolumns + \vbadness\plustenthousand + \c_page_mul_balance_tries\zerocount + \bgroup + \ifgridsnapping + \d_page_mul_balance_step\lineheight + \else + \d_page_mul_balance_step\spacingfactor\onepoint % rubish + \fi + \doloop\page_mul_balance_try_one_attempt + \dohandleallcolumns + {\global\setbox\currentcolumnbox\vbox{\unvcopy\currentcolumnbox}}% + \ifnum\c_page_mul_balance_tries>\c_page_mul_balance_tries_max\relax + \showmessage\m!columns7\empty + \else + \showmessage\m!columns8{\the\c_page_mul_balance_tries\space}% + \fi + \egroup} + +\def\page_mul_balance_try_one_attempt + {\advance\c_page_mul_balance_tries \plusone + \global\setbox\b_page_mul_preceding_rest_of_page\copy\b_page_mul_balance_content\relax + \page_mul_split_first_column\b_page_mul_preceding_rest_of_page\d_page_mul_balance_target + \dohandlemidcolumns + {\page_mul_split_current_column\b_page_mul_preceding_rest_of_page\d_page_mul_balance_target}% + \page_mul_split_last_column\b_page_mul_preceding_rest_of_page\d_page_mul_balance_target + \setbox\b_page_mul_balance_first_column\vbox{\unvcopy\firstcolumnbox}% + \d_page_mul_balance_natural_height\zeropoint + \dohandleallcolumns\page_mul_balance_try_one_attempt_step + \advance\d_page_mul_balance_natural_height -.0005pt % (33sp) get rid of accurracy problem, pretty new + \ifnum\c_page_mul_balance_tries>\c_page_mul_balance_tries_max\relax + \exitloop + \else\ifdim\d_page_mul_balance_natural_height>\ht\b_page_mul_balance_first_column + \advance\d_page_mul_balance_target \d_page_mul_balance_step\relax + \else + \exitloop + \fi\fi} + +\def\page_mul_balance_try_one_attempt_step + {\setbox\b_page_mul_balance_column\vbox + {\unvcopy\currentcolumnbox + \unpenalty + \unskip + \unpenalty + \unskip}% maybe better in main splitter + \ifdim\ht\b_page_mul_balance_column>\d_page_mul_balance_natural_height + \d_page_mul_balance_natural_height\ht\b_page_mul_balance_column + \fi} + +% We cannot assume that the first column is the tallest, if only because we may +% have an aborted balance (one line in the first column and a graphic in the +% second one). + +\def\page_mul_balance_try_two + {\d_page_mul_balance_target\zeropoint + \dohandleallcolumns + {\ifdim\ht\currentcolumnbox>\d_page_mul_balance_target + \d_page_mul_balance_target\ht\currentcolumnbox + \fi}% + \d_page_mul_balance_target_less\dimexpr\d_page_mul_balance_target-\openlineheight\relax + \dohandleallcolumnscs\page_mul_balance_try_two_step} + +\def\page_mul_balance_try_two_step + {\d_page_mul_balance_regular_height\ht\currentcolumnbox + \d_page_mul_balance_threshold\plusten\openlineheight % funny value + \global\setbox\currentcolumnbox\vbox to \d_page_mul_balance_target + {\unvbox\currentcolumnbox + \ifdim\d_page_mul_balance_regular_height>\d_page_mul_balance_threshold + \ifdim\d_page_mul_balance_regular_height<\d_page_mul_balance_target + \ifdim\d_page_mul_balance_regular_height>\d_page_mul_balance_target_less + \vskip\zeropoint % !! + \else + \vskip\openlineheight + \vfill + \fi + \else + \vskip\zeropoint + \fi + \else + \vskip\openlineheight + \vfill + \fi}} + +\def\page_mul_balance_try_three + {\bgroup + \ifstretchcolumns + \d_page_mul_balance_target\ht\firstcolumnbox + \d_page_mul_balance_fuzzyness\bottomtolerance\ht\firstcolumnbox + \setbox\b_page_mul_balance_content\vbox{\unvcopy\lastcolumnbox}% + \advance\d_page_mul_balance_target-\htdp\b_page_mul_balance_content\relax + \ifdim\d_page_mul_balance_target>\openlineheight\relax + \ifdim\d_page_mul_balance_target>\d_page_mul_balance_fuzzyness\relax + % \stretchcolumnsfalse % beter good bad than bad good + \showmessage\m!columns9\empty + \fi + \fi + \fi + \dohandleallcolumnscs\page_mul_balance_try_three_step + \egroup} + +\def\page_mul_balance_try_three_step + {\global\setbox\currentcolumnbox\vbox to \ht\firstcolumnbox + {\ifstretchcolumns + \unvbox\currentcolumnbox + \else + \box\currentcolumnbox + \vfill + \fi}} + %D The multicolumn mechanism is incorporated in a \CONTEXT\ interface, %D which acts like: %D @@ -1105,7 +1108,7 @@ % % \let\page_floats_column_pop_saved\relax -% \def\setcolumnfloats % messy as it adapts everypar +% \def\page_mul_initialize_floats % messy as it adapts everypar % {\xdef\globalsavednoffloats{\the\savednoffloats}% % \ifnum\globalsavednoffloats>\zerocount % \setglobalcolumnfloats % hm, we always push so this never happens @@ -1113,66 +1116,66 @@ % \setlocalcolumnfloats % \fi} -\def\setcolumnfloats % messy as it adapts everypar, we need to adapt this - {\setlocalcolumnfloats} - -\newconditional\onlylocalcolumnfloats % temp hack as we will redo floats (grid snapping is also messy now) - -\unexpanded\def\page_mul_command_flush_floats - {\ifconditional\onlylocalcolumnfloats - \doflushcolumnfloats - \else - \page_one_command_flush_floats - \fi} + \def\page_mul_initialize_floats % messy as it adapts everypar, we need to adapt this + {\setlocalcolumnfloats} -\unexpanded\def\page_mul_command_check_if_float_fits - {\ifconditional\onlylocalcolumnfloats - \docolumnroomfloat - \fi} + \newconditional\onlylocalcolumnfloats % temp hack as we will redo floats (grid snapping is also messy now) + \newtoks \everylocalcolumnfloatspar -\unexpanded\def\page_mul_command_flush_saved_floats - {\ifconditional\onlylocalcolumnfloats\relax - \else - \page_one_command_flush_saved_floats - \fi} - -\unexpanded\def\page_mul_command_flush_top_insertions - {\ifconditional\onlylocalcolumnfloats\relax - \else - \page_one_command_flush_top_insertions - \fi} - -\newtoks\everylocalcolumnfloatspar - -\everylocalcolumnfloatspar - {\flushnotes - \flushcolumnfloat - % \flushmargincontents - \checkindentation} + \unexpanded\def\page_mul_command_flush_floats + {\ifconditional\onlylocalcolumnfloats + \doflushcolumnfloats + \else + \page_one_command_flush_floats + \fi} -\def\setlocalcolumnfloats - {\settrue\onlylocalcolumnfloats - \everypar\everylocalcolumnfloatspar - \let\flushcolumnfloat\doflushcolumnfloat - \let\flushcolumnfloats\doflushcolumnfloats} + \unexpanded\def\page_mul_command_check_if_float_fits + {\ifconditional\onlylocalcolumnfloats + \docolumnroomfloat + \fi} -\def\setglobalcolumnfloats - {\setfalse\onlylocalcolumnfloats - \reseteverypar - \let\flushcolumnfloat\relax - \let\flushcolumnfloats\noflushcolumnfloats} + \unexpanded\def\page_mul_command_flush_saved_floats + {\ifconditional\onlylocalcolumnfloats\relax + \else + \page_one_command_flush_saved_floats + \fi} -\def\noflushcolumnfloats - {\bgroup - \xdef\localsavednoffloats{\the\savednoffloats}% - \global\savednoffloats\globalsavednoffloats - \page_otr_command_flush_top_insertions - \xdef\globalsavenoffloats{\the\savednoffloats}% - \ifnum\globalsavednoffloats=\zerocount - \setlocalcolumnfloats - \fi - \global\savednoffloats\localsavednoffloats - \egroup} + \unexpanded\def\page_mul_command_flush_top_insertions + {\ifconditional\onlylocalcolumnfloats\relax + \else + \page_one_command_flush_top_insertions + \fi} + + \appendtoks + \flushnotes + \page_mul_flush_float + %\flushmargincontents + \checkindentation + \to \everylocalcolumnfloatspar + + \def\setlocalcolumnfloats + {\settrue\onlylocalcolumnfloats + \everypar\everylocalcolumnfloatspar + \let\page_mul_flush_float\doflushcolumnfloat + \let\page_mul_flush_floats\doflushcolumnfloats} + + \def\setglobalcolumnfloats + {\setfalse\onlylocalcolumnfloats + \reseteverypar + \let\page_mul_flush_float\relax + \let\page_mul_flush_floats\noflushcolumnfloats} + + \def\noflushcolumnfloats + {\bgroup + \xdef\localsavednoffloats{\the\savednoffloats}% + \global\savednoffloats\globalsavednoffloats + \page_otr_command_flush_top_insertions + \xdef\globalsavenoffloats{\the\savednoffloats}% + \ifnum\globalsavednoffloats=\zerocount + \setlocalcolumnfloats + \fi + \global\savednoffloats\localsavednoffloats + \egroup} %D We need to calculate the amount of free space in a columns. When there is not %D enough room, we migrate the float to the next column. These macro's are @@ -1181,124 +1184,124 @@ %D floats have to be taken into account when we calculate the available space. It's %D a pitty that such things are no integral part of \TEX. -\def\getcolumnstatus\column#1\total#2\goal#3\\% - {\dimen0=\ifdim\pagegoal<\maxdimen \pagetotal \else \zeropoint \fi - \dimen2=\zeropoint - \count255=\zerocount - \dimen8=\columntextheight - \advance\dimen8 -\precolumnboxheight - \def\dogetcolumnstatus - {\advance\count255 \plusone - \advance\dimen2 \ht\currenttopcolumnbox - \advance\dimen2 \dp\currenttopcolumnbox - \dimen4\dimen2 - \advance\dimen4 \dimen0 - \dimen6=\count255\dimen8 - \ifdim\dimen4>\dimen6 - \else - \let\dogetcolumnstatus\relax - \fi}% - \dohandleallcolumns{\dogetcolumnstatus}% - \ifnum\count255=0 \count255=1 \fi - #1=\count255 - #2=\dimen4 - #3=\dimen6 } - -\def\getinsertionheight - {\ifdim\pagegoal<\maxdimen - \bgroup - \dimen0=\columntextheight - \advance\dimen0 -\pagegoal - \xdef\insertionheight{\the\dimen0}% - \egroup - \else - \global\let\insertionheight\zeropoint - \fi} - -\def\docolumnroomfloat - {\ifpostponecolumnfloats - \global\setfalse\c_page_floats_room - \else\ifconditional\c_page_floats_not_permitted - \global\setfalse\c_page_floats_room - \else - \bgroup - \getcolumnstatus\column\count255\total\dimen0\goal\dimen2\\% - \page_floats_get_info\s!text - \setbox\scratchbox\vbox % tricky met objecten ? - {\blank[\rootfloatparameter\c!spacebefore] - \snaptogrid\vbox{\vskip\floatheight}}% copy? - \advance\dimen0\dimexpr\ht\scratchbox+2\openlineheight+.5\lineheight\relax\relax % needed because goal a bit higher - \ifdim\dimen0>\dimen2 - \global\setfalse\c_page_floats_room - \else - \global\settrue\c_page_floats_room - \fi - \ifdim\floatwidth>\hsize - \showmessage\m!columns{11}\empty - \global\setfalse\c_page_floats_room - \fi - \egroup - \fi\fi} + \def\getcolumnstatus#1#2#3% + {\dimen0=\ifdim\pagegoal<\maxdimen \pagetotal \else \zeropoint \fi + \dimen2=\zeropoint + \count255=\zerocount + \dimen8=\makeupheight + \advance\dimen8 -\d_page_mul_preceding_height + \def\dogetcolumnstatus + {\advance\count255 \plusone + \advance\dimen2 \ht\currenttopcolumnbox + \advance\dimen2 \dp\currenttopcolumnbox + \dimen4\dimen2 + \advance\dimen4 \dimen0 + \dimen6=\count255\dimen8 + \ifdim\dimen4>\dimen6 + \else + \let\dogetcolumnstatus\relax + \fi}% + \dohandleallcolumns{\dogetcolumnstatus}% + \ifnum\count255=0 \count255=1 \fi + #1=\count255 + #2=\dimen4 + #3=\dimen6 } + + \def\getinsertionheight + {\ifdim\pagegoal<\maxdimen + \bgroup + \dimen0=\makeupheight + \advance\dimen0 -\pagegoal + \xdef\insertionheight{\the\dimen0}% + \egroup + \else + \global\let\insertionheight\zeropoint + \fi} + + \def\docolumnroomfloat + {\ifpostponecolumnfloats + \global\setfalse\c_page_floats_room + \else\ifconditional\c_page_floats_not_permitted + \global\setfalse\c_page_floats_room + \else + \bgroup + \getcolumnstatus{\count255}{\dimen0}{\dimen2}% + \page_floats_get_info\s!text + \setbox\scratchbox\vbox % tricky met objecten ? + {\blank[\rootfloatparameter\c!spacebefore] + \snaptogrid\vbox{\vskip\floatheight}}% copy? + \advance\dimen0\dimexpr\ht\scratchbox+2\openlineheight+.5\lineheight\relax\relax % needed because goal a bit higher + \ifdim\dimen0>\dimen2 + \global\setfalse\c_page_floats_room + \else + \global\settrue\c_page_floats_room + \fi + \ifdim\floatwidth>\hsize + \showmessage\m!columns{11}\empty + \global\setfalse\c_page_floats_room + \fi + \egroup + \fi\fi} %D Flushing one float is done as soon as possible, i.e. \type {\everypar}. %D This means that (at the moment) sidefloats are not supported (overulled)! -\newif\ifflushingcolumnfloats \flushingcolumnfloatstrue - -\def\doflushcolumnfloat - {\ifpostponecolumnfloats\else\ifflushingcolumnfloats\ifconditional\c_page_floats_some_waiting - \doflushcolumnfloatindeed - \fi\fi\fi} - -\def\doflushcolumnfloatindeed - {\bgroup - \forgetall - \let\doflushcolumnfloat\relax - \getcolumnstatus\column\mofcolumns\total\dimen0\goal\dimen2\\% - \ifdim\dimen0>\zeropoint - \page_floats_get_info\s!text - \ifdim\floatwidth>\hsize - % dropped ? - \else - \setbox2\vbox - {\blank[\rootfloatparameter\c!spacebefore] - \snaptogrid\vbox{\vskip\floatheight}}% - \advance\dimen0 \ht2 - \ifdim\dimen0>\dimen2 - \ifnum\mofcolumns<\nofcolumns - \advance\mofcolumns \plusone - \ifdim\ht\currenttopcolumnbox=\zeropoint - \page_floats_flush\s!text\plusone - \global\setbox\currenttopcolumnbox\vbox - {\snaptogrid\vbox{\box\floatbox} - \whitespace % nodig ? - \blank[\rootfloatparameter\c!spaceafter]}% - \dimen4=\htdp\currenttopcolumnbox - \global\advance\vsize -\dimen4 - \advance\dimen4 -\pagegoal - \global\pagegoal-\dimen4 - \showmessage\m!columns{12}a% + \newif\ifflushingcolumnfloats \flushingcolumnfloatstrue + + \def\doflushcolumnfloat + {\ifpostponecolumnfloats\else\ifflushingcolumnfloats\ifconditional\c_page_floats_some_waiting + \doflushcolumnfloatindeed + \fi\fi\fi} + + \def\doflushcolumnfloatindeed + {\bgroup + \forgetall + \let\doflushcolumnfloat\relax + \getcolumnstatus{\mofcolumns}{\dimen0}{\dimen2}% + \ifdim\dimen0>\zeropoint + \page_floats_get_info\s!text + \ifdim\floatwidth>\hsize + % dropped ? + \else + \setbox2\vbox + {\blank[\rootfloatparameter\c!spacebefore] + \snaptogrid\vbox{\vskip\floatheight}}% + \advance\dimen0 \ht2 + \ifdim\dimen0>\dimen2 + \ifnum\mofcolumns<\nofcolumns + \advance\mofcolumns \plusone + \ifdim\ht\currenttopcolumnbox=\zeropoint + \page_floats_flush\s!text\plusone + \global\setbox\currenttopcolumnbox\vbox + {\snaptogrid\vbox{\box\floatbox} + \whitespace % nodig ? + \blank[\rootfloatparameter\c!spaceafter]}% + \dimen4=\htdp\currenttopcolumnbox + \global\advance\vsize -\dimen4 + \advance\dimen4 -\pagegoal + \global\pagegoal-\dimen4 + \showmessage\m!columns{12}a% + \else + \showmessage\m!columns{12}b% + \fi + \else + \showmessage\m!columns{12}c% + \fi \else - \showmessage\m!columns{12}b% + \ifhmode{\setbox0\lastbox}\fi% waar is die er in geslopen + \par + \ifdim\prevdepth<\zeropoint \else % anders bovenaan kolom witruimte + \nobreak + \blank[\rootfloatparameter\c!spacebefore] + \nobreak + \fi + \page_floats_flush\s!text\plusone + \page_otr_command_flush_float_box + \blank[\rootfloatparameter\c!spaceafter] \fi - \else - \showmessage\m!columns{12}c% \fi - \else - \ifhmode{\setbox0\lastbox}\fi% waar is die er in geslopen - \par - \ifdim\prevdepth<\zeropoint \else % anders bovenaan kolom witruimte - \nobreak - \blank[\rootfloatparameter\c!spacebefore] - \nobreak - \fi - \page_floats_flush\s!text\plusone - \page_otr_command_flush_float_box - \blank[\rootfloatparameter\c!spaceafter] \fi - \fi - \fi - \egroup} + \egroup} %D This one looks complicated. Upto \type{\nofcolumns} floats are placed, %D taking the width of a float into account. This routine can be improved @@ -1313,96 +1316,96 @@ %D When handling lots of (small) floats spacing can get worse because of %D lining out the columns. -\def\doflushcolumnfloats - {\ifpostponecolumnfloats\else - \bgroup - \forgetall - \ifconditional\c_page_floats_some_waiting - \dimen8\zeropoint - \dimen4\zeropoint - \count0\zerocount % count0 can be used local - \count2\nofcolumns % count2 can be used local - \dohandleallcolumns - {\ifnum\count0>\zerocount % the wide one's reserved space - \global\setbox\currenttopcolumnbox\vbox - {\snaptogrid\vbox - {\copy\currenttopcolumnbox - \hbox{\vphantom{\vskip\floatheight}}}% known from previous - \whitespace % nodig ? - \blank[\rootfloatparameter\c!spaceafter]}% - \else - \page_floats_get_info\s!text - \ifdim\floatwidth>\hsize - \dimen0\dimexpr\floatwidth+\intercolumnwidth+.5pt\relax - \dimen2\dimexpr\hsize +\intercolumnwidth+.5pt\relax - \divide\dimen0 \dimen2 - \count0\dimen0 - \advance\count0 \plusone - \ifnum\count0>\count2 - \count0\zerocount + \def\doflushcolumnfloats + {\ifpostponecolumnfloats\else + \bgroup + \forgetall + \ifconditional\c_page_floats_some_waiting + \dimen8\zeropoint + \dimen4\zeropoint + \count0\zerocount % count0 can be used local + \count2\nofcolumns % count2 can be used local + \dohandleallcolumns + {\ifnum\count0>\zerocount % the wide one's reserved space + \global\setbox\currenttopcolumnbox\vbox + {\snaptogrid\vbox + {\copy\currenttopcolumnbox + \hbox{\vphantom{\vskip\floatheight}}}% known from previous + \whitespace % nodig ? + \blank[\rootfloatparameter\c!spaceafter]}% \else - \dimen0\dimexpr\count0\hsize+\count0\intercolumnwidth-\intercolumnwidth\relax - \page_floats_flush\s!text\plusone - \ifdim\floatwidth>\finalcolumntextwidth % better somewhere else too - \global\setbox\floatbox\hbox to \finalcolumntextwidth{\hss\box\floatbox\hss}% - \fi % otherwise the graphic may disappear - \global\setbox\floatbox\hbox to \dimen0 - {\processaction[\rootfloatparameter\c!location] % how easy to forget - [ \v!left=>\box\floatbox\hss, - \v!right=>\hss\box\floatbox, - \s!default=>\hss\box\floatbox\hss, - \s!unknown=>\hss\box\floatbox\hss]}% + \page_floats_get_info\s!text + \ifdim\floatwidth>\hsize + \dimen0\dimexpr\floatwidth+\d_page_mul_distance+.5pt\relax + \dimen2\dimexpr\hsize +\d_page_mul_distance+.5pt\relax + \divide\dimen0 \dimen2 + \count0\dimen0 + \advance\count0 \plusone + \ifnum\count0>\count2 + \count0\zerocount + \else + \dimen0\dimexpr\count0\hsize+\count0\d_page_mul_distance-\d_page_mul_distance\relax + \page_floats_flush\s!text\plusone + \ifdim\floatwidth>\makeupwidth % better somewhere else too + \global\setbox\floatbox\hbox to \makeupwidth{\hss\box\floatbox\hss}% + \fi % otherwise the graphic may disappear + \global\setbox\floatbox\hbox to \dimen0 + {\processaction[\rootfloatparameter\c!location] % how easy to forget + [ \v!left=>\box\floatbox\hss, + \v!right=>\hss\box\floatbox, + \s!default=>\hss\box\floatbox\hss, + \s!unknown=>\hss\box\floatbox\hss]}% + \fi + \showmessage\m!columns{13}\empty + \else + \page_floats_flush\s!text\plusone + \ifdim\floatwidth>\makeupwidth % better somewhere else too + \global\setbox\floatbox\hbox to \makeupwidth{\hss\box\floatbox\hss}% + \fi % otherwise the graphic may disappear + % \showmessage\m!columns{13}\empty + \fi + \ifdim\ht\floatbox>\zeropoint\relax + \global\setbox\currenttopcolumnbox\vbox + {\snaptogrid\vbox + {\box\currenttopcolumnbox % was copy + \box\floatbox} + \whitespace % nodig ? + \blank[\rootfloatparameter\c!spaceafter]}% + \fi + \dimen6\htdp\currenttopcolumnbox \fi - \showmessage\m!columns{13}\empty - \else - \page_floats_flush\s!text\plusone - \ifdim\floatwidth>\finalcolumntextwidth % better somewhere else too - \global\setbox\floatbox\hbox to \finalcolumntextwidth{\hss\box\floatbox\hss}% - \fi % otherwise the graphic may disappear - % \showmessage\m!columns{13}\empty - \fi - \ifdim\ht\floatbox>\zeropoint\relax - \global\setbox\currenttopcolumnbox\vbox - {\snaptogrid\vbox - {\box\currenttopcolumnbox % was copy - \box\floatbox} - \whitespace % nodig ? - \blank[\rootfloatparameter\c!spaceafter]}% - \fi - \dimen6\htdp\currenttopcolumnbox - \fi - \ifdim\dimen4<\ht\currenttopcolumnbox - \dimen4\ht\currenttopcolumnbox - \fi - \advance\dimen8 \dimen6 - \advance\count2 \minusone - \advance\count0 \minusone }% - \page_otr_command_set_vsize - \global\advance\vsize -\dimen8 - \global\pagegoal\vsize - \else - % \page_mul_command_flush_floats % does not snap! - \fi - \egroup - \fi} + \ifdim\dimen4<\ht\currenttopcolumnbox + \dimen4\ht\currenttopcolumnbox + \fi + \advance\dimen8 \dimen6 + \advance\count2 \minusone + \advance\count0 \minusone }% + \page_otr_command_set_vsize + \global\advance\vsize -\dimen8 + \global\pagegoal\vsize + \else + % \page_mul_command_flush_floats % does not snap! + \fi + \egroup + \fi} %D The next macro can be used to flush floats in the current stream. No %D width checking is (yet) done. -\def\insertcolumnfloats - {\doloop - {\ifconditional\c_page_floats_some_waiting - \bgroup - \forgetall - % no check for width - \page_floats_get - \blank[\rootfloatparameter\c!spacebefore] - \snaptogrid\vbox{\copy\floatbox} - \blank[\rootfloatparameter\c!spaceafter] - \egroup - \else - \exitloop - \fi}} + \def\insertcolumnfloats + {\doloop + {\ifconditional\c_page_floats_some_waiting + \bgroup + \forgetall + % no check for width + \page_floats_get + \blank[\rootfloatparameter\c!spacebefore] + \snaptogrid\vbox{\copy\floatbox} + \blank[\rootfloatparameter\c!spaceafter] + \egroup + \else + \exitloop + \fi}} %D This were the multi||column routines. They can and need to be improved %D but at the moment their behaviour is acceptable. @@ -1422,55 +1425,21 @@ % 3 \input tufte \par \placefigure{}{\framed[width=\hsize,height=3cm]{3}} % \stopcolumns -\unexpanded\def\setupcolumns - {\dosingleempty\dosetupcolumns} - -\def\dosetupcolumns[#1]% - {\getparameters[\??kl][#1]% - \nofcolumns\@@kln\relax - \processaction - [\@@klrule] - [ \v!on=>\let\betweencolumns\linebetweencolumns, - \v!off=>\let\betweencolumns\spacebetweencolumns, - \s!default=>\let\betweencolumns\spacebetweencolumns, - \s!unknown=>\let\betweencolumns\@@klrule]} - -\def\linebetweencolumns - {\bgroup - \starttextproperties - \ifdim\@@kldistance>\zeropoint - \dimen0=\@@kldistance - \else - \dimen0=\linewidth % hm, weird - \fi - \advance\dimen0 -\linewidth - \hskip.5\dimen0 - \vrule - \!!width\linewidth - \ifnum\bottomraggednessmode=\plustwo % baselinebottom - \!!depth\strutdepth - \fi - \hskip.5\dimen0\relax - \stoptextproperties - \egroup} - -\def\spacebetweencolumns - {\hskip\@@kldistance} - -\presetlocalframed[\??kl] - -\def\backgroundfinishcolumnbox - {\doifinsetelse\@@kloffset{\v!none,\v!overlay} - {\let\@@kloffset\!!zeropoint} - {\scratchdimen\@@kloffset - \advance\scratchdimen -\@@klrulethickness - \edef\@@kloffset{\the\scratchdimen}}% - \localframed - [\??kl] - [\c!strut=\v!no, - \c!width=\v!fit, - \c!height=\v!fit, - \c!align=]} + % \def\backgroundfinishcolumnbox + % {\doifinsetelse\@@kloffset{\v!none,\v!overlay} + % {\let\@@kloffset\!!zeropoint} + % {\scratchdimen\@@kloffset + % \advance\scratchdimen -\@@klrulethickness + % \edef\@@kloffset{\the\scratchdimen}}% + % \localframed + % [\??kl] + % [\c!strut=\v!no, + % \c!width=\v!fit, + % \c!height=\v!fit, + % \c!align=]} + + \def\backgroundfinishcolumnbox + {} % to be reconsidered ... (in any case they need to be unexpandable sinze 2011.12.30) @@ -1478,149 +1447,196 @@ \unexpanded\def\page_columns_align_option_no {\stretchcolumnsfalse\inheritcolumnsfalse}% todo: new key \unexpanded\def\page_columns_align_option_text{\stretchcolumnsfalse\inheritcolumnstrue }% +\newtoks\t_page_mul_initialize + \unexpanded\def\startcolumns - {\dosingleempty\dostartcolumns} + {\dosingleempty\page_mul_start} -\def\dostartcolumns[#1]% %% \startcolumns +\def\page_mul_start[#1]% %% \startcolumns {\bgroup - \let\stopcolumns\egroup \ifinsidecolumns + \page_mul_start_nop \else \iffirstargument \setupcolumns[#1]% \fi - \ifnum\@@kln>1\relax - \whitespace - \begingroup - \doif\@@kloption\v!background - {\let\finishcolumnbox\backgroundfinishcolumnbox - \let\columntextoffset\@@kloffset}% - \ifx\@@klcommand\empty\else - \let\postprocesscolumnline\@@klcommand - \fi - \doifelsenothing\@@klheight - \heightencolumnsfalse - \heightencolumnstrue - \doifelse\@@kldirection\v!right - \reversecolumnsfalse - \reversecolumnstrue - \doifelse\@@klbalance\v!yes - \balancecolumnstrue - \balancecolumnsfalse - \installalign\v!yes {\page_columns_align_option_yes }% - \installalign\v!no {\page_columns_align_option_no }% - \installalign\v!text{\page_columns_align_option_text}% - \stretchcolumnsfalse - \inheritcolumnstrue - \doifsomething\@@klalign{\expanded{\setupalign[\@@klalign]}}% - \nofcolumns\@@kln - \edef\fixedcolumnheight{\@@klheight}% - \edef\minbalancetoplines{\@@klntop}% - \setuptolerance[\@@kltolerance]% %% \startcolumns - \setupblank[\@@klblank]% - \ifdim\s_spac_whitespace_parskip>\zeropoint\relax - \setupwhitespace[\@@klblank]% - \fi - \unexpanded\def\stopcolumns - {\endmulticolumns - \global\insidecolumnsfalse - \endgroup - \egroup}% - \global\insidecolumnstrue - \beginmulticolumns + \nofcolumns\columnsparameter\c!n\relax + \ifnum\nofcolumns>\plusone + \page_mul_start_yes + \else + \page_mul_start_nop \fi \fi} -\installcolumnbreakmethod \s!multicolumn \v!preference - {\goodbreak} +\unexpanded\def\page_mul_start_nop + {\let\stopcolumns\page_mul_stop_nop} -% \installcolumnbreakmethod \s!multicolumn \v!yes -% {\par % todo: since -% {\testrulewidth\zeropoint\ruledvskip\textheight} % we misuse a -% \penalty-200 % side effect -% \vskip-\textheight -% }% bugged : \prevdepth-\thousandpoint} % signals top of column to \blank +\unexpanded\def\page_mul_stop_nop + {\egroup} -\installcolumnbreakmethod \s!multicolumn \v!yes - {\par +\unexpanded\def\page_mul_start_yes + {\whitespace \begingroup - \normaloffinterlineskip - \normalpenalty\plustenthousand - \vbox to \textheight{}% - \endgroup - \penalty-200 - \vskip-\textheight - } % bugged : \prevdepth-\thousandpoint} % signals top of column to \blank - -%D New: only at start of columns; may change ! Rather interwoven and therefore -%D to be integrated when the multi column modules are merged. - -\unexpanded\def\setupcolumnspan[#1]% - {\getparameters[\??ks][#1]} - -\presetlocalframed - [\??ks] - -\setupcolumnspan - [\c!n=2, - \c!offset=\v!overlay, - \c!frame=\v!off] + \let\stopcolumns\page_mul_stop_indeed + \global\insidecolumnstrue + \the\t_page_mul_initialize + % + \flushnotes + \begingroup + % + \d_page_mul_leftskip\leftskip + \d_page_mul_rightskip\rightskip + \leftskip\zeropoint + \rightskip\zeropoint + % + \widowpenalty\zerocount % will become option + \clubpenalty \zerocount % will become option + % + \page_floats_column_push_saved + % + \ifdim\dimexpr\pagetotal+\parskip+\openlineheight\relax<\pagegoal + \allowbreak + \else + \break % sometimes fails + \fi + \appendtoks + \topskip1\topskip % best a switch + \to \everybodyfont + \the\everybodyfont % ugly here + \saveinterlinespace % ugly here + % + \initializecolumns\nofcolumns + % + \hangafter\zerocount + \hangindent\zeropoint + \reseteverypar + \ifdim\pagetotal=\zeropoint \else + \verticalstrut + \vskip-\struttotal + \fi + \global\savedpagetotal\pagetotal + \setupoutputroutine[\s!multicolumn]% + \c_page_mul_routine\c_page_mul_routine_intercept + \page_otr_trigger_output_routine % no \holdinginserts=1, can make footnote disappear ! + \global\d_page_mul_preceding_height\ht\b_page_mul_preceding + \c_page_mul_routine\c_page_mul_routine_continue + \page_mul_initialize_floats + \dohandleallcolumns{\global\setbox\currenttopcolumnbox\emptybox}% + \checkbegincolumnfootnotes + \page_otr_command_set_hsize + \page_otr_command_set_vsize} -\newbox\b_page_columns_span \let\postprocesscolumnspanbox\gobbleoneargument +\setnewconstant\multicolumnendsyncmethod\plusone % 1: old sync 2: new sync (cont-loc/project) / may fail ! ! ! ! -\def\dostartcolumnspan[#1]% - {\bgroup - \setupcolumnspan[#1]% - \forgetall - \ifinsidecolumns - \advance\hsize \intercolumnwidth - \hsize\@@ksn\hsize - \advance\hsize -\intercolumnwidth +\unexpanded\def\page_mul_stop_indeed + {\relax + \ifnum\multicolumnendsyncmethod=\plustwo + \synchronizeoutput + \else + % don't collapse these + \vskip \lineheight + \vskip-\lineheight % take footnotes into account \fi - \dowithnextboxcs\dofinishcolumnsetspan\vbox\bgroup - %\topskipcorrection % becomes an option ! - \EveryPar{\begstrut\EveryPar{}}} % also ! - -\def\dofinishcolumnsetspan - {\setbox\b_page_columns_span\flushnextbox - \ifinsidecolumns\wd\b_page_columns_span\hsize\fi - \postprocesscolumnspanbox\b_page_columns_span - \scratchdimen\ht\b_page_columns_span - \setbox\b_page_columns_span\hbox % depth to be checked, probably option! - {\localframed[\??ks][\c!offset=\v!overlay]{\box\b_page_columns_span}}% - \ht\b_page_columns_span\scratchdimen - \dp\b_page_columns_span\strutdp - \wd\b_page_columns_span\hsize - \ifinsidecolumns - \ifnum\@@ksn>1 - \page_otr_command_set_vsize - \dohandleallcolumns - {\ifnum\currentcolumn>\@@ksn\else - \global\setbox\currenttopcolumnbox=\vbox - {\ifnum\currentcolumn=1 - \snaptogrid\vbox{\copy\b_page_columns_span} - \else - \snaptogrid\vbox{\vphantom{\copy\b_page_columns_span}} - \fi}% - \wd\currenttopcolumnbox\hsize - \global\advance\vsize -\ht\currenttopcolumnbox - \fi} - \global\pagegoal\vsize - \else - \snaptogrid\vbox{\box\b_page_columns_span} + \doflushcolumnfloat % added recently + %\doflushcolumnfloats % no, since it results in wrong top floats + \flushnotes % before start of columns + \par + \ifbalancecolumns + \ifnum\multicolumnendsyncmethod=\plusone + \c_page_mul_routine\c_page_mul_routine_continue + \goodbreak \fi + \c_page_mul_routine\c_page_mul_routine_balance \else - \snaptogrid\vbox{\box\b_page_columns_span} + \goodbreak \fi - \endgraf - \ifvmode\prevdepth\strutdp\fi - \egroup} + % still the multi column routine + \page_otr_trigger_output_routine % the prevdepth is important, try e.g. toclist in + \prevdepth\zeropoint % columns before some noncolumned text text + % + \c_page_mul_routine\c_page_mul_routine_regular + % + \ifvoid\b_page_mul_preceding\else + \unvbox\b_page_mul_preceding + \fi + \global\d_page_mul_preceding_height\zeropoint + \endgroup % here + \nofcolumns\plusone + \page_otr_command_set_vsize + \checkendcolumnfootnotes + \dosomebreak\allowbreak + \page_floats_column_pop_saved + % + \global\insidecolumnsfalse + \endgroup + \egroup}% + +\appendtoks + \edef\p_option{\columnsparameter\c!option}% + \ifx\p_option\v!background + \let\finishcolumnbox\backgroundfinishcolumnbox + \fi + \d_page_mul_offset\columnsparameter\c!offset\relax + \edef\p_command{\columnsparameter\c!command}% + \ifx\p_command\empty \else + \let\postprocesscolumnline\p_command + \fi + \edef\p_height{\columnsparameter\c!height}% + \ifx\p_height\empty + \d_page_mul_forced_height\textheight + \heightencolumnsfalse + \else + \d_page_mul_forced_height\p_height\relax + \heightencolumnstrue + \fi + \edef\p_direction{\columnsparameter\c!direction}% + \ifx\p_direction\v!right + \setfalse\c_page_mul_reverse + \else + \settrue\c_page_mul_reverse + \fi + \edef\p_balance{\columnsparameter\c!balance}% + \ifx\p_balance\v!yes + \balancecolumnstrue + \else + \balancecolumnsfalse + \fi + \installalign\v!yes {\page_columns_align_option_yes }% + \installalign\v!no {\page_columns_align_option_no }% + \installalign\v!text{\page_columns_align_option_text}% + \stretchcolumnsfalse + \inheritcolumnstrue + \edef\p_align{\columnsparameter\c!align}% + \ifx\p_align\empty \else + \setupalign[\p_align]% + \fi + \edef\p_tolerance{\columnsparameter\c!tolerance}% + \ifx\p_tolerance\empty \else + \setuptolerance[\p_tolerance]% + \fi + \edef\p_blank{\columnsparameter\c!blank}% + \ifx\p_blank\empty \else + \setupblank[\p_blank]% + \fi + \ifdim\s_spac_whitespace_parskip>\zeropoint\relax + \setupwhitespace[\p_blank]% + \fi + \c_page_mul_balance_minimum\columnsparameter\c!ntop\relax + \edef\p_page_mul_rule{\columnsparameter\c!rule}% + \expandcheckedcsname\??columnseparators\p_page_mul_rule\s!unknown +\to \t_page_mul_initialize + +%D Columns breaks -\unexpanded\def\startcolumnspan - {\dosingleempty\dostartcolumnspan} +\installcolumnbreakmethod \s!multicolumn \v!preference + {\goodbreak} -\unexpanded\def\stopcolumnspan - {\egroup} +\installcolumnbreakmethod \s!multicolumn \v!yes + {\vskip\textheight + \penalty-200 % we can mark and intercept this + \vskip-\textheight} + +%D Next we initialize the lot: \setupcolumns [\c!n=2, @@ -1638,19 +1654,85 @@ \c!rulethickness=\linewidth, \c!offset=.5\bodyfontsize] -%D Undocumented and still under development. +%D New: only at start of columns; may change ! Rather interwoven and therefore +%D to be integrated when the multi column modules are merged. + + \unexpanded\def\setupcolumnspan[#1]% + {\getparameters[\??ks][#1]} + + \presetlocalframed + [\??ks] + + \setupcolumnspan + [\c!n=2, + \c!offset=\v!overlay, + \c!frame=\v!off] + + \newbox\b_page_columns_span \let\page_mul_postprocess_spanbox\gobbleoneargument + + \unexpanded\def\startcolumnspan + {\dosingleempty\dostartcolumnspan} + + \unexpanded\def\stopcolumnspan + {\egroup} + + \def\dostartcolumnspan[#1]% + {\bgroup + \setupcolumnspan[#1]% + \forgetall + \ifinsidecolumns + \advance\hsize \d_page_mul_distance + \hsize\@@ksn\hsize + \advance\hsize -\d_page_mul_distance + \fi + \dowithnextboxcs\dofinishcolumnsetspan\vbox\bgroup + %\topskipcorrection % becomes an option ! + \EveryPar{\begstrut\EveryPar{}}} % also ! + + \def\dofinishcolumnsetspan + {\setbox\b_page_columns_span\flushnextbox + \ifinsidecolumns\wd\b_page_columns_span\hsize\fi + \page_mul_postprocess_spanbox\b_page_columns_span + \scratchdimen\ht\b_page_columns_span + \setbox\b_page_columns_span\hbox % depth to be checked, probably option! + {\localframed[\??ks][\c!offset=\v!overlay]{\box\b_page_columns_span}}% + \ht\b_page_columns_span\scratchdimen + \dp\b_page_columns_span\strutdp + \wd\b_page_columns_span\hsize + \ifinsidecolumns + \ifnum\@@ksn>1 + \page_otr_command_set_vsize + \dohandleallcolumns + {\ifnum\currentcolumn>\@@ksn\else + \global\setbox\currenttopcolumnbox=\vbox + {\ifnum\currentcolumn=1 + \snaptogrid\vbox{\copy\b_page_columns_span} + \else + \snaptogrid\vbox{\vphantom{\copy\b_page_columns_span}} + \fi}% + \wd\currenttopcolumnbox\hsize + \global\advance\vsize -\ht\currenttopcolumnbox + \fi} + \global\pagegoal\vsize + \else + \snaptogrid\vbox{\box\b_page_columns_span} + \fi + \else + \snaptogrid\vbox{\box\b_page_columns_span} + \fi + \endgraf + \ifvmode\prevdepth\strutdp\fi + \egroup} + +%D Undocumented and still under development.\ifdefined\startsimplecolumns \else \unexpanded\def\startsimplecolumns - {\dosingleempty\dostartsimplecolumns} + {\dosingleempty\page_mul_simple_start} -\def\dostartsimplecolumns[#1]% +\def\page_mul_simple_start[#1]% {\bgroup + \setsimplecolumnshsize[#1]% \nopenalties - \getparameters[\??kl] - [\c!width=\hsize,\c!distance=1.5\bodyfontsize,% - \c!n=2,\c!lines=0,#1]% - \let\rigidcolumnlines\@@kllines - \setrigidcolumnhsize\@@klwidth\@@kldistance\@@kln \setbox\scratchbox\vbox\bgroup \forgetall} % \blank[\v!disable] @@ -1661,35 +1743,44 @@ \egroup} \unexpanded\def\setsimplecolumnshsize[#1]% - {\getparameters[\??kl][\c!width=\hsize,\c!distance=1.5\bodyfontsize,\c!n=2,\c!lines=0,#1]% - \let\rigidcolumnlines\@@kllines - \setrigidcolumnhsize\@@klwidth\@@kldistance\@@kln} + {\getdummyparameters + [\c!width=\hsize, + \c!distance=1.5\bodyfontsize, + \c!n=2, + \c!lines=0, + #1]% + \edef\rigidcolumnlines + {\directdummyparameter\c!lines}% + \setrigidcolumnhsize + {\directdummyparameter\c!width}% + {\directdummyparameter\c!distance}% + {\directdummyparameter\c!n}} \let\page_mul_command_package_contents\page_one_command_package_contents \let\page_mul_command_flush_float_box \page_one_command_flush_float_box \defineoutputroutine [\s!multicolumn] - [\s!page_otr_command_routine =\page_mul_command_routine, - \s!page_otr_command_package_contents =\page_mul_command_package_contents, - \s!page_otr_command_set_vsize =\page_mul_command_set_vsize, - \s!page_otr_command_set_hsize =\page_mul_command_set_hsize, - \s!page_otr_command_next_page =\page_mul_command_next_page, - \s!page_otr_command_next_page_and_inserts =\page_mul_command_next_page_and_inserts, - % \s!page_otr_command_synchronize_hsize =\page_mul_command_synchronize_hsize, - % \s!page_otr_command_set_top_insertions =\page_mul_command_set_top_insertions, - % \s!page_otr_command_set_bottom_insertions =\page_mul_command_set_bottom_insertions, - \s!page_otr_command_flush_top_insertions =\page_mul_command_flush_top_insertions, - % \s!page_otr_command_flush_bottom_insertions =\page_mul_command_flush_bottom_insertions, - % \s!page_otr_command_set_float_hsize =\page_mul_command_set_float_hsize, - \s!page_otr_command_check_if_float_fits =\page_mul_command_check_if_float_fits, - \s!page_otr_command_flush_float_box =\page_mul_command_flush_float_box, - \s!page_otr_command_synchronize_side_floats =\page_mul_command_synchronize_side_floats, - \s!page_otr_command_side_float_output =\page_mul_command_side_float_output, - \s!page_otr_command_flush_floats =\page_mul_command_flush_floats, - \s!page_otr_command_flush_side_floats =\page_mul_command_flush_side_floats, - \s!page_otr_command_flush_saved_floats =\page_mul_command_flush_saved_floats - % \s!page_otr_command_flush_margin_blocks =\page_mul_command_flush_margin_blocks, % not used + [\s!page_otr_command_routine =\page_mul_command_routine, + \s!page_otr_command_package_contents =\page_mul_command_package_contents, + \s!page_otr_command_set_vsize =\page_mul_command_set_vsize, + \s!page_otr_command_set_hsize =\page_mul_command_set_hsize, + \s!page_otr_command_next_page =\page_mul_command_next_page, + \s!page_otr_command_next_page_and_inserts =\page_mul_command_next_page_and_inserts, + % \s!page_otr_command_synchronize_hsize =\page_mul_command_synchronize_hsize, + % \s!page_otr_command_set_top_insertions =\page_mul_command_set_top_insertions, + % \s!page_otr_command_set_bottom_insertions =\page_mul_command_set_bottom_insertions, + \s!page_otr_command_flush_top_insertions =\page_mul_command_flush_top_insertions, + % \s!page_otr_command_flush_bottom_insertions=\page_mul_command_flush_bottom_insertions, + % \s!page_otr_command_set_float_hsize =\page_mul_command_set_float_hsize, + \s!page_otr_command_check_if_float_fits =\page_mul_command_check_if_float_fits, + \s!page_otr_command_flush_float_box =\page_mul_command_flush_float_box, + \s!page_otr_command_synchronize_side_floats=\page_mul_command_synchronize_side_floats, + \s!page_otr_command_side_float_output =\page_mul_command_side_float_output, + \s!page_otr_command_flush_floats =\page_mul_command_flush_floats, + \s!page_otr_command_flush_side_floats =\page_mul_command_flush_side_floats, + \s!page_otr_command_flush_saved_floats =\page_mul_command_flush_saved_floats + % \s!page_otr_command_flush_margin_blocks =\page_mul_command_flush_margin_blocks, % not used ] \protect \endinput diff --git a/tex/context/base/page-not.mkiv b/tex/context/base/page-not.mkiv index 7fae16419..d7602bd26 100644 --- a/tex/context/base/page-not.mkiv +++ b/tex/context/base/page-not.mkiv @@ -41,11 +41,13 @@ \newdimen\totalinsertionheight -\def\settotalinsertionheight +\unexpanded\def\settotalinsertionheight {\calculatetotalnoteheight - \totalinsertionheight\totalnoteheight - \addinsertionheight\c_page_floats_insertions_top \to\totalinsertionheight - \addinsertionheight\c_page_floats_insertions_bottom\to\totalinsertionheight} + \totalinsertionheight\dimexpr + \totalnoteheight + +\page_insert_insertion_height\s!topfloat + +\page_insert_insertion_height\s!bottomfloat + \relax} % hm diff --git a/tex/context/base/page-one.mkiv b/tex/context/base/page-one.mkiv index e9ca80e2b..9c740dbc2 100644 --- a/tex/context/base/page-one.mkiv +++ b/tex/context/base/page-one.mkiv @@ -197,18 +197,19 @@ \global\advance\d_page_floats_inserted_top\dimexpr\ht\floatbox+\dp\floatbox+\s_page_one_between_top_insert\relax} \def\page_one_insert_top_float % maybe remember last beforeskip - {\insert\c_page_floats_insertions_top - {\forgetall - \ifconditional\c_page_one_top_of_insert - \ifconditional\c_page_one_correct_top_insert - \topskipcorrection % [xx] new: see icare topbleed - \kern-\lineskip - \par - \prevdepth\maxdimen - \fi - \fi - \page_otr_command_flush_float_box - \vskip\s_page_one_between_top_insert}} + {\insert\namedinsertionnumber\s!topfloat\bgroup + \forgetall + \ifconditional\c_page_one_top_of_insert + \ifconditional\c_page_one_correct_top_insert + \topskipcorrection % [xx] new: see icare topbleed + \kern-\lineskip + \par + \prevdepth\maxdimen + \fi + \fi + \page_otr_command_flush_float_box + \vskip\s_page_one_between_top_insert + \egroup} \unexpanded\def\page_one_command_set_top_insertions {\bgroup @@ -267,10 +268,11 @@ \page_floats_get \global\advance\d_page_floats_inserted_bottom\dimexpr\ht\floatbox+\dp\floatbox+\d_strc_floats_top\relax \ifdim\d_page_floats_inserted_bottom<\pagegoal\relax - \insert\c_page_floats_insertions_bottom - {\forgetall - \blank[\rootfloatparameter\c!spacebefore]% - \page_otr_command_flush_float_box}% + \insert\namedinsertionnumber\s!bottomfloat\bgroup + \forgetall + \blank[\rootfloatparameter\c!spacebefore]% + \page_otr_command_flush_float_box + \egroup \ifconditional\c_page_floats_some_waiting \advance\noffloatinserts \plusone \else @@ -291,9 +293,9 @@ \page_one_command_set_bottom_insertions_indeed} \unexpanded\def\page_one_command_flush_top_insertions - {\ifvoid\c_page_floats_insertions_top\else + {\ifvoid\namedinsertionnumber\s!topfloat\else \ifgridsnapping - \box\c_page_floats_insertions_top + \box\namedinsertionnumber\s!topfloat \vskip-\topskip \vskip\strutheight % [xx] new: see icare topbleed \else @@ -304,20 +306,20 @@ \vskip-\topskip \vskip\strutheight \fi - \unvbox\c_page_floats_insertions_top + \unvbox\namedinsertionnumber\s!topfloat \fi \fi \global\d_page_floats_inserted_top\zeropoint} \unexpanded\def\page_one_command_flush_bottom_insertions - {\ifvoid\c_page_floats_insertions_bottom\else + {\ifvoid\namedinsertionnumber\s!bottomfloat\else \ifgridsnapping % \floatparameter\c!bottombefore - \snaptogrid\hbox{\box\c_page_floats_insertions_bottom}% + \snaptogrid\hbox{\box\namedinsertionnumber\s!bottomfloat}% % \floatparameter\c!bottomafter \else \floatparameter\c!bottombefore - \unvbox\c_page_floats_insertions_bottom + \unvbox\namedinsertionnumber\s!bottomfloat \floatparameter\c!bottomafter \fi \fi @@ -549,11 +551,11 @@ \def\page_one_place_float_bottom_indeed {\global\advance\d_page_floats_inserted_bottom\dimexpr\ht\floatbox+\dp\floatbox+\d_strc_floats_top\relax - \insert\c_page_floats_insertions_bottom - {\forgetall - \blank[\rootfloatparameter\c!spacebefore]% - \page_otr_command_flush_float_box}% - %\global\settrue\c_page_floats_not_permitted + \insert\namedinsertionnumber\s!bottomfloat\bgroup + \forgetall + \blank[\rootfloatparameter\c!spacebefore]% + \page_otr_command_flush_float_box + \egroup \page_floats_report_total} \def\page_one_place_float_face % links, rechts, midden, hoog, midden, laag diff --git a/tex/context/base/page-otr.mkvi b/tex/context/base/page-otr.mkvi index 19c308c32..e5433c866 100644 --- a/tex/context/base/page-otr.mkvi +++ b/tex/context/base/page-otr.mkvi @@ -258,8 +258,8 @@ \definesystemconstant{page_otr_command_flush_margin_blocks} \definesystemconstant{singlecolumn} -\definesystemconstant{multicolumn} -\definesystemconstant{columnset} +\definesystemconstant{multicolumn} % will move +\definesystemconstant{columnset} % will move \defineoutputroutinecommand [\s!page_otr_command_routine, diff --git a/tex/context/base/page-pst.mkiv b/tex/context/base/page-pst.mkiv index 1078dda03..63fa54aa1 100644 --- a/tex/context/base/page-pst.mkiv +++ b/tex/context/base/page-pst.mkiv @@ -51,8 +51,8 @@ %newif \ifinpostponing % prevents nesting -\newcount \c_page_postponed_blocks_next_page % set at the lua end -\newconstant\c_page_postponed_busy +\newcount \c_page_postponed_blocks_next_page % set at the lua end +\newconditional\c_page_postponed_busy \unexpanded\setvalue{\e!start\v!postponing}% {\bgroup diff --git a/tex/context/base/page-set.mkiv b/tex/context/base/page-set.mkiv index c74c397e8..f0981443c 100644 --- a/tex/context/base/page-set.mkiv +++ b/tex/context/base/page-set.mkiv @@ -49,6 +49,17 @@ \newif\ifcolumnspread \newif\iftracecolumnset % \tracecolumnsettrue +\newif\ifforcecolumnsetgrid \forcecolumnsetgridtrue +\newif\ifcollectingsetcontent % never set +\newif\ifcarryoverfootnotes %\carryoverfootnotestrue +\newif\iflastcolumnfootnotes % never set \lastcolumnfootnotestrue +\newif\ifintermediatefootnotes + +\newbox\b_page_set_preceding +\newbox\b_page_set_trailing + +\newdimen\d_page_set_local_hsize + \def\columnmaxcells {75} % runtime \def\columnmaxfreecells {0} % runtime \def\columngaplimit {0} % {5} @@ -385,12 +396,12 @@ \hbox to \OTRSETmakeupwidth {\dostepwiserecurse{#1}{#2}{#3} {\mofcolumns\recurselevel - \localcolumnwidth\OTRSETlocalwidth\mofcolumns + \d_page_set_local_hsize\OTRSETlocalwidth\mofcolumns \setbox\scratchbox\hbox\localframed [\??mc\OTRSETidentifier\number\mofcolumns]% - [\c!width=\localcolumnwidth,\c!height=\!!heighta,\c!lines=]% + [\c!width=\d_page_set_local_hsize,\c!height=\!!heighta,\c!lines=]% {}% - \wd\scratchbox\localcolumnwidth + \wd\scratchbox\d_page_set_local_hsize \ht\scratchbox\!!heighta \ifcase\columndirection \hskip\OTRSETgetparameter\c!distance\recurselevel @@ -404,7 +415,7 @@ \hbox to \OTRSETmakeupwidth {\dostepwiserecurse{#1}{#2}{#3} {\mofcolumns\recurselevel - \localcolumnwidth\OTRSETlocalwidth\mofcolumns + \d_page_set_local_hsize\OTRSETlocalwidth\mofcolumns \offinterlineskip \setbox\scratchbox\vbox to \!!heighta {%\topskipcorrection % not needed @@ -426,8 +437,8 @@ \ifcase\columndirection \box\scratchbox \else - \hbox to \localcolumnwidth - {\hskip\localcolumnwidth\llap{\box\scratchbox}}% + \hbox to \d_page_set_local_hsize + {\hskip\d_page_set_local_hsize\llap{\box\scratchbox}}% \fi \par}% \ifcase\OTRSETbalancemethod @@ -442,7 +453,7 @@ \kern\zeropoint \vss \fi}% - \wd\scratchbox\localcolumnwidth % \textwidth + \wd\scratchbox\d_page_set_local_hsize % \textwidth \page_marks_synchronize_column{#1}{#2}\recurselevel\scratchbox \ifcase\columndirection \hskip\OTRSETgetparameter\c!distance\recurselevel\box\scratchbox @@ -496,7 +507,7 @@ \fi} \def\OTRSETdoflush - {\ifcollectingcontent + {\ifcollectingsetcontent \global\mofcolumns\plusone \else \OTRSETdofinalflush @@ -572,7 +583,7 @@ \fi} \unexpanded\def\page_set_command_set_vsize % snap per sectie (gap here?) - {\ifcollectingcontent \else % can be assigndimen + {\ifcollectingsetcontent \else % can be assigndimen \OTRSETsetcolumnmaxcells % layout can be changed \OTRSETskipstart % not that well tested \OTRSETcheckinsert % added @@ -589,9 +600,9 @@ \fi} \def\page_set_command_set_hsize % of course this does not migrate outside the otr - {\localcolumnwidth\OTRSETlocalwidth\mofcolumns - \textwidth\localcolumnwidth - \hsize\localcolumnwidth} + {\d_page_set_local_hsize\OTRSETlocalwidth\mofcolumns + \textwidth\d_page_set_local_hsize + \hsize\d_page_set_local_hsize} \unexpanded\def\page_set_command_synchronize_hsize {\ifcase0\getvalue{\??mc\??mc\c!width}\else % some width set @@ -1806,46 +1817,46 @@ \ifx\lastskipinotr\undefined \newskip\lastskipinotr \fi \installoutputroutine\OTRSETflushpreposttext - {\global\setbox\precolumnbox\vbox + {\global\setbox\b_page_set_preceding\vbox {\unvbox\normalpagebox \global\lastskipinotr\lastskip}% \ifdim\lastskipinotr>\zeropoint - \global\setbox\precolumnbox\hbox - {\lower\strutdepth\box\precolumnbox}% + \global\setbox\b_page_set_preceding\hbox + {\lower\strutdepth\box\b_page_set_preceding}% \fi - \dp\precolumnbox\strutdepth + \dp\b_page_set_preceding\strutdepth \ifcarryoverfootnotes \else - \global\setbox\postcolumnbox\vbox{\placebottomnotes}% + \global\setbox\b_page_set_trailing\vbox{\placebottomnotes}% \fi} \let\precolumnlines \!!zerocount \let\postcolumnlines\!!zerocount \def\OTRSEThandlepreposttext - {\ifdim\ht\precolumnbox>\zeropoint % new - \getnoflines{\ht\precolumnbox}% + {\ifdim\ht\b_page_set_preceding>\zeropoint % new + \getnoflines{\ht\b_page_set_preceding}% \edef\precolumnlines{\the\noflines}% \doOTRSETsetgridcells {\copy\placeholderboxe} \plusone\plusone\nofcolumns\noflines % normal version (single column set) - % {\box\precolumnbox}% + % {\box\b_page_set_preceding}% % compensated for bodyfont change {\hbox {\OTRSETsetcorrectcellht - \raise\scratchdimen\box\precolumnbox}}% + \raise\scratchdimen\box\b_page_set_preceding}}% \else \let\precolumnlines\!!zerocount \fi - \ifdim\ht\postcolumnbox>\zeropoint % new, otherwise empty bottom line - \getnoflines{\ht\postcolumnbox}% + \ifdim\ht\b_page_set_trailing>\zeropoint % new, otherwise empty bottom line + \getnoflines{\ht\b_page_set_trailing}% \edef\postcolumnlines{\the\noflines}% \advance\columnfreecells -\noflines \advance\columnfreecells \plusone \doOTRSETsetgridcells {\copy\placeholderboxe} \plusone\columnfreecells\nofcolumns\noflines - {\box\postcolumnbox}% + {\box\b_page_set_trailing}% \else \let\postcolumnlines\!!zerocount \fi} @@ -1858,7 +1869,7 @@ \def\OTRSETcheckgrid {\topskip1\topskip - \ifforcecolumngrid + \ifforcecolumnsetgrid \widowpenalty\zerocount \clubpenalty\zerocount \brokenpenalty\zerocount @@ -2049,7 +2060,10 @@ \let\OTRSETdodosettopinserts\relax % to be tested \else \xdef\totaltopinserted{\the\d_page_floats_inserted_top}% - \insert\c_page_floats_insertions_top{\forgetall\box\scratchbox}% interlineskip ? + \insert\namedinsertionnumber\s!topfloat\bgroup + \forgetall + \box\scratchbox + \egroup \ifconditional\c_page_floats_some_waiting \advance\noffloatinserts \plusone \else @@ -2078,10 +2092,11 @@ \page_floats_get \global\advance\d_page_floats_inserted_bottom\dimexpr\ht\floatbox+\dp\floatbox+\d_strc_floats_top\relax \ifdim\d_page_floats_inserted_bottom<\pagegoal\relax - \insert\c_page_floats_insertions_bottom - {\forgetall - \blank[\rootfloatparameter\c!spacebefore]% - \page_otr_command_flush_float_box}% + \insert\namedinsertionnumber\s!bottomfloat\bgroup + \forgetall + \blank[\rootfloatparameter\c!spacebefore]% + \page_otr_command_flush_float_box + \egroup \ifconditional\c_page_floats_some_waiting \advance\noffloatinserts \plusone \else @@ -2102,27 +2117,27 @@ \OTRSETdodosetbotinserts} \unexpanded\def\page_set_command_flush_top_insertions - {\ifvoid\c_page_floats_insertions_top\else + {\ifvoid\namedinsertionnumber\s!topfloat\else \ifvoid\columntopbox\mofcolumns - \columnsettopbox\mofcolumns\box\c_page_floats_insertions_top + \columnsettopbox\mofcolumns\box\namedinsertionnumber\s!topfloat \else \columnsettopbox\mofcolumns\vbox % temp, must be better {\forgetall \offinterlineskip \box\columntopbox\mofcolumns - \box\c_page_floats_insertions_top} + \box\namedinsertionnumber\s!topfloat} \fi \fi \global\d_page_floats_inserted_top\zeropoint\relax} % goes away \unexpanded\def\page_set_command_flush_bottom_insertions - {\ifvoid\c_page_floats_insertions_bottom \else - \columnsetbotbox\mofcolumns\box\c_page_floats_insertions_bottom + {\ifvoid\namedinsertionnumber\s!bottomfloat \else + \columnsetbotbox\mofcolumns\box\namedinsertionnumber\s!bottomfloat % \else % \columnsetbotbox\mofcolumns\vbox % temp, must be better % {\forgetall % \offinterlineskip -% \box\c_page_floats_insertions_bottom +% \box\namedinsertionnumber\s!bottomfloat % \box\columnbotbox\mofcolumns} \fi \global\d_page_floats_inserted_bottom\zeropoint\relax} % goes away diff --git a/tex/context/base/page-sid.mkiv b/tex/context/base/page-sid.mkiv index 629596c33..8989b04b5 100644 --- a/tex/context/base/page-sid.mkiv +++ b/tex/context/base/page-sid.mkiv @@ -210,10 +210,7 @@ \doloop {\strut \iftracesidefloats - \color[darkgray]% - {\baselinerulefalse - \boxrulewidth.5\points - \ruledhbox{\strut\kern\d_page_sides_width}}% + \color[darkgray]{\ruledhbox{\strut\kern\d_page_sides_width}}% \fi \par \ifdim\dimexpr\d_page_sides_vsize-\pagetotal\relax>\zeropoint diff --git a/tex/context/base/s-art-01.mkiv b/tex/context/base/s-art-01.mkiv index 10b4de9ab..c8d849d8c 100644 --- a/tex/context/base/s-art-01.mkiv +++ b/tex/context/base/s-art-01.mkiv @@ -2,6 +2,8 @@ % \showframe +\unprotect + \setuplayout [\c!topspace=2cm, \c!bottomspace=2.5cm, @@ -33,4 +35,6 @@ [\c!style=\bf, \c!after=] +\protect + \stopmodule diff --git a/tex/context/base/spac-ver.mkiv b/tex/context/base/spac-ver.mkiv index 4ffdeaf85..5737fc201 100644 --- a/tex/context/base/spac-ver.mkiv +++ b/tex/context/base/spac-ver.mkiv @@ -1495,7 +1495,7 @@ \ruledvbox \fi} -\def\gridboxwidth{\ifcase\gridboxlinemode0\or.5\or.5\or0\else.5\fi\testrulewidth} +\def\gridboxwidth{\ifcase\gridboxlinemode0\or.5\or.5\or0\else.5\fi\linewidth} \unexpanded\def\setgridbox#1#2#3% maybe ifgridsnapping at outer level {\setbox#1\gridboxvbox to #3 % given size @@ -1503,10 +1503,10 @@ \resetteststrut \offinterlineskip \hsize#2% - \baselinerulefalse \ifnum\gridboxlinenomode=\plusthree \gridboxlinenomode\ifodd\realpageno\plusone\else\plustwo\fi \fi + \topskipcorrection \gridboxvbox % calculated size {\getrawnoflines{#3}% \getnoflines{#3}% \scratchdimen\dimexpr#2+\lineheight\relax @@ -1515,11 +1515,11 @@ \hskip-.5\lineheight\relax \ifcase\gridboxlinenomode\or \rlap - {\hskip.2\bodyfontsize\hskip\scratchdimen - \infofont\hbox to 1em{\hss\recurselevel}}% + {\hskip\dimexpr.2\bodyfontsize+\scratchdimen\relax + \infofont\hbox to \emwidth{\hss\recurselevel}}% \or \llap - {\infofont\hbox to 1em{\hss\recurselevel}% + {\infofont\hbox to \emwidth{\hss\recurselevel}% \hskip.2\bodyfontsize}% \fi \vrule diff --git a/tex/context/base/status-files.pdf b/tex/context/base/status-files.pdf index 259b6f7cc..5fb854019 100644 Binary files a/tex/context/base/status-files.pdf and b/tex/context/base/status-files.pdf differ diff --git a/tex/context/base/status-lua.pdf b/tex/context/base/status-lua.pdf index 691db3b2d..9c7987cca 100644 Binary files a/tex/context/base/status-lua.pdf and b/tex/context/base/status-lua.pdf differ diff --git a/tex/context/base/status-mkiv.lua b/tex/context/base/status-mkiv.lua index 7bd388abd..c2779d0b4 100644 --- a/tex/context/base/status-mkiv.lua +++ b/tex/context/base/status-mkiv.lua @@ -271,6 +271,11 @@ return { marktype = "mkiv", status = "okay", }, + { + filename = "trac-ctx", + marktype = "mkiv", + status = "okay", + }, { filename = "supp-box", marktype = "mkiv", @@ -311,12 +316,6 @@ return { status = "okay", comment = "will grow", }, - { - filename = "page-ins", - marktype = "mkiv", - status = "okay", - comment = "dealing with insertions might change", - }, { filename = "file-syn", marktype = "mkvi", @@ -703,6 +702,12 @@ return { status = "okay", comment = "code might end up elsewhere", }, + { + filename = "page-ins", + marktype = "mkiv", + status = "okay", + comment = "dealing with insertions might change", + }, { filename = "page-fac", marktype = "mkiv", @@ -797,6 +802,12 @@ return { status = "todo", comment = "will be reimplemented", }, + { + filename = "page-mix", + marktype = "mkiv", + status = "todo", + comment = "work in progress", + }, { filename = "page-set", marktype = "mkiv", diff --git a/tex/context/base/strc-itm.mkvi b/tex/context/base/strc-itm.mkvi index a28eaacd8..5ecf72cc9 100644 --- a/tex/context/base/strc-itm.mkvi +++ b/tex/context/base/strc-itm.mkvi @@ -842,9 +842,6 @@ \let\startcollectitems\relax \let\stopcollectitems \relax -\ifdefined\startcolumns \else \unexpanded\def\startcolumns[#settings]{} \fi -\ifdefined\stopcolumns \else \unexpanded\def\stopcolumns {} \fi - \letvalue{\??itemgroupalign\v!flushleft }\relax \letvalue{\??itemgroupalign\v!right }\relax \letvalue{\??itemgroupalign\v!flushright}\hfill @@ -883,16 +880,31 @@ \def\strc_itemgroups_setup_symbol_asked {\edef\strc_itemgroups_asked_symbol{\itemgroupparameter\c!symbol}} -\def\strc_itemgroups_start_columns - {\startcolumns - [\c!n=\itemgroupparameter\c!n, - \c!height=, - \c!rule=\v!off, - \c!balance=\v!yes, - \c!align=\v!no]} +\ifdefined\strc_itemgroups_start_columns + + % already defined in page-mix + +\else + + % will be redefined in page-mix -\def\strc_itemgroups_stop_columns - {\stopcolumns} + \ifdefined\startcolumns \else + \unexpanded\def\startcolumns[#settings]{} + \unexpanded\def\stopcolumns {} + \fi + + \def\strc_itemgroups_start_columns + {\startcolumns + [\c!n=\itemgroupparameter\c!n, + \c!height=, + \c!rule=\v!off, + \c!balance=\v!yes, + \c!align=\v!no]} + + \def\strc_itemgroups_stop_columns + {\stopcolumns} + +\fi \unexpanded\def\stopitemgroup {\stopcollectitems diff --git a/tex/context/base/strc-not.mkvi b/tex/context/base/strc-not.mkvi index 74e4345aa..05bca36ba 100644 --- a/tex/context/base/strc-not.mkvi +++ b/tex/context/base/strc-not.mkvi @@ -364,14 +364,12 @@ \installcorenamespace{noteinsertion} -\def\currentnoteins{\csname\??noteinsertion\currentnote\endcsname} - \appendtoks - \ifcsname\??noteinsertion\currentnote\endcsname\else - \expandafter\installinsertion\csname\??noteinsertion\currentnote\endcsname\relax - \normalexpanded{\t_strc_notes{\the\t_strc_notes\noexpand\strc_notes_process_list{\currentnote}}}% - \fi - \ctxlua{structures.notes.define("\currentnote","insert",\number\currentnoteins)}% + \defineinsertion[\currentnote]% + \doifinsertionelse\currentnote + {\normalexpanded{\t_strc_notes{\the\t_strc_notes\noexpand\strc_notes_process_list{\currentnote}}}} + \donothing + \ctxlua{structures.notes.define("\currentnote","insert",\number\namedinsertionnumber\currentnote)}% \ifx\currentnoteparent\empty \definenotation[\currentnote][\c!type=\v!note]% \else @@ -843,7 +841,7 @@ \ifx\p_factor\empty \else \ifnum\p_factor<\zerocount \else % \global - \count\currentnoteins\p_factor % new: global + \count\namedinsertionnumber\currentnote\p_factor % new: global \fi \fi} @@ -959,9 +957,9 @@ {\setfalse\c_strc_notes_delayed \strc_notes_set_distance \strc_notes_set_columns - \global\count\currentnoteins\numexpr\plusthousand/\c_strc_notes_columns\relax - \global\dimen\currentnoteins\ifnotelimit\dimexpr\noteparameter\c!height*\c_strc_notes_columns\relax\else\maxdimen\fi - \global\skip \currentnoteins\s_strc_notes_distance} + \global\count\namedinsertionnumber\currentnote\numexpr\plusthousand/\c_strc_notes_columns\relax + \global\dimen\namedinsertionnumber\currentnote\ifnotelimit\dimexpr\noteparameter\c!height*\c_strc_notes_columns\relax\else\maxdimen\fi + \global\skip \namedinsertionnumber\currentnote\s_strc_notes_distance} \def\strc_notes_set_location_columns {\setfalse\c_strc_notes_delayed @@ -970,26 +968,26 @@ \ifnum\currentnofcolumns=\zerocount \c_strc_notes_columns\plusone \fi - \global\count\currentnoteins\numexpr\plusthousand/\c_strc_notes_columns\relax - \global\dimen\currentnoteins\ifnotelimit\dimexpr\noteparameter\c!height*\c_strc_notes_columns\relax\else\maxdimen\fi - \global\skip \currentnoteins\s_strc_notes_distance} + \global\count\namedinsertionnumber\currentnote\numexpr\plusthousand/\c_strc_notes_columns\relax + \global\dimen\namedinsertionnumber\currentnote\ifnotelimit\dimexpr\noteparameter\c!height*\c_strc_notes_columns\relax\else\maxdimen\fi + \global\skip \namedinsertionnumber\currentnote\s_strc_notes_distance} \def\strc_notes_set_location_firstcolumn {\setfalse\c_strc_notes_delayed \strc_notes_set_distance \strc_notes_set_columns - \global\count\currentnoteins\plusthousand - \global\dimen\currentnoteins\ifnotelimit\noteparameter\c!height\else\maxdimen\fi - \global\skip \currentnoteins\s_strc_notes_distance} + \global\count\namedinsertionnumber\currentnote\plusthousand + \global\dimen\namedinsertionnumber\currentnote\ifnotelimit\noteparameter\c!height\else\maxdimen\fi + \global\skip \namedinsertionnumber\currentnote\s_strc_notes_distance} \let\strc_notes_set_location_lastcolumn\strc_notes_set_location_firstcolumn \def\strc_notes_set_location_text % we don't use inserts anyway (e.g. endnotes) {\settrue\c_strc_notes_delayed \ctxlua{structures.notes.setstate("\currentnote","store")}% - \global\count\currentnoteins\zerocount - \global\dimen\currentnoteins\maxdimen - \global\skip \currentnoteins\zeropoint} + \global\count\namedinsertionnumber\currentnote\zerocount + \global\dimen\namedinsertionnumber\currentnote\maxdimen + \global\skip \namedinsertionnumber\currentnote\zeropoint} \let\strc_notes_set_location_none\strc_notes_set_location_text @@ -1013,7 +1011,7 @@ \newconditional\c_notes_bottom_present \def\strc_notes_check_if_bottom_present_indeed % in otr ! - {\ifvoid\currentnoteins\else + {\ifvoid\namedinsertionnumber\currentnote\else \strc_notes_set_position \fi} @@ -1134,7 +1132,7 @@ \strc_constructions_initialize{#1}% \strc_notes_synchronize \the\everybeforenoteinsert - \insert\currentnoteins\bgroup + \insert\namedinsertionnumber\currentnote\bgroup \the\everyinsidenoteinsert\relax \doprocesslocalsetups{\noteparameter\c!setups}% experimental \doifelse{\noteparameter\c!paragraph}\v!yes @@ -1236,14 +1234,14 @@ \def\strc_notes_place_inserts {\strc_notes_set_delayed % \strc_notes_synchronize % we need to know if it's delayed \ifconditional\c_strc_notes_delayed \else - \ifdim\ht\currentnoteins>\zeropoint % or a faster delayed test + \ifdim\ht\namedinsertionnumber\currentnote>\zeropoint % or a faster delayed test \strc_notes_place_inserts_indeed \fi \fi} \def\strc_notes_place_inserts_indeed {\relax - \ifdim\ht\currentnoteins>\zeropoint + \ifdim\ht\namedinsertionnumber\currentnote>\zeropoint \endgraf \ifvmode \whitespace @@ -1291,13 +1289,11 @@ \fi} \def\strc_notes_flush_inserts_normal - {%\iftrialtypesetting\copy\else\box\fi\currentnoteins - \strc_notes_flush_global + {\strc_notes_flush_global \obeydepth} % (a) added , since split footnotes will not align properly \def\strc_notes_flush_inserts_columns {\startsimplecolumns[\c!distance=\noteparameter\c!columndistance,\c!n=\noteparameter\c!n,\c!width=\noteparameter\c!width]% - %\iftrialtypesetting\unvcopied\else\unvboxed\fi\currentnoteins % compare with local \strc_notes_flush_global \stopsimplecolumns} @@ -1313,18 +1309,15 @@ {\doifelse{\noteparameter\c!paragraph}\v!yes {\vbox {\beginofshapebox - \iftrialtypesetting\unvcopied\else\unvboxed\fi\currentnoteins + \iftrialtypesetting\unvcopied\else\unvboxed\fi\namedinsertionnumber\currentnote \endofshapebox - %\doreshapebox{\box\shapebox}{}{}{}% get rid of penalties etc \let\strc_notes_between_paragraphs_indeed\strc_notes_between_paragraphs_first % shape works reverse \doreshapebox {\hbox{\unhbox\shapebox\strc_notes_between_paragraphs_indeed}} - {}% - {}% - {}% get rid of penalties etc + \donothing \donothing \donothing % get rid of penalties etc \innerflushshapebox \convertvboxtohbox}} - {\iftrialtypesetting\unvcopied\else\unvboxed\fi\currentnoteins}} + {\iftrialtypesetting\unvcopied\else\unvboxed\fi\namedinsertionnumber\currentnote}} %D Supporting end notes is surprisingly easy. Even better, we %D can combine this feature with solving the common \TEX\ @@ -1358,7 +1351,7 @@ % we need a proper state: normal, postponing, flushing -\def\postponenotes +\unexpanded\def\postponenotes {\ifconditional\postponingnotes\else \global\settrue\postponingnotes \global\let\flushnotes\doflushnotes @@ -1367,7 +1360,7 @@ \let\flushnotes\relax -\def\doflushnotes +\unexpanded\def\doflushnotes {\ifconditional\postponingnotes \begingroup \let\flushnotes \relax @@ -1595,7 +1588,7 @@ \strc_notes_process\strc_notes_check_presence} \def\strc_notes_check_presence - {\ifdim\ht\currentnoteins>\zeropoint + {\ifdim\ht\namedinsertionnumber\currentnote>\zeropoint \notespresenttrue \fi} @@ -1604,7 +1597,7 @@ % used in page-mul - \ifdefined\currentnofcolumns\else \def\currentnofcolumns{\@@kln} \fi + \ifdefined\currentnofcolumns\else \def\currentnofcolumns{\nofcolumns} \fi \unexpanded\def\fakenotes {\ifhmode\endgraf\fi\ifvmode @@ -1620,29 +1613,31 @@ \newdimen\totalnoteheight - \def\doaddtototalnoteheight#1% - {\ifdim\ht#1>\zeropoint - \ifcase\count#1\else - % todo: divide by count - \advance\totalnoteheight\ht #1% - \advance\totalnoteheight\skip#1% + \unexpanded\def\additionaltotalnoteheight#1% temp hacks anyway + {\dimexpr + \ifdim\ht#1>\zeropoint + \ifcase\count#1 + \zeropoint + \else % todo: divide by count + \ht#1+\skip#1% hm, no stretch but a dimen anyway + \fi + \else + \zeropoint \fi - \fi} + \relax} \def\docalculatetotalnoteheight {\ifcase\c_strc_notes_page_location % tricky here ! ! ! to be sorted out ! ! ! - \doaddtototalnoteheight\currentnoteins - \else - % \doaddtototalnoteheight\currentbackupnoteins + \advance\totalnoteheight\normalexpanded{\additionaltotalnoteheight\namedinsertionnumber\currentnote}% \fi} \def\docalculatetotalclevernoteheight {\ifcase\c_strc_notes_page_location \else % tricky here ! ! ! to be sorted out ! ! ! - \doaddtototalnoteheight\currentnoteins + \advance\totalnoteheight\normalexpanded{\additionaltotalnoteheight\namedinsertionnumber\currentnote}% \fi} \def\docalculatetotalpagenoteheight - {\doaddtototalnoteheight\currentnoteins} + {\advance\totalnoteheight\normalexpanded{\additionaltotalnoteheight\namedinsertionnumber\currentnote}} \def\calculatetotalnoteheight {\totalnoteheight\zeropoint\strc_notes_process\docalculatetotalnoteheight} \def\calculatetotalclevernoteheight{\totalnoteheight\zeropoint\strc_notes_process\docalculatetotalclevernoteheight} @@ -1670,7 +1665,7 @@ %D \stoptyping % \def\dosynchronizenotes -% {\ifvoid\currentnoteins\else\insert\currentnoteins{\unvbox\currentnoteins}\fi} +% {\ifvoid\namedinsertionnumber\currentnote\else\insert\namedinsertionnumber\currentnote{\unvbox\namedinsertionnumber\currentnote}\fi} % % \def\synchronizenotes % {\strc_notes_process\dosynchronizenotes} diff --git a/tex/context/base/strc-reg.lua b/tex/context/base/strc-reg.lua index 6da58345b..23609cfd9 100644 --- a/tex/context/base/strc-reg.lua +++ b/tex/context/base/strc-reg.lua @@ -266,6 +266,10 @@ local function preprocessentries(rawdata) end rawdata.entries = nil end + local seeword = rawdata.seeword + if seeword then + seeword.processor, seeword.text = splitprocessor(seeword.text or "") + end end function registers.store(rawdata) -- metadata, references, entries @@ -826,10 +830,11 @@ function registers.flush(data,options,prefixspec,pagespec) context.startregisterseewords() for i=1,nt do local entry = t[i] - local processor = entry.processors and entry.processors[1] or "" + local seeword = entry.seeword + local seetext = seeword.text or "" + local processor = seeword.processor or (entry.processors and entry.processors[1]) or "" local seeindex = entry.references.seeindex or "" - local seeword = entry.seeword.text or "" - context.registerseeword(i,n,processor,0,seeindex,seeword) + context.registerseeword(i,n,processor,0,seeindex,seetext) end context.stopregisterseewords() end diff --git a/tex/context/base/strc-reg.mkiv b/tex/context/base/strc-reg.mkiv index e90de80ec..973c6effd 100644 --- a/tex/context/base/strc-reg.mkiv +++ b/tex/context/base/strc-reg.mkiv @@ -332,7 +332,7 @@ \normalexpanded{\ctxlua{structures.registers.extend("\currentregister","\currentregisterlabel", { metadata = { \ifx\currentregisterownnumber\v!yes - own = "\registerparameter\c!alternative", % can be used instead of pagenumber + own = "\registerparameter\c!alternative", % can be used instead of pagenumber \fi }, userdata = structures.helpers.touserdata(\!!bs\detokenize{#3}\!!es) @@ -349,7 +349,8 @@ }, entries = { % we need a special one for xml, this is just a single one - \!!bs\currentregisterentries\!!es, \!!bs\currentregisterkeys\!!es + \!!bs\currentregisterentries\!!es, + \!!bs\currentregisterkeys\!!es }, userdata = structures.helpers.touserdata(\!!bs\detokenize{#3}\!!es) }) @@ -433,10 +434,11 @@ }, entries = { % we need a special one for xml, this is just a single one - "\currentregisterentries", "#2" + \!!bs\currentregisterentries\!!es, + \!!bs#2\!!es }, seeword = { - text = "\currentregisterseeword" + text = \!!bs\currentregisterseeword\!!es }, } }}% diff --git a/tex/context/base/syst-aux.mkiv b/tex/context/base/syst-aux.mkiv index 0571fd00f..bc75789bd 100644 --- a/tex/context/base/syst-aux.mkiv +++ b/tex/context/base/syst-aux.mkiv @@ -4702,12 +4702,12 @@ \let\syst_helpers_split_string\relax -\def\beforesplitstring#1\at#2\to#3% +\unexpanded\def\beforesplitstring#1\at#2\to#3% {\def\syst_helpers_split_string##1#2##2#2##3\\% {\def#3{##1}}% \expandafter\syst_helpers_split_string#1#2#2\\} -\def\aftersplitstring#1\at#2\to#3% +\unexpanded\def\aftersplitstring#1\at#2\to#3% {\def\syst_helpers_split_string##1#2##2@@@##3\\% {\def#3{##2}}% \expandafter\syst_helpers_split_string#1@@@#2@@@\\} @@ -4717,7 +4717,7 @@ %D %D A bonus macro. -\def\splitstring#1\at#2\to#3\and#4% +\unexpanded\def\splitstring#1\at#2\to#3\and#4% {\def\syst_helpers_split_string##1#2##2\empty\empty\empty##3\\% {\def#3{##1}% \def\syst_helpers_split_string{##3}% @@ -4728,7 +4728,7 @@ \fi}% \expandafter\syst_helpers_split_string#1\empty\empty\empty#2\empty\empty\empty\\} -\def\greedysplitstring#1\at#2\to#3\and#4% +\unexpanded\def\greedysplitstring#1\at#2\to#3\and#4% {\edef\asciib{#1}% \let\asciic\asciib \let#3\empty @@ -4750,12 +4750,12 @@ %D aftertestandsplitstring, %D testandsplitstring} -\def\beforetestandsplitstring#1\at#2\to#3% +\unexpanded\def\beforetestandsplitstring#1\at#2\to#3% {\def\syst_helpers_split_string##1#2##2#2##3##4\\% {\ifx##3\empty\let#3\empty\else\def#3{##1}\fi}% \expandafter\syst_helpers_split_string#1#2#2\empty\\} -\def\aftertestandsplitstring#1\at#2\to#3% +\unexpanded\def\aftertestandsplitstring#1\at#2\to#3% {\def\syst_helpers_split_string ##1#2##2@@@##3##4\\% {\ifx##3\empty\let#3\empty\else\def#3{##2}\fi}% \expandafter\syst_helpers_split_string #1@@@#2@@@\empty\\} @@ -4776,7 +4776,7 @@ %D %D Which in terms of \TEX\ looks like: -\def\removesubstring#1\from#2\to#3% +\unexpanded\def\removesubstring#1\from#2\to#3% {\splitstring#2\to\m_syst_string_one\and\m_syst_string_two \dodoglobal#3{\m_syst_string_one\m_syst_string_two}} diff --git a/tex/context/base/trac-ctx.lua b/tex/context/base/trac-ctx.lua new file mode 100644 index 000000000..dd3aa392a --- /dev/null +++ b/tex/context/base/trac-ctx.lua @@ -0,0 +1,36 @@ +if not modules then modules = { } end modules ['trac-ctx'] = { + version = 1.001, + comment = "companion to trac-ctx.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +tex.trackers = tex.trackers or { } + +local textrackers = tex.trackers +local register = trackers.register + +storage.register("tex/trackers",textrackers,"tex.trackers") + +local function doit(tag,v) + local tt = textrackers[tag] + if tt then + context.unprotect() + context(v and tt[1] or tt[2]) + context.protect() + end +end + +function commands.initializetextrackers() + for tag, commands in next, textrackers do + register(tag, function(v) doit(tag,v) end) -- todo: v,tag in caller + end +end + +function commands.installtextracker(tag,enable,disable) + textrackers[tag] = { enable, disable } + register(tag, function(v) doit(tag,v) end) -- todo: v,tag in caller +end + +-- lua.registerfinalizer(dump,"dump storage") diff --git a/tex/context/base/trac-ctx.mkiv b/tex/context/base/trac-ctx.mkiv new file mode 100644 index 000000000..4aeb99116 --- /dev/null +++ b/tex/context/base/trac-ctx.mkiv @@ -0,0 +1,28 @@ + +%D \module +%D [ file=trac-ctx, +%D version=2012.07.13, +%D title=\CONTEXT\ Tracing Macros, +%D subtitle=TeX Trackers, +%D author=Hans Hagen, +%D date=\currentdate, +%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] +%C +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA. See mreadme.pdf for +%C details. + +\writestatus{loading}{ConTeXt Tracing Macros / TeX Trackers} + +\registerctxluafile{trac-ctx}{1.001} + +\unprotect + +\unexpanded\def\installtextracker#1#2#3% + {\ctxcommand{installtextracker("#1",\!!bs\detokenize{#2}\!!es,\!!bs\detokenize{#3}\!!es)}} + +\appendtoks + \ctxcommand{initializetextrackers()}% +\to \everyjob + +\protect \endinput diff --git a/tex/context/base/typo-txt.mkvi b/tex/context/base/typo-txt.mkvi index 0e926ed2c..f1c80c1bd 100644 --- a/tex/context/base/typo-txt.mkvi +++ b/tex/context/base/typo-txt.mkvi @@ -105,10 +105,10 @@ \unexpanded\def\normalizefontdepth {\typo_normalizers_font_at_size\dp} \unexpanded\def\normalizefontline {\typo_normalizers_font_at_size\htdp} -\unexpanded\def\widthspanningtext #text#width#specification{\hbox{\normalizefontwidth \temp{#text}{#width}{#specification}\temp#text}} -\unexpanded\def\heightspanningtext#text#width#specification{\hbox{\normalizefontheight\temp{#text}{#width}{#specification}\temp#text}} -\unexpanded\def\depthspanningtext #text#width#specification{\hbox{\normalizefontdepth \temp{#text}{#width}{#specification}\temp#text}} -\unexpanded\def\linespanningtext #text#width#specification{\hbox{\normalizefontline \temp{#text}{#width}{#specification}\temp#text}} +\unexpanded\def\widthspanningtext #text#size#specification{\hbox{\normalizefontwidth \temp{#text}{#size}{#specification}\temp#text}} +\unexpanded\def\heightspanningtext#text#size#specification{\hbox{\normalizefontheight\temp{#text}{#size}{#specification}\temp#text}} +\unexpanded\def\depthspanningtext #text#size#specification{\hbox{\normalizefontdepth \temp{#text}{#size}{#specification}\temp#text}} +\unexpanded\def\linespanningtext #text#size#specification{\hbox{\normalizefontline \temp{#text}{#size}{#specification}\temp#text}} %D Traditionally we use UpperCasedNames for this kind of functionality. diff --git a/tex/context/fonts/demo.lfg b/tex/context/fonts/demo.lfg index 00ca3ee6e..06c59e644 100644 --- a/tex/context/fonts/demo.lfg +++ b/tex/context/fonts/demo.lfg @@ -30,11 +30,36 @@ return { comment = "An example of goodies.", author = "Hans Hagen", featuresets = { + simple = { + mode = "node", + script = "latn" + }, default = { - default, + mode = "node", + script = "latn", + kern = "yes", + }, + ligatures = { + mode = "node", + script = "latn", + kern = "yes", + liga = "yes", }, smallcaps = { - default, smallcaps, + mode = "node", + script = "latn", + kern = "yes", + smcp = "yes", + }, + }, + solutions = { -- here we have references to featuresets, so we use strings! + experimental = { + less = { + "ligatures", "simple", + }, + more = { + "smallcaps", + }, }, }, colorschemes = { diff --git a/tex/generic/context/luatex/luatex-fonts-merged.lua b/tex/generic/context/luatex/luatex-fonts-merged.lua index c84dd2668..b92bf2ab3 100644 --- a/tex/generic/context/luatex/luatex-fonts-merged.lua +++ b/tex/generic/context/luatex/luatex-fonts-merged.lua @@ -1,6 +1,6 @@ -- merged file : luatex-fonts-merged.lua -- parent file : luatex-fonts.lua --- merge date : 07/10/12 09:52:35 +-- merge date : 07/17/12 00:23:01 do -- begin closure to overcome local limits and interference -- cgit v1.2.3