diff options
-rw-r--r-- | src/java/org/apache/fop/layoutmgr/PageBreaker.java | 266 |
1 files changed, 134 insertions, 132 deletions
diff --git a/src/java/org/apache/fop/layoutmgr/PageBreaker.java b/src/java/org/apache/fop/layoutmgr/PageBreaker.java index 1137065ab..20fd89cd9 100644 --- a/src/java/org/apache/fop/layoutmgr/PageBreaker.java +++ b/src/java/org/apache/fop/layoutmgr/PageBreaker.java @@ -28,7 +28,6 @@ import org.apache.fop.area.Footnote; import org.apache.fop.area.PageViewport; import org.apache.fop.fo.Constants; import org.apache.fop.fo.FObj; -import org.apache.fop.fo.pagination.PageSequence; import org.apache.fop.fo.pagination.Region; import org.apache.fop.fo.pagination.RegionBody; import org.apache.fop.fo.pagination.StaticContent; @@ -136,16 +135,9 @@ public class PageBreaker extends AbstractBreaker { return super.getNextBlockList(childLC, nextSequenceStartsOn); } - /** {@inheritDoc} */ - protected List getNextKnuthElements(LayoutContext context, int alignment) { - List contentList = null; - - while (!childFLM.isFinished() && contentList == null) { - contentList = childFLM.getNextKnuthElements(context, alignment); - } + private boolean containsFootnotes(List contentList, LayoutContext context) { - // scan contentList, searching for footnotes - boolean bFootnotesPresent = false; + boolean containsFootnotes = false; if (contentList != null) { ListIterator contentListIterator = contentList.listIterator(); while (contentListIterator.hasNext()) { @@ -153,7 +145,7 @@ public class PageBreaker extends AbstractBreaker { if (element instanceof KnuthBlockBox && ((KnuthBlockBox) element).hasAnchors()) { // element represents a line with footnote citations - bFootnotesPresent = true; + containsFootnotes = true; LayoutContext footnoteContext = new LayoutContext(context); footnoteContext.setStackLimitBP(context.getStackLimitBP()); footnoteContext.setRefIPD(pslm.getCurrentPV() @@ -173,31 +165,46 @@ public class PageBreaker extends AbstractBreaker { } } } + return containsFootnotes; + } - if (bFootnotesPresent) { - // handle the footnote separator - StaticContent footnoteSeparator; - footnoteSeparator = pslm.getPageSequence().getStaticContent("xsl-footnote-separator"); - if (footnoteSeparator != null) { - // the footnote separator can contain page-dependent content such as - // page numbers or retrieve markers, so its areas cannot simply be - // obtained now and repeated in each page; - // we need to know in advance the separator bpd: the actual separator - // could be different from page to page, but its bpd would likely be - // always the same - - // create a Block area that will contain the separator areas - separatorArea = new Block(); - separatorArea.setIPD(pslm.getCurrentPV() - .getRegionReference(Constants.FO_REGION_BODY).getIPD()); - // create a StaticContentLM for the footnote separator - footnoteSeparatorLM = (StaticContentLayoutManager) - pslm.getLayoutManagerMaker().makeStaticContentLayoutManager( - pslm, footnoteSeparator, separatorArea); - footnoteSeparatorLM.doLayout(); + private void handleFootnoteSeparator() { + StaticContent footnoteSeparator; + footnoteSeparator = pslm.getPageSequence().getStaticContent("xsl-footnote-separator"); + if (footnoteSeparator != null) { + // the footnote separator can contain page-dependent content such as + // page numbers or retrieve markers, so its areas cannot simply be + // obtained now and repeated in each page; + // we need to know in advance the separator bpd: the actual separator + // could be different from page to page, but its bpd would likely be + // always the same - footnoteSeparatorLength = new MinOptMax(separatorArea.getBPD()); - } + // create a Block area that will contain the separator areas + separatorArea = new Block(); + separatorArea.setIPD(pslm.getCurrentPV() + .getRegionReference(Constants.FO_REGION_BODY).getIPD()); + // create a StaticContentLM for the footnote separator + footnoteSeparatorLM + = pslm.getLayoutManagerMaker().makeStaticContentLayoutManager( + pslm, footnoteSeparator, separatorArea); + footnoteSeparatorLM.doLayout(); + + footnoteSeparatorLength = new MinOptMax(separatorArea.getBPD()); + } + } + + /** {@inheritDoc} */ + protected List getNextKnuthElements(LayoutContext context, int alignment) { + List contentList = null; + + while (!childFLM.isFinished() && contentList == null) { + contentList = childFLM.getNextKnuthElements(context, alignment); + } + + // scan contentList, searching for footnotes + if (containsFootnotes(contentList, context)) { + // handle the footnote separator + handleFootnoteSeparator(); } return contentList; } @@ -241,49 +248,61 @@ public class PageBreaker extends AbstractBreaker { } /** - * Performs phase 3 operation - * - * @param alg page breaking algorithm - * @param partCount part count - * @param originalList the block sequence original list - * @param effectiveList the block sequence effective list + * {@inheritDoc} + * This implementation checks whether to trigger column-balancing, + * or whether to take into account a 'last-page' condition. */ protected void doPhase3(PageBreakingAlgorithm alg, int partCount, BlockSequence originalList, BlockSequence effectiveList) { + if (needColumnBalancing) { - doPhase3WithColumnBalancing(alg, partCount, originalList, effectiveList); - } else { - if (!hasMoreContent() && pslm.getPageSequence().hasPagePositionLast()) { - //last part is reached and we have a "last page" condition - doPhase3WithLastPage(alg, partCount, originalList, effectiveList); - } else { - //Directly add areas after finding the breaks - addAreas(alg, partCount, originalList, effectiveList); + //column balancing for the last part + doPhase3(alg, partCount, originalList, effectiveList, false); + return; + } + + boolean lastPageMasterDefined = pslm.getPageSequence().hasPagePositionLast(); + if (!hasMoreContent()) { + //last part is reached + if (lastPageMasterDefined) { + //last-page condition + doPhase3(alg, partCount, originalList, effectiveList, true); + return; } } + + //nothing special: just add the areas now + addAreas(alg, partCount, originalList, effectiveList); } - private void doPhase3WithLastPage(PageBreakingAlgorithm alg, int partCount, - BlockSequence originalList, BlockSequence effectiveList) { - int newStartPos; + /** + * Restart the algorithm at the break corresponding + * to the given partCount + * (currently only used to redo the part after the + * last break in case of column-balancing + * and/or a last page-master) + */ + private void doPhase3(PageBreakingAlgorithm alg, int partCount, + BlockSequence originalList, BlockSequence effectiveList, + boolean isLastPart) { + + + int newStartPos = 0; int restartPoint = pageProvider.getStartingPartIndexForLastPage(partCount); if (restartPoint > 0) { - //Add definitive areas before last page + //Add definitive areas for the parts before the + //restarting point addAreas(alg, restartPoint, originalList, effectiveList); //Get page break from which we restart PageBreakPosition pbp = (PageBreakPosition) alg.getPageBreaks().get(restartPoint - 1); - //Set starting position to the first element *after* the page-break newStartPos = pbp.getLeafPos() + 1; //Handle page break right here to avoid any side-effects if (newStartPos > 0) { handleBreakTrait(Constants.EN_PAGE); } - } else { - newStartPos = 0; } - AbstractBreaker.log.debug("Last page handling now!!!"); - AbstractBreaker.log.debug("==================================================="); + AbstractBreaker.log.debug("Restarting at " + restartPoint + ", new start position: " + newStartPos); @@ -292,91 +311,74 @@ public class PageBreaker extends AbstractBreaker { int currentPageNum = pslm.getCurrentPageNum(); pageProvider.setStartOfNextElementList(currentPageNum, pslm.getCurrentPV().getCurrentSpan().getCurrentFlowIndex()); - pageProvider.setLastPageIndex(currentPageNum); - - //Restart last page - PageBreakingAlgorithm algRestart = new PageBreakingAlgorithm( - getTopLevelLM(), - getPageProvider(), createLayoutListener(), - alg.getAlignment(), alg.getAlignmentLast(), - footnoteSeparatorLength, - isPartOverflowRecoveryActivated(), false, false); - //alg.setConstantLineWidth(flowBPD); - int iOptPageCount = algRestart.findBreakingPoints(effectiveList, - newStartPos, - 1, true, BreakingAlgorithm.ALL_BREAKS); - AbstractBreaker.log.debug("restart: iOptPageCount= " + iOptPageCount - + " pageBreaks.size()= " + algRestart.getPageBreaks().size()); + + PageBreakingAlgorithm algRestart = null; + int optimalPageCount; //Make sure we only add the areas we haven't added already effectiveList.ignoreAtStart = newStartPos; - boolean replaceLastPage - = iOptPageCount <= pslm.getCurrentPV().getBodyRegion().getColumnCount(); - if (replaceLastPage) { - //Replace last page - pslm.setCurrentPage(pageProvider.getPage(false, currentPageNum)); - addAreas(algRestart, iOptPageCount, originalList, effectiveList); - } else { - addAreas(alg, restartPoint, partCount - restartPoint, originalList, effectiveList); - //Add blank last page - pageProvider.setLastPageIndex(currentPageNum + 1); - pslm.setCurrentPage(pslm.makeNewPage(true, true)); - } - AbstractBreaker.log.debug("==================================================="); - } - private void doPhase3WithColumnBalancing(PageBreakingAlgorithm alg, int partCount, - BlockSequence originalList, BlockSequence effectiveList) { - AbstractBreaker.log.debug("Column balancing now!!!"); - AbstractBreaker.log.debug("==================================================="); - int newStartPos; - int restartPoint = pageProvider.getStartingPartIndexForLastPage(partCount); - if (restartPoint > 0) { - //Add definitive areas - addAreas(alg, restartPoint, originalList, effectiveList); - //Get page break from which we restart - PageBreakPosition pbp = (PageBreakPosition) - alg.getPageBreaks().get(restartPoint - 1); - newStartPos = pbp.getLeafPos(); - //Handle page break right here to avoid any side-effects - if (newStartPos > 0) { - handleBreakTrait(Constants.EN_PAGE); - } - } else { - newStartPos = 0; + if (isLastPart) { + pageProvider.setLastPageIndex(currentPageNum); } - AbstractBreaker.log.debug("Restarting at " + restartPoint - + ", new start position: " + newStartPos); - pageBreakHandled = true; - //Update so the available BPD is reported correctly - pageProvider.setStartOfNextElementList(pslm.getCurrentPageNum(), - pslm.getCurrentPV().getCurrentSpan().getCurrentFlowIndex()); + if (needColumnBalancing) { + AbstractBreaker.log.debug("Column balancing now!!!"); + AbstractBreaker.log.debug("==================================================="); + + //Restart last page + algRestart = new BalancingColumnBreakingAlgorithm( + getTopLevelLM(), getPageProvider(), createLayoutListener(), + alignment, Constants.EN_START, footnoteSeparatorLength, + isPartOverflowRecoveryActivated(), + pslm.getCurrentPV().getBodyRegion().getColumnCount()); + AbstractBreaker.log.debug("==================================================="); + } else { + //plain last page, no column balancing + AbstractBreaker.log.debug("Last page handling now!!!"); + AbstractBreaker.log.debug("==================================================="); + //Restart last page + algRestart = new PageBreakingAlgorithm( + getTopLevelLM(), getPageProvider(), createLayoutListener(), + alg.getAlignment(), alg.getAlignmentLast(), + footnoteSeparatorLength, + isPartOverflowRecoveryActivated(), false, false); + AbstractBreaker.log.debug("==================================================="); + } - //Restart last page - PageBreakingAlgorithm algRestart = new BalancingColumnBreakingAlgorithm( - getTopLevelLM(), - getPageProvider(), createLayoutListener(), - alignment, Constants.EN_START, footnoteSeparatorLength, - isPartOverflowRecoveryActivated(), - pslm.getCurrentPV().getBodyRegion().getColumnCount()); - //alg.setConstantLineWidth(flowBPD); - int iOptPageCount = algRestart.findBreakingPoints(effectiveList, + optimalPageCount = algRestart.findBreakingPoints(effectiveList, newStartPos, 1, true, BreakingAlgorithm.ALL_BREAKS); - AbstractBreaker.log.debug("restart: iOptPageCount= " + iOptPageCount + AbstractBreaker.log.debug("restart: optimalPageCount= " + optimalPageCount + " pageBreaks.size()= " + algRestart.getPageBreaks().size()); - if (iOptPageCount > pslm.getCurrentPV().getBodyRegion().getColumnCount()) { - AbstractBreaker.log.warn( - "Breaking algorithm produced more columns than are available."); - /* reenable when everything works - throw new IllegalStateException( - "Breaking algorithm must not produce more columns than available."); - */ + + boolean fitsOnePage + = optimalPageCount <= pslm.getCurrentPV().getBodyRegion().getColumnCount(); + + if (isLastPart) { + if (fitsOnePage) { + //Replace last page + pslm.setCurrentPage(pageProvider.getPage(false, currentPageNum)); + } else { + //Last page-master cannot hold the content. + //Add areas now... + addAreas(alg, restartPoint, partCount - restartPoint, originalList, effectiveList); + //...and add a blank last page + pageProvider.setLastPageIndex(currentPageNum + 1); + pslm.setCurrentPage(pslm.makeNewPage(true, true)); + return; + } + } else { + if (!fitsOnePage) { + AbstractBreaker.log.warn( + "Breaking algorithm produced more columns than are available."); + /* reenable when everything works + throw new IllegalStateException( + "Breaking algorithm must not produce more columns than available."); + */ + } } - //Make sure we only add the areas we haven't added already - effectiveList.ignoreAtStart = newStartPos; - addAreas(algRestart, iOptPageCount, originalList, effectiveList); - AbstractBreaker.log.debug("==================================================="); + + addAreas(algRestart, optimalPageCount, originalList, effectiveList); } protected void startPart(BlockSequence list, int breakClass) { |