page-otr.mklx /size: 11 Kb    last modification: 2023-12-21 09:44
1%D \module
2%D   [       file=page-otr,
3%D        version=2012.01.25,
4%D          title=\CONTEXT\ Page Macros,
5%D       subtitle=Output Routines,
6%D         author=Hans Hagen,
7%D           date=\currentdate,
8%D      copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
9%C
10%C This module is part of the \CONTEXT\ macro||package and is
11%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
12%C details.
13
14\writestatus{loading}{ConTeXt Page Macros / Output Routines}
15
16%D This module will get some of the code from other modules. At the same time we
17%D provide a bit more control.
18
19% When issuing two \par\penalty-\plustenthousand's, only the first triggers the
20% otr. Is this an obscure feature or an optimization?
21
22\registerctxluafile{page-otr}{autosuffix}
23
24\unprotect
25
26% triggerpagebuilder % defined at the lua end
27
28\installcorenamespace{outputroutine}
29
30\installswitchcommandhandler \??outputroutine {outputroutine} \??outputroutine
31
32\newtoks\t_page_otr_commands
33\newtoks\t_page_otr_tracers
34
35\permanent\protected\def\defineoutputroutinecommand[#name]% doing multiple on one go saves syncing
36  {\processcommalist[#name]\page_otr_commands_define}
37
38\protected\def\page_otr_commands_define#name%
39  {\ifcsname#name\endcsname \else
40     \letcsname#name\endcsname\relax
41     \normalexpanded{\t_page_otr_commands{\the\t_page_otr_commands\noexpand\page_otr_commands_process{#name}}}%
42   \fi}
43
44\let\page_otr_commands_process\gobbleoneargument
45
46\appendtoks
47    \let\page_otr_commands_process\page_otr_specifics_preset
48    \expand\t_page_otr_commands
49    \let\page_otr_commands_process\gobbleoneargument
50\to \everyswitchoutputroutine
51
52% use \csstring
53
54\protected\def\page_otr_specifics_preset#name%
55  {\edef\page_otr_specifics_command{\directoutputroutineparameter{#name}}% no inheritance of commands
56   \ifempty\page_otr_specifics_command
57     \writestatus{\currentoutputroutine}{- \expandafter\strippedcsname\csname#name\endcsname}%
58     \letcsname#name\endcsname\relax
59   \else
60     \writestatus{\currentoutputroutine}{+ \expandafter\strippedcsname\csname#name\endcsname}%
61     \letcsname#name\expandafter\endcsname\page_otr_specifics_command
62   \fi}
63
64\protected\def\page_otr_specifics_preset_normal#name%
65  {\edef\page_otr_specifics_command{\directoutputroutineparameter{#name}}% no inheritance of commands
66   \ifempty\page_otr_specifics_command
67     \letcsname#name\endcsname\relax
68   \else
69     \letcsname#name\expandafter\endcsname\page_otr_specifics_command
70   \fi}
71
72\protected\def\page_otr_specifics_preset_traced#name%
73  {\edef\page_otr_specifics_command{\directoutputroutineparameter{#name}}% no inheritance of commands
74   \ifempty\page_otr_specifics_command
75     \writestatus{\currentoutputroutine}{preset: - \expandafter\strippedcsname\csname#name\endcsname}%
76     \letcsname#name\endcsname\relax
77   \else
78     \writestatus{\currentoutputroutine}{preset: + \expandafter\strippedcsname\csname#name\endcsname}%
79     \letcsname#name\expandafter\endcsname\page_otr_specifics_command
80   \fi}
81
82\let\page_otr_specifics_preset\page_otr_specifics_preset_normal
83
84\permanent\protected\def\traceoutputroutines
85  {\expand\t_page_otr_tracers}
86
87\appendtoks
88    \let\page_otr_specifics_preset\page_otr_specifics_preset_traced
89\to \t_page_otr_tracers
90
91%D We have a couple of output routines and the default one is the single column
92%D routine. Then there is a multicolumn variant that can be used mixed, and a
93%D columnset variant that is more exclusive.
94
95\installcorenamespace{otrtriggers}
96
97\newconstant\c_page_otr_eject_penalty   \c_page_otr_eject_penalty   -\plustenthousand
98\newconstant\c_page_otr_super_penalty   \c_page_otr_super_penalty   -\plustwentythousand
99\newinteger \c_page_otr_trigger_penalty \c_page_otr_trigger_penalty -100010
100
101\newinteger \c_page_otr_columns % we will share this one
102
103\newif      \ifinotr % we keep this (name) for old times sake
104
105% \def\page_otr_update_page_goal#1#2%
106%   {\global\c_page_otr_columns#2\relax
107%    \pagegoal\dimexpr\vsize-\c_page_otr_columns\insertheights\relax}
108
109\appendtoks
110    \insertheights\zeropoint
111\to \everyaftershipout
112
113\protected\def\page_otr_message_b{\page_otr_message_s+}
114\protected\def\page_otr_message_e{\page_otr_message_s-}
115
116\protected\def\page_otr_message_s#sign#what%
117  {\writestatus
118    \currentoutputroutine
119    {#sign\space           \space
120     #what\space           \space
121     p:\the\outputpenalty ,\space
122     r:\the\realpageno    ,\space
123     c:\number\mofcolumns ,\space
124     v:\the\vsize         ,\space
125     g:\the\pagegoal      ,\space
126     t:\the\pagetotal     ,\space
127     h:\the\pagelastheight,\space
128     i:\the\insertheights
129     \ifdim\pagetotal>\pagegoal
130       ,\space
131       d:\the\dimexpr\pagetotal-\pagegoal\relax
132     \fi}}
133
134\protected\def\page_otr_trigger#penalty%
135  {\begingroup
136   \par
137   \penalty#penalty%
138   \endgroup}
139
140\permanent\protected\def\installoutputroutine#invoke#action% \invoke \action
141  {\global\advanceby\c_page_otr_trigger_penalty\minusone
142   \frozen\protected\edef#invoke{\page_otr_trigger{\the\c_page_otr_trigger_penalty}}%
143   \defcsname\??otrtriggers\the\c_page_otr_trigger_penalty\endcsname{#action}}
144
145\protected\def\page_otr_triggered_output_routine_traced
146  {\ifcsname\??otrtriggers\the\outputpenalty\endcsname
147     \page_otr_message_b{special}%
148     \csname\??otrtriggers\the\outputpenalty\endcsname % \lastnamedcs can be gone
149     \page_otr_message_e{special}%
150   \else
151     \page_otr_message_b{normal}%
152     \page_otr_command_routine
153     \page_otr_message_e{normal}%
154   \fi}
155
156\protected\def\page_otr_triggered_output_routine_normal
157  {\ifcsname\??otrtriggers\the\outputpenalty\endcsname
158     \lastnamedcs
159   \else
160     \page_otr_command_routine
161   \fi}
162
163\let\page_otr_triggered_output_routine\page_otr_triggered_output_routine_normal
164
165\appendtoks
166    \let\page_otr_triggered_output_routine\page_otr_triggered_output_routine_traced
167\to \t_page_otr_tracers
168
169%D The real routine handler:
170
171\ifdefined\everybeforeoutput \else \newtoks\everybeforeoutput \fi
172\ifdefined\everyafteroutput  \else \newtoks\everyafteroutput  \fi
173
174\def\page_otr_set_engine_output_routine#content%
175  {\global\output
176     {\inotrtrue
177      \expand\everybeforeoutput
178      #content\relax
179      \expand\everyafteroutput}}
180
181\page_otr_set_engine_output_routine\page_otr_triggered_output_routine
182
183\installoutputroutine\synchronizeoutput % use \triggerpagebuilder instead
184  {\ifvoid\normalpagebox\else
185     \unvbox\normalpagebox
186     % not \pagediscards as it does more harm than good
187   \fi}
188
189\installoutputroutine\discardpage
190  {\setbox\scratchbox\box\normalpagebox}
191
192% todo: \resetpagebreak -> everyejectpage
193
194\def\page_otr_trigger_output_routine
195  {\par
196   \ifvmode
197     \penalty\c_page_otr_eject_penalty
198   \fi
199   \resetpagebreak}
200
201\def\page_otr_fill_and_eject_page
202  {\par
203   \ifvmode
204     \vfill
205     \penalty\c_page_otr_eject_penalty
206   \fi
207   \resetpagebreak}
208
209% In case \pagetotal is ahead of \pagegoal (\pagelastheight is the real one) we
210% need to make sure that we flush but we don't do that in a ragged situation where
211% we have safeguards.
212
213% \setuplayout[limitstretch=yes] % border case 1
214% \setupalign[depth]
215%
216% \starttext
217%     \startitemize
218%         \dorecurse{24}{\startitem test \stopitem}
219%         \dorecurse{3}{\startitem test \stopitem}
220%         \startitem test \stopitem % border case 2
221%     \stopitemize
222% \stoptext
223
224% \def\page_otr_fill_page_unchecked
225%   {\ifdim\pagetotal>\pagegoal \else
226%      \normalvfil
227%    \fi}
228
229\def\page_otr_fill_page_unchecked
230  {% \writestatus{!!!!!}{h=\the\pagelastheight,t=\the\pagetotal,g=\the\pagegoal}%
231   \ifdim\pagetotal>\pagegoal
232     % we're probably okay and are not too flexible
233   \orelse\ifnum\bottomraggednessmode>\plusone
234     % we actualy want to be flexible
235   \else
236     % we have to make sure that we don't stretch
237     \normalvfil
238   \fi}
239
240\def\page_otr_fill_page_checked
241  {\ifdim\dimexpr\pagelastheight+\c_page_scale_lines\lineheight+\pageexcess\relax>\pagegoal\else
242     \normalvfil
243   \fi}
244
245\def\page_otr_eject_page
246  {\par
247   \ifvmode
248     \ifcase\c_page_scale_lines
249       \page_otr_fill_page_unchecked
250     \else
251       \page_otr_fill_page_checked
252     \fi
253     \penalty\c_page_otr_eject_penalty
254   \fi
255   \resetpagebreak}
256
257\def\page_otr_eject_page_and_flush_inserts % can be an installed one
258  {\par
259   \ifvmode
260     \ifcase\c_page_scale_lines
261       \page_otr_fill_page_unchecked
262     \else
263       \page_otr_fill_page_checked
264     \fi
265     \penalty\c_page_otr_super_penalty
266   \fi
267   \resetpagebreak}
268
269\def\page_otr_check_for_pending_inserts
270  {\ifnum\outputpenalty>\c_page_otr_super_penalty
271   \orelse\ifnum\insertpenalties>\zerocount
272     % something is being held over so we force a new page
273     \page_otr_force_another_page
274   \fi}
275
276%D So far.
277
278\def\page_otr_force_another_page
279  {% we should actually remove the dummy line in the otr
280   \hpack to \hsize{}%
281   \kern-\topskip
282   \nobreak
283   \vfill
284   \penalty\c_page_otr_super_penalty
285   \resetpagebreak}
286
287%D For those who've read the plain \TEX\ book, we provide the next macro:
288
289\permanent\protected\def\bye
290  {\writestatus\m!system{Sorry, you're not done yet, so no goodbye!}}
291
292%D We define a few constants because that (1) provides some checking and (2) is
293%D handier when aligning definitions (checks nicer). Most routines will use ard
294%D codes names but sometimes we want to adapt, which is why we have these:
295
296\definesystemconstant{page_otr_command_routine}
297\definesystemconstant{page_otr_command_package_contents}
298\definesystemconstant{page_otr_command_set_vsize}
299\definesystemconstant{page_otr_command_set_hsize}
300\definesystemconstant{page_otr_command_synchronize_hsize}
301\definesystemconstant{page_otr_command_next_page}
302\definesystemconstant{page_otr_command_next_page_and_inserts}
303\definesystemconstant{page_otr_command_set_top_insertions}
304\definesystemconstant{page_otr_command_set_bottom_insertions}
305\definesystemconstant{page_otr_command_flush_top_insertions}
306\definesystemconstant{page_otr_command_flush_bottom_insertions}
307\definesystemconstant{page_otr_command_check_if_float_fits}
308\definesystemconstant{page_otr_command_set_float_hsize}
309\definesystemconstant{page_otr_command_flush_float_box}
310\definesystemconstant{page_otr_command_side_float_output}
311\definesystemconstant{page_otr_command_synchronize_side_floats}
312\definesystemconstant{page_otr_command_flush_floats}
313\definesystemconstant{page_otr_command_flush_side_floats}
314\definesystemconstant{page_otr_command_flush_saved_floats}
315\definesystemconstant{page_otr_command_flush_all_floats}
316\definesystemconstant{page_otr_command_flush_margin_blocks}
317\definesystemconstant{page_otr_command_test_column}
318
319\definesystemconstant{singlecolumn}
320\definesystemconstant{multicolumn}   % will move
321\definesystemconstant{columnset}     % will move
322\definesystemconstant{pagecolumn}    % will move
323
324\defineoutputroutinecommand
325  [\s!page_otr_command_routine,
326   \s!page_otr_command_package_contents,
327   \s!page_otr_command_set_vsize,
328   \s!page_otr_command_set_hsize,
329   \s!page_otr_command_synchronize_hsize, % for columns of different width
330   \s!page_otr_command_next_page,
331   \s!page_otr_command_next_page_and_inserts,
332   \s!page_otr_command_set_top_insertions,
333   \s!page_otr_command_set_bottom_insertions,
334   \s!page_otr_command_flush_top_insertions,
335   \s!page_otr_command_flush_bottom_insertions,
336   \s!page_otr_command_check_if_float_fits,
337   \s!page_otr_command_set_float_hsize,
338   \s!page_otr_command_flush_float_box,
339   \s!page_otr_command_side_float_output, % name will change as will hooks
340   \s!page_otr_command_synchronize_side_floats,
341   \s!page_otr_command_flush_floats,
342   \s!page_otr_command_flush_side_floats,
343   \s!page_otr_command_flush_saved_floats,
344   \s!page_otr_command_flush_all_floats,
345   \s!page_otr_command_flush_margin_blocks,
346   \s!page_otr_command_test_column]
347
348\appendtoks
349    \setupoutputroutine[\s!singlecolumn]%
350\to \everydump
351
352\protect \endinput
353