From c5315f6df87ff9a1c94bf58efe7029078ceb9b08 Mon Sep 17 00:00:00 2001 From: Jeremias Maerki Date: Fri, 4 Aug 2006 15:13:53 +0000 Subject: [PATCH] Bugzilla #39840: Changed the way overflowing pages are handled. The overflow property on region-body is now used to define the behaviour. It removes the "Some content could not fit..." exception that bugged so many. However, the change does not yet change any keep behaviour. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@428750 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/fop/layoutmgr/AbstractBreaker.java | 11 ++- .../BalancingColumnBreakingAlgorithm.java | 5 +- .../fop/layoutmgr/BreakingAlgorithm.java | 36 ++++++-- .../fop/layoutmgr/PageBreakingAlgorithm.java | 31 +++++-- .../layoutmgr/PageSequenceLayoutManager.java | 36 +++++++- status.xml | 4 + .../block_keep-together_overflow_1.xml | 85 +++++++++++++++++++ 7 files changed, 189 insertions(+), 19 deletions(-) create mode 100644 test/layoutengine/standard-testcases/block_keep-together_overflow_1.xml diff --git a/src/java/org/apache/fop/layoutmgr/AbstractBreaker.java b/src/java/org/apache/fop/layoutmgr/AbstractBreaker.java index c549be3ee..24ee2e4da 100644 --- a/src/java/org/apache/fop/layoutmgr/AbstractBreaker.java +++ b/src/java/org/apache/fop/layoutmgr/AbstractBreaker.java @@ -196,6 +196,15 @@ public abstract class AbstractBreaker { return null; } + /** + * Returns a PageBreakingLayoutListener for the PageBreakingAlgorithm to notify about layout + * problems. + * @return the listener instance or null if no notifications are needed + */ + protected PageBreakingAlgorithm.PageBreakingLayoutListener getLayoutListener() { + return null; + } + /* * This method is to contain the logic to determine the LM's * getNextKnuthElements() implementation(s) that are to be called. @@ -310,7 +319,7 @@ public abstract class AbstractBreaker { log.debug("PLM> start of algorithm (" + this.getClass().getName() + "), flow BPD =" + flowBPD); PageBreakingAlgorithm alg = new PageBreakingAlgorithm(getTopLevelLM(), - getPageProvider(), + getPageProvider(), getLayoutListener(), alignment, alignmentLast, footnoteSeparatorLength, isPartOverflowRecoveryActivated(), autoHeight, isSinglePartFavored()); int iOptPageCount; diff --git a/src/java/org/apache/fop/layoutmgr/BalancingColumnBreakingAlgorithm.java b/src/java/org/apache/fop/layoutmgr/BalancingColumnBreakingAlgorithm.java index c91722360..57e42aaf6 100644 --- a/src/java/org/apache/fop/layoutmgr/BalancingColumnBreakingAlgorithm.java +++ b/src/java/org/apache/fop/layoutmgr/BalancingColumnBreakingAlgorithm.java @@ -21,6 +21,7 @@ package org.apache.fop.layoutmgr; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.apache.fop.layoutmgr.PageBreakingAlgorithm.PageBreakingLayoutListener; import org.apache.fop.traits.MinOptMax; /** @@ -37,11 +38,13 @@ public class BalancingColumnBreakingAlgorithm extends PageBreakingAlgorithm { public BalancingColumnBreakingAlgorithm(LayoutManager topLevelLM, PageSequenceLayoutManager.PageProvider pageProvider, + PageBreakingLayoutListener layoutListener, int alignment, int alignmentLast, MinOptMax footnoteSeparatorLength, boolean partOverflowRecovery, int columnCount) { - super(topLevelLM, pageProvider, alignment, alignmentLast, + super(topLevelLM, pageProvider, layoutListener, + alignment, alignmentLast, footnoteSeparatorLength, partOverflowRecovery, false, false); this.columnCount = columnCount; this.considerTooShort = true; //This is important! diff --git a/src/java/org/apache/fop/layoutmgr/BreakingAlgorithm.java b/src/java/org/apache/fop/layoutmgr/BreakingAlgorithm.java index 33f5f96ad..5720e3095 100644 --- a/src/java/org/apache/fop/layoutmgr/BreakingAlgorithm.java +++ b/src/java/org/apache/fop/layoutmgr/BreakingAlgorithm.java @@ -50,7 +50,7 @@ public abstract class BreakingAlgorithm { /** Maximum adjustment ration */ protected static final int INFINITE_RATIO = 1000; - private static final int MAX_RECOVERY_ATTEMPTS = 50; + private static final int MAX_RECOVERY_ATTEMPTS = 5; // constants identifying a subset of the feasible breaks /** All feasible breaks are ok. */ @@ -156,6 +156,7 @@ public abstract class BreakingAlgorithm { /** @see #isPartOverflowRecoveryActivated() */ private boolean partOverflowRecoveryActivated = true; + private KnuthNode lastRecovered; /** * Create a new instance. @@ -495,6 +496,12 @@ public abstract class BreakingAlgorithm { } if (lastTooShort == null || lastForced.position == lastTooShort.position) { if (isPartOverflowRecoveryActivated()) { + if (this.lastRecovered == null) { + this.lastRecovered = lastTooLong; + if (log.isDebugEnabled()) { + log.debug("Recovery point: " + lastRecovered); + } + } // content would overflow, insert empty line/page and try again KnuthNode node = createNode( lastTooLong.previous.position, lastTooLong.previous.line + 1, 1, @@ -503,23 +510,34 @@ public abstract class BreakingAlgorithm { 0, 0, lastTooLong.previous); lastForced = node; node.fitRecoveryCounter = lastTooLong.previous.fitRecoveryCounter + 1; - log.debug("first part doesn't fit into line, recovering: " - + node.fitRecoveryCounter); + if (log.isDebugEnabled()) { + log.debug("first part doesn't fit into line, recovering: " + + node.fitRecoveryCounter); + } if (node.fitRecoveryCounter > getMaxRecoveryAttempts()) { - FONode contextFO = findContextFO(par, node.position + 1); - throw new RuntimeException(FONode.decorateWithContextInfo( - "Some content could not fit " - + "into a line/page after " + getMaxRecoveryAttempts() - + " attempts. Giving up to avoid an endless loop.", contextFO)); + while (lastForced.fitRecoveryCounter > 0) { + lastForced = lastForced.previous; + lastDeactivated = lastForced.previous; + startLine--; + endLine--; + } + lastForced = this.lastRecovered; + this.lastRecovered = null; + startLine = lastForced.line; + endLine = lastForced.line; + log.debug("rolled back..."); } } else { lastForced = lastTooLong; } } else { lastForced = lastTooShort; + this.lastRecovered = null; } - log.debug("Restarting at node " + lastForced); + if (log.isDebugEnabled()) { + log.debug("Restarting at node " + lastForced); + } i = restartFrom(lastForced, i); } } diff --git a/src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java b/src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java index 3910fa023..cb28223d0 100644 --- a/src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java +++ b/src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java @@ -39,6 +39,7 @@ class PageBreakingAlgorithm extends BreakingAlgorithm { private LayoutManager topLevelLM; private PageSequenceLayoutManager.PageProvider pageProvider; + private PageBreakingLayoutListener layoutListener; /** List of PageBreakPosition elements. */ private LinkedList pageBreaks = null; @@ -94,6 +95,7 @@ class PageBreakingAlgorithm extends BreakingAlgorithm { public PageBreakingAlgorithm(LayoutManager topLevelLM, PageSequenceLayoutManager.PageProvider pageProvider, + PageBreakingLayoutListener layoutListener, int alignment, int alignmentLast, MinOptMax footnoteSeparatorLength, boolean partOverflowRecovery, boolean autoHeight, @@ -102,6 +104,7 @@ class PageBreakingAlgorithm extends BreakingAlgorithm { this.log = classLog; this.topLevelLM = topLevelLM; this.pageProvider = pageProvider; + this.layoutListener = layoutListener; best = new BestPageRecords(); this.footnoteSeparatorLength = (MinOptMax) footnoteSeparatorLength.clone(); // add some stretch, to avoid a restart for every page containing footnotes @@ -746,11 +749,15 @@ class PageBreakingAlgorithm extends BreakingAlgorithm { // ? bestActiveNode.difference : bestActiveNode.difference + fillerMinWidth; int difference = bestActiveNode.difference; if (difference + bestActiveNode.availableShrink < 0) { - if (!autoHeight && log.isWarnEnabled()) { - log.warn(FONode.decorateWithContextInfo( - "Part/page " + (getPartCount() + 1) - + " overflows the available area in block-progression dimension.", - getFObj())); + if (!autoHeight) { + if (layoutListener != null) { + layoutListener.notifyOverflow(bestActiveNode.line - 1, getFObj()); + } else if (log.isWarnEnabled()) { + log.warn(FONode.decorateWithContextInfo( + "Part/page " + (bestActiveNode.line - 1) + + " overflows the available area in block-progression dimension.", + getFObj())); + } } } boolean isNonLastPage = (bestActiveNode.line < total); @@ -852,4 +859,18 @@ class PageBreakingAlgorithm extends BreakingAlgorithm { return bpd; } + /** + * Interface to notify about layout events during page breaking. + */ + public interface PageBreakingLayoutListener { + + /** + * Issued when an overflow is detected + * @param part the number of the part (page) this happens on + * @param obj the root FO object where this happens + */ + void notifyOverflow(int part, FObj obj); + + } + } diff --git a/src/java/org/apache/fop/layoutmgr/PageSequenceLayoutManager.java b/src/java/org/apache/fop/layoutmgr/PageSequenceLayoutManager.java index 9a06896f3..4496d11da 100644 --- a/src/java/org/apache/fop/layoutmgr/PageSequenceLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/PageSequenceLayoutManager.java @@ -33,6 +33,8 @@ import org.apache.fop.area.LineArea; import org.apache.fop.area.Resolvable; import org.apache.fop.fo.Constants; +import org.apache.fop.fo.FONode; +import org.apache.fop.fo.FObj; import org.apache.fop.fo.flow.Marker; import org.apache.fop.fo.flow.RetrieveMarker; @@ -43,6 +45,7 @@ import org.apache.fop.fo.pagination.RegionBody; import org.apache.fop.fo.pagination.SideRegion; import org.apache.fop.fo.pagination.SimplePageMaster; import org.apache.fop.fo.pagination.StaticContent; +import org.apache.fop.layoutmgr.PageBreakingAlgorithm.PageBreakingLayoutListener; import org.apache.fop.layoutmgr.inline.ContentLayoutManager; import org.apache.fop.traits.MinOptMax; @@ -192,8 +195,9 @@ public class PageSequenceLayoutManager extends AbstractLayoutManager { context.setRefIPD(flowIPD); } + /** @see org.apache.fop.layoutmgr.AbstractBreaker#getTopLevelLM() */ protected LayoutManager getTopLevelLM() { - return null; // unneeded for PSLM + return pslm; } /** @see org.apache.fop.layoutmgr.AbstractBreaker#getPageProvider() */ @@ -201,6 +205,32 @@ public class PageSequenceLayoutManager extends AbstractLayoutManager { return pageProvider; } + /** + * @see org.apache.fop.layoutmgr.AbstractBreaker#getLayoutListener() + */ + protected PageBreakingLayoutListener getLayoutListener() { + return new PageBreakingLayoutListener() { + + public void notifyOverflow(int part, FObj obj) { + Page p = pageProvider.getPage( + false, part, PageProvider.RELTO_CURRENT_ELEMENT_LIST); + RegionBody body = (RegionBody)p.getSimplePageMaster().getRegion( + Region.FO_REGION_BODY); + String err = FONode.decorateWithContextInfo( + "Content of the region-body on page " + + p.getPageViewport().getPageNumberString() + + " overflows the available area in block-progression dimension.", + obj); + if (body.getOverflow() == Constants.EN_ERROR_IF_OVERFLOW) { + throw new RuntimeException(err); + } else { + PageSequenceLayoutManager.log.warn(err); + } + } + + }; + } + /** @see org.apache.fop.layoutmgr.AbstractBreaker */ protected int handleSpanChange(LayoutContext childLC, int nextSequenceStartsOn) { needColumnBalancing = false; @@ -373,7 +403,7 @@ public class PageSequenceLayoutManager extends AbstractLayoutManager { //Restart last page PageBreakingAlgorithm algRestart = new PageBreakingAlgorithm( getTopLevelLM(), - getPageProvider(), + getPageProvider(), getLayoutListener(), alg.getAlignment(), alg.getAlignmentLast(), footnoteSeparatorLength, isPartOverflowRecoveryActivated(), false, false); @@ -433,7 +463,7 @@ public class PageSequenceLayoutManager extends AbstractLayoutManager { //Restart last page PageBreakingAlgorithm algRestart = new BalancingColumnBreakingAlgorithm( getTopLevelLM(), - getPageProvider(), + getPageProvider(), getLayoutListener(), alignment, Constants.EN_START, footnoteSeparatorLength, isPartOverflowRecoveryActivated(), getCurrentPV().getBodyRegion().getColumnCount()); diff --git a/status.xml b/status.xml index 408dba617..b71af09d4 100644 --- a/status.xml +++ b/status.xml @@ -28,6 +28,10 @@ + + Changed the way overflowing pages are handled. The overflow property on region-body + is now used to define the behaviour. + Fixed a memory-leak: The FO tree part of a page-sequence was not released when a page-sequence was finished. diff --git a/test/layoutengine/standard-testcases/block_keep-together_overflow_1.xml b/test/layoutengine/standard-testcases/block_keep-together_overflow_1.xml new file mode 100644 index 000000000..a4a2de62c --- /dev/null +++ b/test/layoutengine/standard-testcases/block_keep-together_overflow_1.xml @@ -0,0 +1,85 @@ + + + + + +

+ This test checks keep-together with overflow conditions. +

+

+ Widows and Orphans are disabled in this test to avoid side-effects. +

+
+ + + + + + + + + + + + + + + + + + block1 + block2 + + block3 + block4 + block5 + block6 + block7 + + block8 + block9 + + block10 + block11 + block12 + block13 + block14 + + block15 + + + + + + + + + + + + + + + + + + + + + +
-- 2.39.5