page-otr.mkvi /size: 10 Kb    last modification: 2021-10-28 13:50
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
17%D same time we provide a bit more control.
18
19% When issuing two \par\penalty-\plustenthousand's, only the first
20% triggers the otr. Is this an obscure feature or an optimization?
21
22\registerctxluafile{page-otr}{}
23
24\unprotect
25
26\let\triggerpagebuilder\clf_triggerpagebuilder
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\unexpanded\def\defineoutputroutinecommand[#name]% doing multiple on one go saves syncing
36  {\processcommalist[#name]\page_otr_commands_define}
37
38\unexpanded\def\page_otr_commands_define#name%
39  {\ifcsname#name\endcsname \else
40     \expandafter\let\csname#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    \the\t_page_otr_commands
49    \let\page_otr_commands_process\gobbleoneargument
50\to \everyswitchoutputroutine
51
52\unexpanded\def\page_otr_specifics_preset#name%
53  {\edef\page_otr_specifics_command{\directoutputroutineparameter{#name}}% no inheritance of commands
54   \ifx\page_otr_specifics_command\empty
55     \writestatus{\currentoutputroutine}{- \expandafter\strippedcsname\csname#name\endcsname}%
56     \expandafter\let\csname#name\endcsname\relax
57   \else
58     \writestatus{\currentoutputroutine}{+ \expandafter\strippedcsname\csname#name\endcsname}%
59     \expandafter\let\csname#name\expandafter\endcsname\page_otr_specifics_command
60   \fi}
61
62\unexpanded\def\page_otr_specifics_preset_normal#name%
63  {\edef\page_otr_specifics_command{\directoutputroutineparameter{#name}}% no inheritance of commands
64   \ifx\page_otr_specifics_command\empty
65     \expandafter\let\csname#name\endcsname\relax
66   \else
67     \expandafter\let\csname#name\expandafter\endcsname\page_otr_specifics_command
68   \fi}
69
70\unexpanded\def\page_otr_specifics_preset_traced#name%
71  {\edef\page_otr_specifics_command{\directoutputroutineparameter{#name}}% no inheritance of commands
72   \ifx\page_otr_specifics_command\empty
73     \writestatus{\currentoutputroutine}{preset: - \expandafter\strippedcsname\csname#name\endcsname}%
74     \expandafter\let\csname#name\endcsname\relax
75   \else
76     \writestatus{\currentoutputroutine}{preset: + \expandafter\strippedcsname\csname#name\endcsname}%
77     \expandafter\let\csname#name\expandafter\endcsname\page_otr_specifics_command
78   \fi}
79
80\let\page_otr_specifics_preset\page_otr_specifics_preset_normal
81
82\unexpanded\def\traceoutputroutines
83  {\the\t_page_otr_tracers}
84
85\appendtoks
86    \let\page_otr_specifics_preset\page_otr_specifics_preset_traced
87\to \t_page_otr_tracers
88
89%D We have a couple of output routines and the default one is
90%D the single column routine. Then there is a multicolumn variant
91%D that can be used mixed, and a columnset variant that is more
92%D exclusive.
93
94\installcorenamespace{otrtriggers}
95
96\newconstant\c_page_otr_eject_penalty   \c_page_otr_eject_penalty   -\plustenthousand
97\newconstant\c_page_otr_super_penalty   \c_page_otr_super_penalty   -\plustwentythousand
98\newcount   \c_page_otr_trigger_penalty \c_page_otr_trigger_penalty -100010
99
100\newif      \ifinotr % we keep this (name) for old times sake
101
102\unexpanded\def\page_otr_message_b{\page_otr_message_s+}
103\unexpanded\def\page_otr_message_e{\page_otr_message_s-}
104
105\unexpanded\def\page_otr_message_s#sign#what%
106  {\writestatus
107    \currentoutputroutine
108    {#sign\space          \space
109     #what\space          \space
110     p:\the\outputpenalty,\space
111     r:\the\realpageno   ,\space
112     c:\number\mofcolumns,\space
113     v:\the\vsize        ,\space
114     g:\the\pagegoal     ,\space
115     t:\the\pagetotal
116     \ifdim\pagetotal>\pagegoal
117       ,\space
118       d:\the\dimexpr\pagetotal-\pagegoal\relax
119     \fi}}
120
121\unexpanded\def\page_otr_trigger#penalty%
122  {\begingroup
123   \par
124   \penalty#penalty%
125   \endgroup}
126
127\unexpanded\def\installoutputroutine#invoke#action% \invoke \action
128  {\global\advance\c_page_otr_trigger_penalty\minusone
129   \edef#invoke{\page_otr_trigger{\number\c_page_otr_trigger_penalty}}%
130   \setvalue{\??otrtriggers\number\c_page_otr_trigger_penalty}{#action}}
131
132\unexpanded\def\page_otr_triggered_output_routine_traced
133  {\ifcsname\??otrtriggers\the\outputpenalty\endcsname
134     \page_otr_message_b{special}%
135     \csname\??otrtriggers\the\outputpenalty\endcsname % \lastnamedcs can be gone
136     \page_otr_message_e{special}%
137   \else
138     \page_otr_message_b{normal}%
139     \page_otr_command_routine
140     \page_otr_message_e{normal}%
141   \fi}
142
143\unexpanded\def\page_otr_triggered_output_routine_normal
144  {\ifcsname\??otrtriggers\the\outputpenalty\endcsname
145     \lastnamedcs
146   \else
147     \page_otr_command_routine
148   \fi}
149
150\let\page_otr_triggered_output_routine\page_otr_triggered_output_routine_normal
151
152\appendtoks
153    \let\page_otr_triggered_output_routine\page_otr_triggered_output_routine_traced
154\to \t_page_otr_tracers
155
156%D The real routine handler:
157
158\ifdefined\everybeforeoutput \else \newtoks\everybeforeoutput \fi
159\ifdefined\everyafteroutput  \else \newtoks\everyafteroutput  \fi
160
161\def\page_otr_set_engine_output_routine#content%
162  {\global\output
163     {\inotrtrue
164      \the\everybeforeoutput
165      #content\relax
166      \the\everyafteroutput}}
167
168% Just as fuzzy (and in 'one' we are okay with \aftergroup anyway):
169%
170% \ifdefined\everybeforeoutputgroup \else \newtoks\everybeforeoutputgroup \fi
171% \ifdefined\everyafteroutputgroup  \else \newtoks\everyafteroutputgroup  \fi
172%
173% \def\page_otr_set_engine_output_routine#content%
174%   {\the\everybeforeoutputgroup
175%    \global\output
176%      {\inotrtrue
177%       \the\everybeforeoutput
178%       #content\relax
179%       \the\everyafteroutput
180%       \aftergroup\the\aftergroup\everyafteroutputgroup}}
181%
182% \appendtoks
183%     \ifnum\c_page_postponed_mode=\plusone
184%         \page_postponed_blocks_flush % and then not in \page_otr_construct_and_shipout
185%     \fi
186% \to \everyafteroutputgroup
187
188\page_otr_set_engine_output_routine\page_otr_triggered_output_routine
189
190\installoutputroutine\synchronizeoutput % use \triggerpagebuilder instead
191  {\ifvoid\normalpagebox\else
192     \unvbox\normalpagebox
193     % not \pagediscards as it does more harm than good
194   \fi}
195
196\installoutputroutine\discardpage
197  {\setbox\scratchbox\box\normalpagebox}
198
199% todo: \resetpagebreak -> everyejectpage
200
201\def\page_otr_trigger_output_routine
202  {\par
203   \ifvmode
204     \penalty\c_page_otr_eject_penalty
205   \fi
206   \resetpagebreak}
207
208\def\page_otr_fill_and_eject_page
209  {\par
210   \ifvmode
211     \vfill
212     \penalty\c_page_otr_eject_penalty
213   \fi
214   \resetpagebreak}
215
216\def\page_otr_eject_page
217  {\par
218   \ifvmode
219     \ifdim\pagetotal>\pagegoal \else
220       \normalvfil
221     \fi
222     \penalty\c_page_otr_eject_penalty
223   \fi
224   \resetpagebreak}
225
226\def\page_otr_eject_page_and_flush_inserts % can be an installed one
227  {\par
228   \ifvmode
229     \ifdim\pagetotal>\pagegoal \else
230       \normalvfil
231     \fi
232     \penalty\c_page_otr_super_penalty
233   \fi
234   \resetpagebreak}
235
236\def\page_otr_check_for_pending_inserts
237  {\ifnum\outputpenalty>\c_page_otr_super_penalty \else
238     \ifnum\insertpenalties>\zerocount
239       % something is being held over so we force a new page
240       \page_otr_force_another_page
241     \fi
242   \fi}
243
244\def\page_otr_force_another_page
245  {% we should actually remove the dummy line in the otr
246   \hpack to \hsize{}%
247   \kern-\topskip
248   \nobreak
249   \vfill
250   \penalty\c_page_otr_super_penalty
251   \resetpagebreak}
252
253%D For those who've read the plain \TEX\ book, we provide the next
254%D macro:
255
256\unexpanded\def\bye
257  {\writestatus\m!system{Sorry, you're not done yet, so no goodbye!}}
258
259%D We define a few constants because that (1) provides some checking
260%D and (2) is handier when aligning definitions (checks nicer). Most
261%D routines will use ard codes names but sometimes we want to adapt,
262%D which is why we have these:
263
264\definesystemconstant{page_otr_command_routine}
265\definesystemconstant{page_otr_command_package_contents}
266\definesystemconstant{page_otr_command_set_vsize}
267\definesystemconstant{page_otr_command_set_hsize}
268\definesystemconstant{page_otr_command_synchronize_hsize}
269\definesystemconstant{page_otr_command_next_page}
270\definesystemconstant{page_otr_command_next_page_and_inserts}
271\definesystemconstant{page_otr_command_set_top_insertions}
272\definesystemconstant{page_otr_command_set_bottom_insertions}
273\definesystemconstant{page_otr_command_flush_top_insertions}
274\definesystemconstant{page_otr_command_flush_bottom_insertions}
275\definesystemconstant{page_otr_command_check_if_float_fits}
276\definesystemconstant{page_otr_command_set_float_hsize}
277\definesystemconstant{page_otr_command_flush_float_box}
278\definesystemconstant{page_otr_command_side_float_output}
279\definesystemconstant{page_otr_command_synchronize_side_floats}
280\definesystemconstant{page_otr_command_flush_floats}
281\definesystemconstant{page_otr_command_flush_side_floats}
282\definesystemconstant{page_otr_command_flush_saved_floats}
283\definesystemconstant{page_otr_command_flush_all_floats}
284\definesystemconstant{page_otr_command_flush_margin_blocks}
285\definesystemconstant{page_otr_command_test_column}
286\definesystemconstant{page_otr_command_flush_facing_floats}
287
288\definesystemconstant{singlecolumn}
289\definesystemconstant{multicolumn}   % will move
290\definesystemconstant{columnset}     % will move
291\definesystemconstant{pagecolumn}    % will move
292
293\defineoutputroutinecommand
294  [\s!page_otr_command_routine,
295   \s!page_otr_command_package_contents,
296   \s!page_otr_command_set_vsize,
297   \s!page_otr_command_set_hsize,
298   \s!page_otr_command_synchronize_hsize, % for columns of different width
299   \s!page_otr_command_next_page,
300   \s!page_otr_command_next_page_and_inserts,
301   \s!page_otr_command_set_top_insertions,
302   \s!page_otr_command_set_bottom_insertions,
303   \s!page_otr_command_flush_top_insertions,
304   \s!page_otr_command_flush_bottom_insertions,
305   \s!page_otr_command_check_if_float_fits,
306   \s!page_otr_command_set_float_hsize,
307   \s!page_otr_command_flush_float_box,
308   \s!page_otr_command_side_float_output, % name will change as will hooks
309   \s!page_otr_command_synchronize_side_floats,
310   \s!page_otr_command_flush_floats,
311   \s!page_otr_command_flush_side_floats,
312   \s!page_otr_command_flush_saved_floats,
313   \s!page_otr_command_flush_all_floats,
314   \s!page_otr_command_flush_margin_blocks,
315   \s!page_otr_command_test_column,
316   \s!page_otr_command_flush_facing_floats]
317
318\appendtoks
319    \setupoutputroutine[\s!singlecolumn]%
320\to \everydump
321
322\protect \endinput
323