1
% Modified \output-routine for the use with PyX
2
% this file makes changes of \hsize and \vsizes possible after
5
% Copyright (C) 2004 Michael Schindler <m-schindler@sourceforge.net>
7
% This file is part of PyX (http://pyx.sourceforge.net/).
9
% PyX is free software; you can redistribute it and/or modify
10
% it under the terms of the GNU General Public License as published by
11
% the Free Software Foundation; either version 2 of the License, or
12
% (at your option) any later version.
14
% PyX is distributed in the hope that it will be useful,
15
% but WITHOUT ANY WARRANTY; without even the implied warranty of
16
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
% GNU General Public License for more details.
19
% You should have received a copy of the GNU General Public License
20
% along with PyX; if not, write to the Free Software
21
% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29
% Please note that all four tokenlists have to end with {\relax}
30
% This is needed for correct shortening
32
%%%%%%%%%% TeX's part %%%%%%%%%%
33
\newif\ifverbose \verbosefalse
35
\newcount\parno \parno=1
36
\newcount\myprevgraf \myprevgraf=0
37
\newcount\showprevgraf \showprevgraf=0
38
\newcount\outputtype \outputtype=0
40
\newcount\leastcost \leastcost=10000000
43
% Tools for splitting and merging tokenlists after their first element {{{
44
% did I learn too much lisp or what?
45
\def\cdr#1{\expandafter\precdr\expandafter#1\the#1@}
46
\def\numcdr#1{\expandafter\prenumcdr\expandafter#1\the#1@}
47
\def\numconcat#1#2{\edef\foo{{\the#1}\the#2}\global#2=\expandafter{\foo}}
49
\def\precdr#1#2#3@{\ifx#2\relax\relax\global#1={\relax}\else#2\global#1={#3}\fi}
50
\def\prenumcdr#1#2#3@{\ifx\relax#2 0\global#1={\relax}\else#2\global#1={#3}\fi}
53
% The output routine {{{
55
% 1. Question: Who calls the pagebuilder and \output?
56
% Answer: Only \par and $$ (as far as I have read the TeXbook)
58
% 2. Question: So, all together: What is to be done?
59
% Answer: We have to simulate the work of the linebuilder that makes
60
% paragraphs and math into lines in order to find out, what value \prevgraf
61
% might have at a pagepreak. Then, we change the \hsize and \vsize at the
62
% pagepreak and inform PyX about the value of \prevgraf.
64
% 3. Question: When is \prevgraf advanced?
65
% Answer: At every line by 1 and at every display math by 3
67
% 4. Question: How can we hook into the pagebuilding mechanism to find out
68
% about lines and displays?
69
% Answer: We get into the pagebuilder that splits vertical lists into pages
70
% if we enforce a penalty of less than -10000. There are three built-in
71
% hooks: \interlinepenalty
74
% These are set to values less than -10000 by wrapping \par and $$, the
75
% ones who call the pagebuilder and, therefore, \output
77
% Unfortunately, we get only "breaks", but we are interested in lines. At
78
% each list, we have one break less than lines. So, we have to add another
79
% call of \output at the end of a paragraph. This is done by an explicit
81
% A display math succeeding some text also calls the pagebuilder. We have
82
% to add another line in such situations. This is done in the output
83
% routine while processing \predisplaypenalty.
85
% 5. Question: Why are there so many \ifnum s in the output routine?
86
% Answer: As explained avove, we have to do different things at different
87
% positions of our text. \interlinepenalty and the \penalty for paragraph
88
% endings have to add a line. \postdisplaypenalty has to add the display
89
% (advances \prevgraf by 3), while \predisplaypenalty may still reside on
90
% the previous page, while the display math has moved to the next one.
91
% Therefore, it does not contribute to the \prevgraf. Nevertheless, if
92
% there was some text before the display math in the same paragraph, we
93
% still have to add the last line of text!
95
% This is the reason for the whole \outputtype business:
96
% We have to show a \prevgraf value different to \myprevgraf at a situation
97
% where an \interlinepenalty is followed by a \predisplaypenalty which is
98
% followed by a pagebreak. The display is on the next page.
99
% The same can -- of course -- also occur with a \predisplaypenalty
100
% following a \penalty caused by \par
102
% 6. Question: What the hell does \leastcost do?
103
% Answer: This is a tricky point. We hooked into the pagebuilding mechanism
104
% by changing penalties. In this case, TeX thinks, there is a very good
105
% pagebreak and calls \output. But \output removes the strongly negative
106
% penalty we added. Now, TeX has to reconsider the pagebreak and may come
107
% to the result that some of the lines that have appeared as perfect
108
% pagebreaks are not so perfect...
109
% Therefore, before we re-inject the whole vertical list and remove the
110
% negative penalty by saying
111
% \unvbox255 \advance\outputpenalty by XXXXXX \penalty\outputpenalty
112
% we have to know in advance, what the pagebuilder will think of the
113
% pagebreak in the next run. See the TeXbook, p. 111 for the correct
116
% This is the reason for \showprevgraf. We have two counters:
117
% - \myprevgraf counts real lines and displays. This keeps us up-to-date
118
% with the paragraph all the time
119
% - \showprevgraf only counts what will be visible on the current page. It
120
% will be reset to \myprevgraf after the pagebreak.
122
% 7. Question: What do you do to \deadcycles?
123
% Answer: \deadcycles is advanced every time an \output routine has
124
% re-inserted \box255 into the recent contributions. We have to do this for
125
% every line and display math. Therefore, we are restricted to
126
% \maxdeadcycles lines or displays :-(
127
% To avoid this, we cheat the counting of deadcycles and re-advance
128
% \deadcycles by -1. Please, be careful with this hack!
130
\def\setshowprevgraf#1{%
131
% \futurecost will be the cost in the next step (TeXBook, p.111)
133
\advance\futurecost by\outputpenalty
134
% redo Knuth's formula for pagebreaking: futurecost (is the penalty), badness and insertpenalties
135
\ifnum\insertpenalties<10000
136
\ifnum\futurecost<-9999
137
\else\ifnum\futurecost<10000
139
\advance\futurecost by\badness
140
\else\ifnum\badness=10000
143
\futurecost=10000000 % infinity
146
\futurecost=10000 % this case is not in Knuth's formula !??
149
\futurecost=10000000 % infinity
151
% track the leastcost up to now and
152
% set showprevgraf to the current value of myprevgraf
153
\ifnum\futurecost>\leastcost\else
154
\global\leastcost=\futurecost
155
\global\showprevgraf=\myprevgraf
157
% show some debugging info
160
\def\inform{\ifverbose\immediate\write16{%
161
\space myprevgraf=\the\myprevgraf
162
\space showprevgraf=\the\showprevgraf
163
\space futurecost=\the\futurecost
164
\space leastcost=\the\leastcost}\fi
166
% at the end of all input we will need \showprevgraf to be \myprevgraf
167
% \supereject is called by \bye
168
% and explicitly by the textboxes() method
169
\edef\savesupereject{\supereject}
170
\def\supereject{\global\showprevgraf=\myprevgraf\savesupereject}
171
% save whatever someone said to be the output routine
172
% \plainoutput uses \makeheadline and \makefootline
176
\saveoutput=\expandafter{\the\output}
177
\def\linemarker{\PyXMarker{start@\the\parno@\the\myprevgraf}}
179
\tempcnt=\deadcycles \advance\tempcnt by-1 \deadcycles=\tempcnt%
181
\ifnum\outputpenalty>\razor
182
%%%%%%%%%% End of the page %%%%%%%%%%
183
\immediate\write16{PyXVariableBox:page=\the\pageno,par=\the\parno,prevgraf=\the\showprevgraf:}%
185
\global\showprevgraf=\myprevgraf
186
\tempcnt=\deadcycles \advance\tempcnt by 1 \deadcycles=\tempcnt
188
% \global\outputtype=0 % this has no outputtype!! Otherwise, the outputtype of the last page is lost
189
% e.g. <textline> <pagebreak> <textline> <display> makes
190
% <\interlinepenalty (1)> <pagebreak (!!! not 0!!!)> <\predisplaypenalty (should be 5, not 2)>
191
% after the page has been shipped out, we need a new leastcost
192
\global\leastcost=10000000
193
% do whatever someone told to be the output routine
195
% and change the \hsize and \vsize
196
\cdr\lovsizes \cdr\lohsizes
197
\else\advance\razor by -100000 \ifnum\outputpenalty>\razor
198
%%%%%%%%%% InterLinePenalty: -100000 %%%%%%%%%%
199
\ifverbose\immediate\write16{******** InterLinePenalty ********}\fi
200
\global\advance\myprevgraf by 1
201
% this will be the cost in the next page break finding:
202
\setshowprevgraf{100000}
205
% and re-inject the whole page with the original penalty
209
% \setbox0=\hbox to \the\wd0{\PyXMarker{start@\the\parno@\the\myprevgraf}%
211
% \PyXMarker{end@\the\parno@\the\myprevgraf}}%
212
% \nointerlineskip\box0%
213
\advance\outputpenalty by 100000 \penalty\outputpenalty
214
\else\advance\razor by -100000 \ifnum\outputpenalty>\razor
215
%%%%%%%%%% PreDisplayPenalty: -200000 %%%%%%%%%%
216
\ifverbose\immediate\write16{******** PreDisplayPenalty ********}\fi
218
\global\advance\myprevgraf by 1 % this is for the last preceding text line
220
% this will be the cost in the next page break finding:
221
\setshowprevgraf{200000}
222
\else\ifnum\outputtype=4
223
\global\advance\myprevgraf by 1 % this is for the first line of the current par
224
% which has no interlinepenalty
226
% this will be the cost in the next page break finding:
227
\setshowprevgraf{200000}
232
% and re-inject the whole page with the original penalty
235
\advance\outputpenalty by 200000 \penalty\outputpenalty
236
\else\advance\razor by -100000 \ifnum\outputpenalty>\razor
237
%%%%%%%%%% PostDisplayPenalty: -300000 %%%%%%%%%%
238
\ifverbose\immediate\write16{******** PostDisplayPenalty ********}\fi
239
\global\advance\myprevgraf by 3 % all prevgraf for the display comes here, not in PreDisplayPenalty
240
% this will be the cost in the next page break finding:
241
\setshowprevgraf{300000}
244
% and re-inject the whole page with the original penalty
247
\advance\outputpenalty by 300000 \penalty\outputpenalty
248
\else\advance\razor by -100000 \ifnum\outputpenalty>\razor
249
%%%%%%%%%% end of the paragraph: \penalty-400000 %%%%%%%%%%
250
\ifverbose\immediate\write16{******** Penalty ********}\fi
251
\global\advance\myprevgraf by 1
252
% this will be the cost in the next page break finding:
253
\setshowprevgraf{400000}
255
% and re-inject the whole page with the original penalty
258
\advance\outputpenalty by 400000 \penalty\outputpenalty
260
%%%%%%%%%% some stuff unknown to us %%%%%%%%%%
261
\immediate\write16{******** VEEEEEEERY negative value of outputpenalty: ERROR? ********}%
263
\tempcnt=\deadcycles\advance\tempcnt by 1 \deadcycles=\tempcnt
267
% We have to reset certain things at the beginning of {{{
268
% every paragraph: Hook into it with \everypar
269
\newtoks\saveeverypar
270
\saveeverypar=\expandafter{\the\everypar}
272
\global\advance\parno by 1
274
\global\showprevgraf=0
275
% \global\leastcost=10000000
276
% check if the following paragraph will need a \parshape
277
% if yes, say the first token of \parshapes
278
% if no, restore the parno number into \parnos.
279
% This has to come in \everypar to avoid content after the last \par
280
\tempcnt=\numcdr\parnos
281
\ifnum\tempcnt=\parno \cdr\parshapes
282
\else \numconcat\tempcnt\parnos
288
% \par calls the pagebuilder and \output {{{
289
% We wrap the \par primitive
290
% - set \interlinepenalty first and reset it afterwards
291
% - call \output another time for the last line of the paragraph
294
\ifvmode\savepar\else\ifinner\savepar\else
295
% \global\leastcost=10000000
296
\advance\interlinepenalty by -100000
297
\vadjust{\penalty-400000}%
299
\advance\interlinepenalty by 100000
303
% $$ also calls the pagebuilder and \output {{{
304
% We wrap these characters with newly defined commands
305
% \display and \enddisplay
306
% XXX Can $ be redefined to achieve the same result?
307
% - $$ (begin) calls the pagebuilder for the previous text
308
% we have to do similar things as in \par
309
% - $$ (end) calls the pagebuilder for the display math
310
% we have to adjust \predisplaypenalty and \postdisplaypenalty
311
% XXX Has \interdisplaylinepenalty any effect on \prevgraf ?
313
% \global\leastcost=10000000
314
\global\advance\interlinepenalty by -100000
316
\global\advance\interlinepenalty by 100000\relax}
318
% \global\leastcost=10000000
319
\global\advance\predisplaypenalty by -200000
320
\global\advance\postdisplaypenalty by -300000
322
\global\advance\predisplaypenalty by 200000
323
\global\advance\postdisplaypenalty by 300000\relax}