aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeremias Maerki <jeremias@apache.org>2006-08-04 15:13:53 +0000
committerJeremias Maerki <jeremias@apache.org>2006-08-04 15:13:53 +0000
commitc5315f6df87ff9a1c94bf58efe7029078ceb9b08 (patch)
tree863bfc0091ca299ccf6dbf2f80b170c44c2f9a77
parentde718914ca7a6f6655d227f5ed55b3d32bb6026a (diff)
downloadxmlgraphics-fop-c5315f6df87ff9a1c94bf58efe7029078ceb9b08.tar.gz
xmlgraphics-fop-c5315f6df87ff9a1c94bf58efe7029078ceb9b08.zip
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
-rw-r--r--src/java/org/apache/fop/layoutmgr/AbstractBreaker.java11
-rw-r--r--src/java/org/apache/fop/layoutmgr/BalancingColumnBreakingAlgorithm.java5
-rw-r--r--src/java/org/apache/fop/layoutmgr/BreakingAlgorithm.java36
-rw-r--r--src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java31
-rw-r--r--src/java/org/apache/fop/layoutmgr/PageSequenceLayoutManager.java36
-rw-r--r--status.xml4
-rw-r--r--test/layoutengine/standard-testcases/block_keep-together_overflow_1.xml85
7 files changed, 189 insertions, 19 deletions
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 @@
<changes>
<release version="FOP Trunk">
+ <action context="Code" dev="JM" type="update">
+ Changed the way overflowing pages are handled. The overflow property on region-body
+ is now used to define the behaviour.
+ </action>
<action context="Code" dev="JM" type="fix">
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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<!-- $Id$ -->
+<testcase>
+ <info>
+ <p>
+ This test checks keep-together with overflow conditions.
+ </p>
+ <p>
+ Widows and Orphans are disabled in this test to avoid side-effects.
+ </p>
+ </info>
+ <fo>
+ <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" widows="0" orphans="0">
+ <fo:layout-master-set>
+ <fo:simple-page-master master-name="normal" page-width="5in" page-height="4.5 * 14.4pt">
+ <fo:region-body overflow="hidden"/>
+ </fo:simple-page-master>
+ <fo:simple-page-master master-name="longer" page-width="5in" page-height="5.5 * 14.4pt">
+ <fo:region-body overflow="hidden"/>
+ </fo:simple-page-master>
+ <fo:page-sequence-master master-name="mix">
+ <fo:repeatable-page-master-reference master-reference="normal" maximum-repeats="2"/>
+ <fo:repeatable-page-master-reference master-reference="longer" maximum-repeats="1"/>
+ <fo:repeatable-page-master-reference master-reference="normal"/>
+ </fo:page-sequence-master>
+ </fo:layout-master-set>
+ <fo:page-sequence master-reference="mix">
+ <fo:flow flow-name="xsl-region-body">
+ <fo:block>block1</fo:block>
+ <fo:block>block2</fo:block>
+ <fo:block keep-together.within-page="10" color="blue">
+ <fo:block>block3</fo:block>
+ <fo:block>block4</fo:block>
+ <fo:block>block5</fo:block>
+ <fo:block>block6</fo:block>
+ <fo:block>block7</fo:block>
+ </fo:block>
+ <fo:block>block8</fo:block>
+ <fo:block>block9</fo:block>
+ <fo:block keep-together.within-page="10" color="green">
+ <fo:block>block10</fo:block>
+ <fo:block>block11</fo:block>
+ <fo:block>block12</fo:block>
+ <fo:block>block13</fo:block>
+ <fo:block>block14</fo:block>
+ </fo:block>
+ <fo:block>block15</fo:block>
+ </fo:flow>
+ </fo:page-sequence>
+ </fo:root>
+ </fo>
+ <checks>
+ <eval expected="1" xpath="//lineArea[starts-with(., 'block1')]/ancestor::pageViewport/@nr"/>
+ <eval expected="1" xpath="//lineArea[starts-with(., 'block2')]/ancestor::pageViewport/@nr"/>
+ <eval expected="3" xpath="//lineArea[starts-with(., 'block3')]/ancestor::pageViewport/@nr"/>
+ <eval expected="3" xpath="//lineArea[starts-with(., 'block4')]/ancestor::pageViewport/@nr"/>
+ <eval expected="3" xpath="//lineArea[starts-with(., 'block5')]/ancestor::pageViewport/@nr"/>
+ <eval expected="3" xpath="//lineArea[starts-with(., 'block6')]/ancestor::pageViewport/@nr"/>
+ <eval expected="3" xpath="//lineArea[starts-with(., 'block7')]/ancestor::pageViewport/@nr"/>
+ <eval expected="4" xpath="//lineArea[starts-with(., 'block8')]/ancestor::pageViewport/@nr"/>
+ <eval expected="4" xpath="//lineArea[starts-with(., 'block9')]/ancestor::pageViewport/@nr"/>
+ <eval expected="5" xpath="//lineArea[starts-with(., 'block10')]/ancestor::pageViewport/@nr"/>
+ <eval expected="5" xpath="//lineArea[starts-with(., 'block11')]/ancestor::pageViewport/@nr"/>
+ <eval expected="5" xpath="//lineArea[starts-with(., 'block12')]/ancestor::pageViewport/@nr"/>
+ <eval expected="5" xpath="//lineArea[starts-with(., 'block13')]/ancestor::pageViewport/@nr"/>
+ <eval expected="5" xpath="//lineArea[starts-with(., 'block14')]/ancestor::pageViewport/@nr"/>
+ <eval expected="6" xpath="//lineArea[starts-with(., 'block15')]/ancestor::pageViewport/@nr"/>
+ </checks>
+</testcase>