6

I know I can set \clubpenalty and \widowpenalty to 10 000 to make them “really bad”, but then TeX sees it equally bad to cut the page short when there is no vertical stretch (i.e. \parskip=0pt), and so I’m left with underfull pages often.

The question is: Would it somehow be possible in those cases to instruct TeX to re-do the whole page, for example, trying to get it one line shorter or longer? (Not the page as in \vsize, but the typeset texts space requirements)

Maybe this could be possible with LuaTeX? Or some clever output routine?

Update

OK so now, as per comments, I've played with the eTeX \club-/\widowpenalties. But either I don't understand how they work, or they do not help with the problem:

\font\bodyfont=cmr10 at 11bp \bodyfont

\frenchspacing
\parskip=0pt
\baselineskip=15bp
\topskip=15bp
\parindent=1em
\hsize=27pc
\vsize=525bp % 525 / 15 = 35, the number of lines

\clubpenalties=2 10000 0
\widowpenalties=2 10000 0
\looseness=1

\input a_novel
\bye

The pages are cut short when there would be a widow/orphan.

References

Jonathan Fines “Line breaking and page breaking” hints at a possible global optimisation via multiple passes.

David Salomon writes in his book “The Advanced TeXbook” about “A global page-break algorithm”, but I cannot find the reference (Ref. 37).

morbusg
  • 25,490
  • 4
  • 81
  • 162
  • Please be a bit more specific about the goal(s) you're looking to achieve. I'm a bit confused by your write-up because (i) you seem to be weary of having under-full pages -- possibly because of some setting of the \widowpenalty and \clubpenalty parameters -- and yet (ii) seem to be willing to shorten (or lengthen...) a given page's text height to avoid widows and orphans. – Mico Apr 22 '13 at 18:14
  • 2
    @Mico: "Is it possible in those cases (cases where trying to avoid a widow/orphan, a page is cut short), to get it shorter/longer" (it == the contents of the page, as in loosing/tightening up the paragraphs contained therein), that is, not to actually adjust \vsize, but to make that text more sparse/tight so that the required space for it would be longer/shorter so that the pagebreak wouldn't occur at a place where it would create a widow/orphan and thereby not needing to cut the page short in trying to compensate that. – morbusg Apr 22 '13 at 18:39
  • Thanks for this clarification. AFAICT, the fundamental text object whose appearance TeX takes great care to optimize is the paragraph. Once a paragraph "box" has been optimized and placed on the current page's vertical list, it will not be re-opened. (That's one reason why it's usually a good idea to allow for some stretch or "glue" between paragraphs...) Short of completely re-writing the entire page typesetting algorithm -- something which may be possible in LuaTeX, though I don't know of any current implementations -- I believe the answer to your question is therefore NO. – Mico Apr 22 '13 at 18:53
  • Did you try \usepackage[all]{nowidow} and looseness=1? Surely a LuaTeX solution would be possible, but perhaps the current eTeX solutions are good enough? – topskip Apr 22 '13 at 20:10
  • @Mico: But I wonder that isn't the information that the \vbox of \pagebody is underfull already available at that point? Or is it only when it gets \unvboxed and \output? If so, couldn't that box just be dumped into another box with different, say, inter-word spacing settings and then \unvboxed? – morbusg Apr 22 '13 at 20:10
  • @topskip: I glanced over the package source, and I suppose you mean the \clubpenalties/\widowpenalties (plural, eTeX)? I need to play around with those, thanks! – morbusg Apr 22 '13 at 20:32
  • @morbusg exactly. But don't forget the \loosenes parameter. – topskip Apr 22 '13 at 20:34
  • I don't understand what you expect TeX do to in that case? Did you try to set \looseness on a per paragraph basis? It's not a global variable. – topskip Apr 23 '13 at 08:50
  • @topskip: To, for example, discard the page and re-do it with different inter-word glues. – morbusg Apr 23 '13 at 09:24

2 Answers2

4

It is surely impossible to have all of the following conditions:

  1. No clubs/widows
  2. TeX must not change the paragraph
  3. Number of lines must be fixed

Since TeX breaks paragraphs before looking at pages, it has no chance to redo 2). With LuaTeX you could probably cook your own automatic solution, but this is pretty much the opposite of 'trivial'.

In PDFTeX you have to manually tell TeX to re-arrange the paragraphs. The \looseness parameter tells TeX to make the paragraph larger or smaller, but only if it can do so (\tolerance and such).

The following code is a sample document which has no widows/clubs, but the paragraphs are not pretty anymore:

\font\bodyfont=cmr10 at 11bp \bodyfont

\frenchspacing
\parskip=0pt
\baselineskip=15bp
\topskip=15bp
\parindent=1em
\hsize=27pc
\vsize=525bp % 525 / 15 = 35, the number of lines

\clubpenalties=2 10000 0
\widowpenalties=2 10000 0

\def\a{A wonderful serenity has taken possession of my entire soul, like these sweet
mornings of spring which I enjoy with my whole heart. I am alone, and feel the
charm of existence in this spot, which was created for the bliss of souls like
mine. I am so happy, my dear friend, so absorbed in the exquisite sense of
mere tranquil existence, that I neglect my talents. I should be incapable of
drawing a single stroke at the present moment; and yet I feel that I never was
a greater artist than now. When, while the lovely valley teems with vapour
around me, and the meridian sun strikes the upper surface of the impenetrable
foliage of my trees, and but a few stray gleams steal into the inner
sanctuary, I throw myself down among the tall grass by the trickling stream;
and, as I lie close to the earth, a thousand unknown plants are noticed by me:
when I hear the buzz of the little world among the stalks, and grow familiar
with the countless indescribable forms of the insects and flies, then I feel
the presence of the Almighty, who formed us in his own image, and the breath
of that universal love which bears and sustains us, as it floats around us in
an \par}
\a
\looseness=-1\a
\tolerance300\looseness=2\a
\looseness=2\a

\bye
topskip
  • 37,020
  • Putting manually different looseness/tolerances on a page-by-page basis is an exercise in masochism, especially when testing different page/typeblock layouts. There has to be a way. Paragraph builder implemented in TeX's mouth? Anyone? No? – morbusg Apr 23 '13 at 09:30
  • 2
    Using TeX is an exercise in masochism, adding the few bits of ´\looseness` in the document doesn't make this much worse. – topskip Apr 23 '13 at 09:32
  • 1
    @morbusg It is not possible to implement the paragraph builder in TeX' mouth, as there is AFAIK no way to access the sizes of each characters (etc.) expandably. Perhaps keep track in the aux file of which paragraphs fall on which page and must be stretched compressed. Counting pars: \newcount\parcnt \everypar\expandafter{\the\everypar\advance\parcnt1}, use \marks to find the first/last par in the page. Put max \clubpenalty and \widowpenalty. Patch the output routine to detect underfull pages, and store the first/last par number in the aux. – Bruno Le Floch Jun 14 '13 at 07:07
3

I was struggling with the same after switching to lualatex. Apparently the \club-/\widowpenalties works better in pdflatex than in lualatex. However, adding this to the preface solved all of my problems:

\usepackage[defaultlines=4,all]{nowidow}

See the nowidow package manual for more options: http://mirrors.ctan.org/macros/latex/contrib/nowidow/nowidow.pdf