aboutsummaryrefslogtreecommitdiffstats
path: root/src/java/org/apache/fop
diff options
context:
space:
mode:
authorJeremias Maerki <jeremias@apache.org>2005-06-23 15:01:14 +0000
committerJeremias Maerki <jeremias@apache.org>2005-06-23 15:01:14 +0000
commit1b0fdf72a4abad2c9e8f8878bf257313321855a9 (patch)
tree8fe2bbd0eb48f6ca77b3a2fd723c54ae8a93076f /src/java/org/apache/fop
parent726fc6a48ffc465e312e60064ed2bde96ea1f5ff (diff)
downloadxmlgraphics-fop-1b0fdf72a4abad2c9e8f8878bf257313321855a9.tar.gz
xmlgraphics-fop-1b0fdf72a4abad2c9e8f8878bf257313321855a9.zip
First parts on a page which don't fit are moved to the next page. A counter avoids endless loops.
Fixes normal-breaking5.xml. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@198768 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src/java/org/apache/fop')
-rw-r--r--src/java/org/apache/fop/area/Page.java17
-rw-r--r--src/java/org/apache/fop/layoutmgr/AbstractBreaker.java22
-rw-r--r--src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java6
-rw-r--r--src/java/org/apache/fop/layoutmgr/BreakingAlgorithm.java81
-rw-r--r--src/java/org/apache/fop/layoutmgr/LineLayoutManager.java2
-rw-r--r--src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java5
-rw-r--r--src/java/org/apache/fop/layoutmgr/PageSequenceLayoutManager.java5
-rw-r--r--src/java/org/apache/fop/layoutmgr/StaticContentLayoutManager.java6
8 files changed, 119 insertions, 25 deletions
diff --git a/src/java/org/apache/fop/area/Page.java b/src/java/org/apache/fop/area/Page.java
index 1733f4879..2f327b55a 100644
--- a/src/java/org/apache/fop/area/Page.java
+++ b/src/java/org/apache/fop/area/Page.java
@@ -55,6 +55,9 @@ public class Page implements Serializable, Cloneable {
// temporary map of unresolved objects used when serializing the page
private HashMap unresolved = null;
+ /** Set to true to make this page behave as if it were not empty. */
+ private boolean fakeNonEmpty = false;
+
/**
* Empty constructor, for cloning
*/
@@ -110,6 +113,13 @@ public class Page implements Serializable, Cloneable {
}
/**
+ * Call this method to force this page to pretend not to be empty.
+ */
+ public void fakeNonEmpty() {
+ this.fakeNonEmpty = true;
+ }
+
+ /**
* Creates a RegionViewport Area object for this pagination Region.
* @param reldims relative dimensions
* @param pageCTM page coordinate transformation matrix
@@ -197,10 +207,11 @@ public class Page implements Serializable, Cloneable {
* @return whether any FOs have been added to the body region
*/
public boolean isEmpty() {
- if (regionBody == null) {
+ if (fakeNonEmpty) {
+ return false;
+ } else if (regionBody == null) {
return true;
- }
- else {
+ } else {
BodyRegion body = (BodyRegion)regionBody.getRegionReference();
return body.isEmpty();
}
diff --git a/src/java/org/apache/fop/layoutmgr/AbstractBreaker.java b/src/java/org/apache/fop/layoutmgr/AbstractBreaker.java
index b6f2eda24..7b5a2eb5a 100644
--- a/src/java/org/apache/fop/layoutmgr/AbstractBreaker.java
+++ b/src/java/org/apache/fop/layoutmgr/AbstractBreaker.java
@@ -106,6 +106,15 @@ public abstract class AbstractBreaker {
protected abstract LayoutManager getCurrentChildLM();
/**
+ * Controls the behaviour of the algorithm in cases where the first element of a part
+ * overflows a line/page.
+ * @return true if the algorithm should try to send the element to the next line/page.
+ */
+ protected boolean isPartOverflowRecoveryActivated() {
+ return true;
+ }
+
+ /**
* Returns the PageViewportProvider if any. PageBreaker overrides this method because each
* page may have a different available BPD which needs to be accessible to the breaking
* algorithm.
@@ -131,6 +140,13 @@ public abstract class AbstractBreaker {
//nop
}
+ /**
+ * This method is called when no content is available for a part. Used to force empty pages.
+ */
+ protected void handleEmptyContent() {
+ //nop
+ }
+
protected abstract void finishPart(PageBreakingAlgorithm alg, PageBreakPosition pbp);
protected LayoutContext createLayoutContext() {
@@ -182,7 +198,8 @@ public abstract class AbstractBreaker {
+ "), flow BPD =" + flowBPD);
PageBreakingAlgorithm alg = new PageBreakingAlgorithm(getTopLevelLM(),
getPageViewportProvider(),
- alignment, alignmentLast, footnoteSeparatorLength);
+ alignment, alignmentLast, footnoteSeparatorLength,
+ isPartOverflowRecoveryActivated());
int iOptPageCount;
BlockSequence effectiveList;
@@ -328,6 +345,9 @@ public abstract class AbstractBreaker {
addAreas(new KnuthPossPosIter(effectiveList,
startElementIndex, endElementIndex + 1), childLC);
+ } else {
+ //no content for this part
+ handleEmptyContent();
}
finishPart(alg, pbp);
diff --git a/src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java b/src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java
index ed855afe4..001fdfbb6 100644
--- a/src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java
@@ -447,6 +447,12 @@ public class BlockContainerLayoutManager extends BlockStackingLayoutManager {
this.ipd = ipd;
}
+ /** @see org.apache.fop.layoutmgr.AbstractBreaker#isPartOverflowRecoveryActivated() */
+ protected boolean isPartOverflowRecoveryActivated() {
+ //For block-containers, this must be disabled because of wanted overflow.
+ return false;
+ }
+
public int getDifferenceOfFirstPart() {
PageBreakPosition pbp = (PageBreakPosition)this.deferredAlg.getPageBreaks().getFirst();
return pbp.difference;
diff --git a/src/java/org/apache/fop/layoutmgr/BreakingAlgorithm.java b/src/java/org/apache/fop/layoutmgr/BreakingAlgorithm.java
index 30deec540..a09680821 100644
--- a/src/java/org/apache/fop/layoutmgr/BreakingAlgorithm.java
+++ b/src/java/org/apache/fop/layoutmgr/BreakingAlgorithm.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.KnuthPageNode;
import org.apache.fop.traits.MinOptMax;
/**
@@ -45,6 +46,8 @@ public abstract class BreakingAlgorithm {
protected static final int INFINITE_RATIO = 1000;
+ private static final int MAX_RECOVERY_ATTEMPTS = 50;
+
// parameters of Knuth's algorithm:
// penalty value for flagged penalties
private int flaggedPenalty = 50;
@@ -117,57 +120,66 @@ public abstract class BreakingAlgorithm {
protected BestRecords best;
private KnuthNode[] positions;
+ /** @see isPartOverflowRecoveryActivated() */
+ private boolean partOverflowRecoveryActivated = true;
+
public BreakingAlgorithm(int align, int alignLast,
- boolean first) {
+ boolean first, boolean partOverflowRecovery) {
alignment = align;
alignmentLast = alignLast;
bFirst = first;
+ this.partOverflowRecoveryActivated = partOverflowRecovery;
this.best = new BestRecords();
}
// this class represent a feasible breaking point
protected class KnuthNode {
- // index of the breakpoint represented by this node
+ /** index of the breakpoint represented by this node */
public int position;
- // number of the line ending at this breakpoint
+ /** number of the line ending at this breakpoint */
public int line;
- // fitness class of the line ending at his breakpoint
+ /** fitness class of the line ending at his breakpoint */
public int fitness;
- // accumulated width of the KnuthElements
+ /** accumulated width of the KnuthElements */
public int totalWidth;
- // accumulated stretchability of the KnuthElements
+ /** accumulated stretchability of the KnuthElements */
public int totalStretch;
- // accumulated shrinkability of the KnuthElements
+ /** accumulated shrinkability of the KnuthElements */
public int totalShrink;
- // adjustment ratio if the line ends at this breakpoint
+ /** adjustment ratio if the line ends at this breakpoint */
public double adjustRatio;
- // available stretch of the line ending at this breakpoint
+ /** available stretch of the line ending at this breakpoint */
public int availableShrink;
- // available shrink of the line ending at this breakpoint
+ /** available shrink of the line ending at this breakpoint */
public int availableStretch;
- // difference between target and actual line width
+ /** difference between target and actual line width */
public int difference;
- // minimum total demerits up to this breakpoint
+ /** minimum total demerits up to this breakpoint */
public double totalDemerits;
- // best node for the preceding breakpoint
+ /** best node for the preceding breakpoint */
public KnuthNode previous;
- // next possible node in the same line
+ /** next possible node in the same line */
public KnuthNode next;
-
+ /**
+ * Holds the number of subsequent recovery attempty that are made to get content fit
+ * into a line.
+ */
+ public int fitRecoveryCounter = 0;
+
public KnuthNode(int position, int line, int fitness,
int totalWidth, int totalStretch, int totalShrink,
double adjustRatio, int availableShrink, int availableStretch, int difference,
@@ -219,7 +231,7 @@ public abstract class BreakingAlgorithm {
int availableShrink, int availableStretch,
int difference, int fitness) {
if (demerits > bestDemerits[fitness]) {
- log.error("New demerits value greter than the old one");
+ log.error("New demerits value greater than the old one");
}
bestDemerits[fitness] = demerits;
bestNode[fitness] = node;
@@ -282,7 +294,22 @@ public abstract class BreakingAlgorithm {
}
}
-
+ /**
+ * @return the number of times the algorithm should try to move overflowing content to the
+ * next line/page.
+ */
+ protected int getMaxRecoveryAttempts() {
+ return MAX_RECOVERY_ATTEMPTS;
+ }
+
+ /**
+ * Controls the behaviour of the algorithm in cases where the first element of a part
+ * overflows a line/page.
+ * @return true if the algorithm should try to send the element to the next line/page.
+ */
+ protected boolean isPartOverflowRecoveryActivated() {
+ return this.partOverflowRecoveryActivated;
+ }
public abstract void updateData1(int total, double demerits) ;
@@ -367,7 +394,25 @@ public abstract class BreakingAlgorithm {
return 0;
}
if (lastTooShort == null || lastForced.position == lastTooShort.position) {
- lastForced = lastTooLong;
+ if (isPartOverflowRecoveryActivated()) {
+ // content would overflow, insert empty line/page and try again
+ KnuthNode node = createNode(
+ lastTooLong.previous.position, lastTooLong.previous.line + 1, 1,
+ 0, 0, 0,
+ 0, 0, 0,
+ 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 (node.fitRecoveryCounter > getMaxRecoveryAttempts()) {
+ throw new RuntimeException("Some content could not fit "
+ + "into a line/page after " + getMaxRecoveryAttempts()
+ + " attempts. Giving up to avoid an endless loop.");
+ }
+ } else {
+ lastForced = lastTooLong;
+ }
} else {
lastForced = lastTooShort;
}
diff --git a/src/java/org/apache/fop/layoutmgr/LineLayoutManager.java b/src/java/org/apache/fop/layoutmgr/LineLayoutManager.java
index 7fe0c3e29..14a9709a0 100644
--- a/src/java/org/apache/fop/layoutmgr/LineLayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/LineLayoutManager.java
@@ -273,7 +273,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager
int indent, int fillerWidth,
int lh, int ld, int fl, int ms, boolean first,
LineLayoutManager llm) {
- super(textAlign, textAlignLast, first);
+ super(textAlign, textAlignLast, first, false);
pageAlignment = pageAlign;
textIndent = indent;
fillerMinWidth = fillerWidth;
diff --git a/src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java b/src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java
index ec1f8860a..b96d2ad78 100644
--- a/src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java
+++ b/src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java
@@ -67,8 +67,9 @@ class PageBreakingAlgorithm extends BreakingAlgorithm {
public PageBreakingAlgorithm(LayoutManager topLevelLM,
PageSequenceLayoutManager.PageViewportProvider pvProvider,
int alignment, int alignmentLast,
- MinOptMax fnSeparatorLength) {
- super(alignment, alignmentLast, true);
+ MinOptMax fnSeparatorLength,
+ boolean partOverflowRecovery) {
+ super(alignment, alignmentLast, true, partOverflowRecovery);
this.topLevelLM = topLevelLM;
this.pvProvider = pvProvider;
best = new BestPageRecords();
diff --git a/src/java/org/apache/fop/layoutmgr/PageSequenceLayoutManager.java b/src/java/org/apache/fop/layoutmgr/PageSequenceLayoutManager.java
index 59f07bf93..2a097cbf8 100644
--- a/src/java/org/apache/fop/layoutmgr/PageSequenceLayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/PageSequenceLayoutManager.java
@@ -286,6 +286,11 @@ public class PageSequenceLayoutManager extends AbstractLayoutManager {
firstPart = false;
}
+ /** @see org.apache.fop.layoutmgr.AbstractBreaker#handleEmptyContent() */
+ protected void handleEmptyContent() {
+ curPV.getPage().fakeNonEmpty();
+ }
+
protected void finishPart(PageBreakingAlgorithm alg, PageBreakPosition pbp) {
// add footnote areas
if (pbp.footnoteFirstListIndex < pbp.footnoteLastListIndex
diff --git a/src/java/org/apache/fop/layoutmgr/StaticContentLayoutManager.java b/src/java/org/apache/fop/layoutmgr/StaticContentLayoutManager.java
index 417ad467e..841634ef4 100644
--- a/src/java/org/apache/fop/layoutmgr/StaticContentLayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/StaticContentLayoutManager.java
@@ -236,6 +236,12 @@ public class StaticContentLayoutManager extends BlockStackingLayoutManager {
this.displayAlign = displayAlign;
}
+ /** @see org.apache.fop.layoutmgr.AbstractBreaker#isPartOverflowRecoveryActivated() */
+ protected boolean isPartOverflowRecoveryActivated() {
+ //For side regions, this must be disabled because of wanted overflow.
+ return false;
+ }
+
public boolean isOverflow() {
return this.overflow;
}