[Date Prev] | [Thread Prev] | [Thread Next] | [Date Next] -- [Date Index] | [Thread Index] | [List Home]
Subject: soft page break
[FOP users can skip this message since this doesn't work in FOP] I've been experimenting with a soft page break feature for DocBook FO output. Anyone who has implemented hard page breaks (usually with processing instructions) knows that they can be an immediate fix, but they can also create maintenance headaches when you edit the document and change the pagination. Then you end up with page breaks where they are not needed. I borrowed the idea of a soft page break from the troff typesetting system, which uses the term "need". You put in a processing instruction in your document that effectively says "I need at least 2 inches left on the current page to fit the following material. If that much space is not available on the page, then break to the next page at this point. If there is enough space, don't break." This kind of conditional page break is handy when the normal "keeps" used in the stylesheet are not sufficient, either for technical reasons or for aesthetic reasons. For example, you may want to make sure a short introductory paragraph that precedes a code listing has at least a few lines of code with it on the page. The para and the programlisting are separate elements that normally would not have a "keep". This kind of page breaking is not perfect, because you need to estimate how much physical space is needed for the content you want to keep together. I typically use it after the first printout so I can take a ruler to it. But since it isn't wrapping elements, it can create keeps of arbitrary size. I've implemented this feature using a block-container of the desired height, followed by an empty block with a negative space-before property that brings it back to the top of the block-container. If the block-container doesn't fit on the page, it is forced to the next page, and the empty block and the text that follows appear on the next page. If the block-container fits, then the block-container is simply overwritten by the text that follows the empty block, starting at the top of the block-container. If done correctly, a block-container that fits should have no net effect, but a block-container that doesn't fit should force the page break. In a text picture, it looks like this (this won't look right if viewed with a proportional font): +===================================+ <-- top of container |First line of text after the need | and empty block |and some more text after the need | +-----------------------------------+ and even more text after the need that does not fit in the container. It sounds easy, but there are several issues with how the space-before and space-after properties combine in adjacent blocks. Getting the "need" to not add or reduce spacing between the visible blocks makes it more complicated. I'd like to let people try this out before I commit to the stylesheet. Unfortunately, it does not work with the current FOP processor, because FOP does not fully implement block-container. I tried using an fo:table with a specified row height, but FOP doesn't seem to break the page properly for an empty row container. But anyone using XEP or Antenna House is welcome to try this out. I've included a customization below that you can xsl:include in your customization layer. Then you should be able to add something like this to your document: <?dbfo-need height="2in"?> You can't put the processing instruction inline. It must be between elements that generate blocks of text, otherwise you may get invalid XSL-FO. Here is an example of how to use it: <para>blah blah</para> <?dbfo-need height="0.5in" ?> <para>The following code snippet illustrates the technique:</para> <programlisting>blah blah more and more etc. Note that the processing instruction name is "dbfo-need", not "dbfo". The default template for dbfo PIs is a no-op. The processing of all dbfo PIs is triggered by the template handling the PI's container element. This PI must be processed on its own, so it has a different name. The dbfo-need PI also accepts a second optional pseudo attribute named 'space-before'. This is useful to manually adjust the spacing when the stylesheet can't quite resolve the spacing the way it was without the PI. For example: <?dbfo-need height="0.5in" space-before="3em" ?> It also could be used to add extra vertical space wherever you need it. If you leave out the height pseudo attribute, then you will just get the extra spacing. Here is the code: --------------------------- snip --------------------------------- <?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" version='1.0'> <!-- need PI --> <xsl:template match="processing-instruction('dbfo-need')"> <xsl:variable name="pi-height"> <xsl:call-template name="dbfo-attribute"> <xsl:with-param name="pis" select="."/> <xsl:with-param name="attribute" select="'height'"/> </xsl:call-template> </xsl:variable> <xsl:variable name="height"> <xsl:choose> <xsl:when test="$pi-height != ''"> <xsl:value-of select="$pi-height"/> </xsl:when> <xsl:otherwise>0pt</xsl:otherwise> </xsl:choose> </xsl:variable> <xsl:variable name="pi-before"> <xsl:call-template name="dbfo-attribute"> <xsl:with-param name="pis" select="."/> <xsl:with-param name="attribute" select="'space-before'"/> </xsl:call-template> </xsl:variable> <xsl:variable name="spacer"> <fo:block-container width="100%" height="{$height}"> <fo:block/> </fo:block-container> </xsl:variable> <xsl:choose> <xsl:when test="$pi-before != ''"> <fo:block space-after="0pt" space-before="{$pi-before}"> <xsl:copy-of select="$spacer"/> </fo:block> </xsl:when> <xsl:when test="following-sibling::para"> <fo:block space-after="0pt" xsl:use-attribute-sets="normal.para.spacing"> <xsl:copy-of select="$spacer"/> </fo:block> </xsl:when> <xsl:when test="following-sibling::table or following-sibling::figure or following-sibling::example or following-sibling::equation"> <fo:block space-after="0pt" xsl:use-attribute-sets="formal.object.properties"> <xsl:copy-of select="$spacer"/> </fo:block> </xsl:when> <xsl:when test="following-sibling::informaltable or following-sibling::informalfigure or following-sibling::informalexample or following-sibling::informalequation"> <fo:block space-after="0pt" xsl:use-attribute-sets="informal.object.properties"> <xsl:copy-of select="$spacer"/> </fo:block> </xsl:when> <xsl:when test="following-sibling::itemizedlist or following-sibling::orderedlist or following-sibling::variablelist or following-sibling::simplelist"> <fo:block space-after="0pt" xsl:use-attribute-sets="informal.object.properties"> <xsl:copy-of select="$spacer"/> </fo:block> </xsl:when> <xsl:when test="following-sibling::listitem or following-sibling::step"> <fo:list-item space-after="0pt" xsl:use-attribute-sets="informal.object.properties"> <fo:list-item-label/> <fo:list-item-body start-indent="0pt" end-indent="0pt"> <xsl:copy-of select="$spacer"/> </fo:list-item-body> </fo:list-item> </xsl:when> <xsl:when test="following-sibling::sect1 or following-sibling::sect2 or following-sibling::sect3 or following-sibling::sect4 or following-sibling::sect5 or following-sibling::section"> <fo:block space-after="0pt" xsl:use-attribute-sets="section.title.properties"> <xsl:copy-of select="$spacer"/> </fo:block> </xsl:when> <xsl:otherwise> <fo:block space-after="0pt" space-before="0em"> <xsl:copy-of select="$spacer"/> </fo:block> </xsl:otherwise> </xsl:choose> <xsl:choose> <xsl:when test="following-sibling::listitem or following-sibling::step"> <fo:list-item space-before.precedence="force" space-before="-{$height}" space-after="0pt" space-after.precedence="force"> <fo:list-item-label/> <fo:list-item-body start-indent="0pt" end-indent="0pt"/> </fo:list-item> </xsl:when> <xsl:otherwise> <fo:block space-before.precedence="force" space-before="-{$height}" space-after="0pt" space-after.precedence="force"> </fo:block> </xsl:otherwise> </xsl:choose> </xsl:template> </xsl:stylesheet> --------------------------- snip --------------------------------- I'd be interested in getting feedback on situations where this doesn't work properly. Bob Stayton Sagehill Enterprises DocBook Consulting bobs@sagehill.net
[Date Prev] | [Thread Prev] | [Thread Next] | [Date Next] -- [Date Index] | [Thread Index] | [List Home]