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}