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 \ifnum\insertpenalties<
10000
135 \ifnum\futurecost<-
9999
136 \else\ifnum\futurecost<
10000
138 \advance\futurecost by
\badness
139 \else\ifnum\badness=
10000
145 \futurecost=
10000 % this case is not in Knuth's formula !??
150 % track the leastcost up to now and
151 % set showprevgraf to the current value of myprevgraf
152 \ifnum\futurecost>
\leastcost\else
153 \global\leastcost=
\futurecost
154 \global\showprevgraf=
\myprevgraf
156 % show some debugging info
159 \def\inform{\ifverbose\immediate\write16{%
160 \space myprevgraf=
\the\myprevgraf
161 \space showprevgraf=
\the\showprevgraf
162 \space futurecost=
\the\futurecost
163 \space leastcost=
\the\leastcost}\fi
166 %\saveoutput=\expandafter{\the\output}
167 \saveoutput=
{\shipout\vbox{\pagebody}\advancepageno\ifnum\outputpenalty>-
20000\else\dosupereject\fi}
169 \tempcnt=
\deadcycles \advance\tempcnt by-
1 \deadcycles=
\tempcnt%
171 \ifnum\outputpenalty>
\razor
172 %%%%%%%%%% End of the page %%%%%%%%%%
173 \immediate\write16{PyXVariableBox:page=
\the\pageno,par=
\the\parno,prevgraf=
\the\showprevgraf:
}%
175 \global\showprevgraf=
\myprevgraf
176 \tempcnt=
\deadcycles \advance\tempcnt by
1 \deadcycles=
\tempcnt
178 % \global\outputtype=0 % this has no outputtype!! Otherwise, the outputtype of the last page is lost
179 % e.g. <textline> <pagebreak> <textline> <display> makes
180 % <\interlinepenalty (1)> <pagebreak (!!! not 0!!!)> <\predisplaypenalty (should be 5, not 2)>
181 % after the page has been shipped out, we need a new leastcost
182 \global\leastcost=
10000000
183 % do whatever someone told to be the output routine
185 % and change the \hsize and \vsize
186 \cdr\lovsizes \cdr\lohsizes
187 \else\advance\razor by -
100000 \ifnum\outputpenalty>
\razor
188 %%%%%%%%%% InterLinePenalty: -100000 %%%%%%%%%%
189 \ifverbose\immediate\write16{******** InterLinePenalty ********
}\fi
190 \global\advance\myprevgraf by
1
191 % this will be the cost in the next page break finding:
192 \setshowprevgraf{100000}
195 % and re-inject the whole page with the original penalty
198 \setbox0=
\hbox to
\the\wd0{\PyXMarker{start@
\the\parno@
\the\myprevgraf}%
200 \PyXMarker{end@
\the\parno@
\the\myprevgraf}}%
201 \nointerlineskip\box0%
202 \advance\outputpenalty by
100000 \penalty\outputpenalty
203 \else\advance\razor by -
100000 \ifnum\outputpenalty>
\razor
204 %%%%%%%%%% PreDisplayPenalty: -200000 %%%%%%%%%%
205 \ifverbose\immediate\write16{******** PreDisplayPenalty ********
}\fi
207 \global\advance\myprevgraf by
1 % this is for the last preceding text line
209 % this will be the cost in the next page break finding:
210 \setshowprevgraf{200000}
211 \else\ifnum\outputtype=
4
212 \global\advance\myprevgraf by
1 % this is for the first line of the current par
213 % which has no interlinepenalty
215 % this will be the cost in the next page break finding:
216 \setshowprevgraf{200000}
217 \else\global\outputtype=
2 \fi\fi
218 % and re-inject the whole page with the original penalty
219 \unvbox255 \advance\outputpenalty by
200000 \penalty\outputpenalty
220 \else\advance\razor by -
100000 \ifnum\outputpenalty>
\razor
221 %%%%%%%%%% PostDisplayPenalty: -300000 %%%%%%%%%%
222 \ifverbose\immediate\write16{******** PostDisplayPenalty ********
}\fi
223 \global\advance\myprevgraf by
3 % all prevgraf for the display comes here, not in PreDisplayPenalty
224 % this will be the cost in the next page break finding:
225 \setshowprevgraf{300000}
228 % and re-inject the whole page with the original penalty
229 \unvbox255 \advance\outputpenalty by
300000 \penalty\outputpenalty
230 \else\advance\razor by -
100000 \ifnum\outputpenalty>
\razor
231 %%%%%%%%%% end of the paragraph: \penalty-400000 %%%%%%%%%%
232 \ifverbose\immediate\write16{******** Penalty ********
}\fi
233 \global\advance\myprevgraf by
1
234 % this will be the cost in the next page break finding:
235 \setshowprevgraf{400000}
237 % and re-inject the whole page with the original penalty
238 \unvbox255 \advance\outputpenalty by
400000 \penalty\outputpenalty
240 %%%%%%%%%% some stuff unknown to us %%%%%%%%%%
241 \immediate\write16{******** VEEEEEEERY negative value of outputpenalty: ERROR? ********
}%
243 \tempcnt=
\deadcycles\advance\tempcnt by
1 \deadcycles=
\tempcnt
247 % We have to reset certain things at the beginning of {{{
248 % every paragraph: Hook into it with \everypar
249 \newtoks\saveeverypar
250 \saveeverypar=
\expandafter{\the\everypar}
252 \global\advance\parno by
1
254 \global\showprevgraf=
0
255 % \global\leastcost=10000000
256 % check if the following paragraph will need a \parshape
257 % if yes, say the first token of \parshapes
258 % if no, restore the parno number into \parnos.
259 % This has to come in \everypar to avoid content after the last \par
260 \tempcnt=
\numcdr\parnos
261 \ifnum\tempcnt=
\parno \cdr\parshapes
262 \else \numconcat\tempcnt\parnos
268 % \par calls the pagebuilder and \output {{{
269 % We wrap the \par primitive
270 % - set \interlinepenalty first and reset it afterwards
271 % - call \output another time for the last line of the paragraph
274 \ifvmode\savepar\else\ifinner\savepar\else
275 % \global\leastcost=10000000
276 \advance\interlinepenalty by -
100000
277 \vadjust{\penalty-
400000}%
279 \advance\interlinepenalty by
100000
283 % $$ also calls the pagebuilder and \output {{{
284 % We wrap these characters with newly defined commands
285 % \display and \enddisplay
286 % XXX Can $ be redefined to achieve the same result?
287 % - $$ (begin) calls the pagebuilder for the previous text
288 % we have to do similar things as in \par
289 % - $$ (end) calls the pagebuilder for the display math
290 % we have to adjust \predisplaypenalty and \postdisplaypenalty
291 % XXX Has \interdisplaylinepenalty any effect on \prevgraf ?
293 % \global\leastcost=10000000
294 \global\advance\interlinepenalty by -
100000
296 \global\advance\interlinepenalty by
100000\relax}
298 % \global\leastcost=10000000
299 \global\advance\predisplaypenalty by -
200000
300 \global\advance\postdisplaypenalty by -
300000
302 \global\advance\predisplaypenalty by
200000
303 \global\advance\postdisplaypenalty by
300000\relax}