aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVincent Hennebert <vhennebert@apache.org>2009-08-26 18:50:10 +0000
committerVincent Hennebert <vhennebert@apache.org>2009-08-26 18:50:10 +0000
commitbcfda76c15640c34c91f2d8e29d85b9326ab8d25 (patch)
tree8ebab128378a36a84ddd450063a402ff2b6841e5
parent9520407736edcb4389c1418b70e0f7f376d7bd85 (diff)
downloadxmlgraphics-fop-bcfda76c15640c34c91f2d8e29d85b9326ab8d25.tar.gz
xmlgraphics-fop-bcfda76c15640c34c91f2d8e29d85b9326ab8d25.zip
Merged back ChangingIPDHack branch into Trunk
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@808157 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--src/java/org/apache/fop/layoutmgr/AbstractBaseLayoutManager.java20
-rw-r--r--src/java/org/apache/fop/layoutmgr/AbstractBreaker.java146
-rw-r--r--src/java/org/apache/fop/layoutmgr/AbstractLayoutManager.java40
-rw-r--r--src/java/org/apache/fop/layoutmgr/AbstractPageSequenceLayoutManager.java5
-rw-r--r--src/java/org/apache/fop/layoutmgr/AreaAdditionUtil.java2
-rw-r--r--src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java306
-rw-r--r--src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java36
-rw-r--r--src/java/org/apache/fop/layoutmgr/BlockStackingLayoutManager.java402
-rw-r--r--src/java/org/apache/fop/layoutmgr/BreakingAlgorithm.java21
-rw-r--r--src/java/org/apache/fop/layoutmgr/FlowLayoutManager.java219
-rw-r--r--src/java/org/apache/fop/layoutmgr/InlineKnuthSequence.java16
-rw-r--r--src/java/org/apache/fop/layoutmgr/LayoutContext.java39
-rw-r--r--src/java/org/apache/fop/layoutmgr/LayoutManager.java33
-rw-r--r--src/java/org/apache/fop/layoutmgr/LeafPosition.java11
-rw-r--r--src/java/org/apache/fop/layoutmgr/PageBreaker.java35
-rw-r--r--src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java62
-rw-r--r--src/java/org/apache/fop/layoutmgr/PageProvider.java27
-rw-r--r--src/java/org/apache/fop/layoutmgr/Position.java5
-rw-r--r--src/java/org/apache/fop/layoutmgr/SpaceResolver.java6
-rw-r--r--src/java/org/apache/fop/layoutmgr/StaticContentLayoutManager.java103
-rw-r--r--src/java/org/apache/fop/layoutmgr/inline/ContentLayoutManager.java10
-rwxr-xr-xsrc/java/org/apache/fop/layoutmgr/inline/InlineLayoutManager.java10
-rw-r--r--src/java/org/apache/fop/layoutmgr/inline/InlineStackingLayoutManager.java32
-rw-r--r--src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java558
-rw-r--r--src/java/org/apache/fop/layoutmgr/list/ListItemLayoutManager.java7
-rw-r--r--src/java/org/apache/fop/render/pdf/PDFEventProducer.xml3
-rw-r--r--test/layoutengine/standard-testcases/flow_changing-ipd_1.xml97
-rw-r--r--test/layoutengine/standard-testcases/flow_changing-ipd_2.xml75
-rw-r--r--test/layoutengine/standard-testcases/flow_changing-ipd_3.xml86
-rw-r--r--test/layoutengine/standard-testcases/flow_changing-ipd_4.xml159
-rw-r--r--test/layoutengine/standard-testcases/flow_changing-ipd_block-container_1.xml101
-rw-r--r--test/layoutengine/standard-testcases/flow_changing-ipd_block-container_2.xml89
32 files changed, 1945 insertions, 816 deletions
diff --git a/src/java/org/apache/fop/layoutmgr/AbstractBaseLayoutManager.java b/src/java/org/apache/fop/layoutmgr/AbstractBaseLayoutManager.java
index f7acf3eb5..8c213d7d5 100644
--- a/src/java/org/apache/fop/layoutmgr/AbstractBaseLayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/AbstractBaseLayoutManager.java
@@ -19,8 +19,12 @@
package org.apache.fop.layoutmgr;
+import java.util.List;
+import java.util.Stack;
+
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+
import org.apache.fop.datatypes.LengthBase;
import org.apache.fop.datatypes.PercentBaseContext;
import org.apache.fop.fo.FObj;
@@ -253,4 +257,20 @@ public abstract class AbstractBaseLayoutManager
return fobj;
}
+ /** {@inheritDoc} */
+ public void reset() {
+ throw new UnsupportedOperationException("Not implemented");
+ }
+
+ /** {@inheritDoc} */
+ public boolean isRestartable() {
+ return false;
+ }
+
+ /** {@inheritDoc} */
+ public List getNextKnuthElements(LayoutContext context, int alignment, Stack lmStack,
+ Position positionAtIPDChange, LayoutManager restartAtLM) {
+ throw new UnsupportedOperationException("Not implemented");
+ }
+
}
diff --git a/src/java/org/apache/fop/layoutmgr/AbstractBreaker.java b/src/java/org/apache/fop/layoutmgr/AbstractBreaker.java
index 6393935ae..1a6f7cfb9 100644
--- a/src/java/org/apache/fop/layoutmgr/AbstractBreaker.java
+++ b/src/java/org/apache/fop/layoutmgr/AbstractBreaker.java
@@ -19,6 +19,8 @@
package org.apache.fop.layoutmgr;
+import java.util.Collections;
+import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
@@ -27,6 +29,7 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.fop.fo.Constants;
+import org.apache.fop.layoutmgr.BreakingAlgorithm.KnuthNode;
import org.apache.fop.traits.MinOptMax;
import org.apache.fop.util.ListUtil;
@@ -247,6 +250,11 @@ public abstract class AbstractBreaker {
*/
protected abstract List getNextKnuthElements(LayoutContext context, int alignment);
+ protected List getNextKnuthElements(LayoutContext context, int alignment,
+ Position positionAtIPDChange, LayoutManager restartAtLM) {
+ throw new UnsupportedOperationException("TODO: implement acceptable fallback");
+ }
+
/** @return true if there's no content that could be handled. */
public boolean isEmpty() {
return (this.blockLists.isEmpty());
@@ -293,14 +301,6 @@ public abstract class AbstractBreaker {
/**
* Starts the page breaking process.
* @param flowBPD the constant available block-progression-dimension (used for every part)
- */
- public void doLayout(int flowBPD) {
- doLayout(flowBPD, false);
- }
-
- /**
- * Starts the page breaking process.
- * @param flowBPD the constant available block-progression-dimension (used for every part)
* @param autoHeight true if warnings about overflows should be disabled because the
* the BPD is really undefined (for footnote-separators, for example)
*/
@@ -354,7 +354,6 @@ public abstract class AbstractBreaker {
getPageProvider(), createLayoutListener(),
alignment, alignmentLast, footnoteSeparatorLength,
isPartOverflowRecoveryActivated(), autoHeight, isSinglePartFavored());
- int iOptPageCount;
BlockSequence effectiveList;
if (getCurrentDisplayAlign() == Constants.EN_X_FILL) {
@@ -365,22 +364,108 @@ public abstract class AbstractBreaker {
effectiveList = blockList;
}
- //iOptPageCount = alg.firstFit(effectiveList, flowBPD, 1, true);
alg.setConstantLineWidth(flowBPD);
- iOptPageCount = alg.findBreakingPoints(effectiveList, /*flowBPD,*/
- 1, true, BreakingAlgorithm.ALL_BREAKS);
- log.debug("PLM> iOptPageCount= " + iOptPageCount
- + " pageBreaks.size()= " + alg.getPageBreaks().size());
+ int optimalPageCount = alg.findBreakingPoints(effectiveList, 1, true,
+ BreakingAlgorithm.ALL_BREAKS);
+ if (alg.ipdChanged()) {
+ KnuthNode optimalBreak = alg.getBestNodeBeforeIPDChange();
+ int positionIndex = optimalBreak.position;
+ KnuthElement elementAtBreak = alg.getElement(positionIndex);
+ Position positionAtBreak = elementAtBreak.getPosition();
+ if (!(positionAtBreak instanceof SpaceResolver.SpaceHandlingBreakPosition)) {
+ throw new UnsupportedOperationException(
+ "Don't know how to restart at position" + positionAtBreak);
+ }
+ /* Retrieve the original position wrapped into this space position */
+ positionAtBreak = positionAtBreak.getPosition();
+ LayoutManager restartAtLM = null;
+ List firstElements = Collections.EMPTY_LIST;
+ if (containsNonRestartableLM(positionAtBreak)) {
+ firstElements = new LinkedList();
+ boolean boxFound = false;
+ Iterator iter = effectiveList.listIterator(++positionIndex);
+ Position position = null;
+ while (iter.hasNext()
+ && (position == null || containsNonRestartableLM(position))) {
+ KnuthElement element = (KnuthElement) iter.next();
+ positionIndex++;
+ position = element.getPosition();
+ if (element.isBox()) {
+ boxFound = true;
+ firstElements.add(element);
+ } else if (boxFound) {
+ firstElements.add(element);
+ }
+ }
+ if (position instanceof SpaceResolver.SpaceHandlingBreakPosition) {
+ /* Retrieve the original position wrapped into this space position */
+ positionAtBreak = position.getPosition();
+ }
+ }
+ if (positionAtBreak.getIndex() == -1) {
+ /*
+ * This is an indication that we are between two blocks
+ * (possibly surrounded by another block), not inside a
+ * paragraph.
+ */
+ Position position;
+ Iterator iter = effectiveList.listIterator(positionIndex + 1);
+ do {
+ KnuthElement nextElement = (KnuthElement) iter.next();
+ position = nextElement.getPosition();
+ } while (position == null
+ || position instanceof SpaceResolver.SpaceHandlingPosition
+ || position instanceof SpaceResolver.SpaceHandlingBreakPosition
+ && position.getPosition().getIndex() == -1);
+ LayoutManager surroundingLM = positionAtBreak.getLM();
+ while (position.getLM() != surroundingLM) {
+ position = position.getPosition();
+ }
+ restartAtLM = position.getPosition().getLM();
+ }
+ log.trace("IPD changes after page " + optimalPageCount + " at index "
+ + optimalBreak.position);
+ doPhase3(alg, optimalPageCount, blockList, effectiveList);
+
+ blockLists.clear();
+ blockListIndex = -1;
+ nextSequenceStartsOn = getNextBlockList(childLC, Constants.EN_COLUMN,
+ positionAtBreak, restartAtLM, firstElements);
+ } else {
+ log.debug("PLM> iOptPageCount= " + optimalPageCount
+ + " pageBreaks.size()= " + alg.getPageBreaks().size());
- //*** Phase 3: Add areas ***
- doPhase3(alg, iOptPageCount, blockList, effectiveList);
+ //*** Phase 3: Add areas ***
+ doPhase3(alg, optimalPageCount, blockList, effectiveList);
+ }
}
}
}
/**
+ * Returns {@code true} if the given position or one of its descendants
+ * corresponds to a non-restartable LM.
+ *
+ * @param position a position
+ * @return {@code true} if there is a non-restartable LM in the hierarchy
+ */
+ private boolean containsNonRestartableLM(Position position) {
+ LayoutManager lm = position.getLM();
+ if (lm != null && !lm.isRestartable()) {
+ return true;
+ } else {
+ Position subPosition = position.getPosition();
+ if (subPosition == null) {
+ return false;
+ } else {
+ return containsNonRestartableLM(subPosition);
+ }
+ }
+ }
+
+ /**
* Phase 3 of Knuth algorithm: Adds the areas
* @param alg PageBreakingAlgorithm instance which determined the breaks
* @param partCount number of parts (pages) to be rendered
@@ -559,6 +644,7 @@ public abstract class AbstractBreaker {
protected int handleSpanChange(LayoutContext childLC, int nextSequenceStartsOn) {
return nextSequenceStartsOn;
}
+
/**
* Gets the next block list (sequence) and adds it to a list of block lists if it's not empty.
* @param childLC LayoutContext to use
@@ -567,12 +653,38 @@ public abstract class AbstractBreaker {
*/
protected int getNextBlockList(LayoutContext childLC,
int nextSequenceStartsOn) {
+ return getNextBlockList(childLC, nextSequenceStartsOn, null, null, null);
+ }
+
+ /**
+ * Gets the next block list (sequence) and adds it to a list of block lists
+ * if it's not empty.
+ *
+ * @param childLC LayoutContext to use
+ * @param nextSequenceStartsOn indicates on what page the next sequence
+ * should start
+ * @param positionAtIPDChange last element on the part before an IPD change
+ * @param restartAtLM the layout manager from which to restart, if IPD
+ * change occurs between two LMs
+ * @param firstElements elements from non-restartable LMs on the new page
+ * @return the page on which the next content should appear after a hard
+ * break
+ */
+ protected int getNextBlockList(LayoutContext childLC, int nextSequenceStartsOn,
+ Position positionAtIPDChange, LayoutManager restartAtLM, List firstElements) {
updateLayoutContext(childLC);
//Make sure the span change signal is reset
childLC.signalSpanChange(Constants.NOT_SET);
BlockSequence blockList;
- List returnedList = getNextKnuthElements(childLC, alignment);
+ List returnedList;
+ if (positionAtIPDChange == null) {
+ returnedList = getNextKnuthElements(childLC, alignment);
+ } else {
+ returnedList = getNextKnuthElements(childLC, alignment, positionAtIPDChange,
+ restartAtLM);
+ returnedList.addAll(0, firstElements);
+ }
if (returnedList != null) {
if (returnedList.isEmpty()) {
nextSequenceStartsOn = handleSpanChange(childLC, nextSequenceStartsOn);
diff --git a/src/java/org/apache/fop/layoutmgr/AbstractLayoutManager.java b/src/java/org/apache/fop/layoutmgr/AbstractLayoutManager.java
index 8dca1c749..82f0599eb 100644
--- a/src/java/org/apache/fop/layoutmgr/AbstractLayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/AbstractLayoutManager.java
@@ -47,22 +47,22 @@ public abstract class AbstractLayoutManager extends AbstractBaseLayoutManager
private static Log log = LogFactory.getLog(AbstractLayoutManager.class);
/** Parent LayoutManager for this LayoutManager */
- protected LayoutManager parentLM = null;
+ protected LayoutManager parentLM;
/** List of child LayoutManagers */
- protected List childLMs = null;
+ protected List childLMs;
/** Iterator for child LayoutManagers */
- protected ListIterator fobjIter = null;
+ protected ListIterator fobjIter;
/** Marker map for markers related to this LayoutManager */
- private Map markers = null;
+ private Map markers;
/** True if this LayoutManager has handled all of its content. */
- private boolean isFinished = false;
+ private boolean isFinished;
/** child LM during getNextKnuthElement phase */
- protected LayoutManager curChildLM = null;
+ protected LayoutManager curChildLM;
/** child LM iterator during getNextKnuthElement phase */
- protected ListIterator childLMiter = null;
+ protected ListIterator childLMiter;
private int lastGeneratedPosition = -1;
private int smallestPosNumberChecked = Integer.MAX_VALUE;
@@ -122,6 +122,14 @@ public abstract class AbstractLayoutManager extends AbstractBaseLayoutManager
return null;
}
+ protected void setCurrentChildLM(LayoutManager childLM) {
+ curChildLM = childLM;
+ childLMiter = new LMiter(this);
+ do {
+ curChildLM = (LayoutManager) childLMiter.next();
+ } while (curChildLM != childLM);
+ }
+
/**
* Return indication if getChildLM will return another LM.
* @return true if another child LM is still available
@@ -450,4 +458,22 @@ public abstract class AbstractLayoutManager extends AbstractBaseLayoutManager
return (super.toString() + (fobj != null ? "[fobj=" + fobj.toString() + "]" : ""));
}
+ /** {@inheritDoc} */
+ public void reset() {
+ isFinished = false;
+ curChildLM = null;
+ childLMiter = new LMiter(this);
+ /*
+ * Reset the children LM. Can't rely on childLMiter since it may have
+ * been set to null in checkEndOfLayout.
+ */
+ for (LMiter iter = new LMiter(this); iter.hasNext();) {
+ ((LayoutManager) iter.next()).reset();
+ }
+ if (fobj != null) {
+ markers = fobj.getMarkers();
+ }
+ lastGeneratedPosition = -1;
+ }
+
}
diff --git a/src/java/org/apache/fop/layoutmgr/AbstractPageSequenceLayoutManager.java b/src/java/org/apache/fop/layoutmgr/AbstractPageSequenceLayoutManager.java
index 758761303..0fa046aee 100644
--- a/src/java/org/apache/fop/layoutmgr/AbstractPageSequenceLayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/AbstractPageSequenceLayoutManager.java
@@ -382,4 +382,9 @@ public abstract class AbstractPageSequenceLayoutManager extends AbstractLayoutMa
}
}
+ /** {@inheritDoc} */
+ public void reset() {
+ throw new IllegalStateException();
+ }
+
}
diff --git a/src/java/org/apache/fop/layoutmgr/AreaAdditionUtil.java b/src/java/org/apache/fop/layoutmgr/AreaAdditionUtil.java
index a429359ad..14183c52e 100644
--- a/src/java/org/apache/fop/layoutmgr/AreaAdditionUtil.java
+++ b/src/java/org/apache/fop/layoutmgr/AreaAdditionUtil.java
@@ -117,7 +117,7 @@ public class AreaAdditionUtil {
// set space after for each LM, in order to implement
// display-align = distribute
lc.setSpaceAfter(layoutContext.getSpaceAfter());
- lc.setStackLimitsFrom(layoutContext);
+ lc.setStackLimitBP(layoutContext.getStackLimitBP());
childLM.addAreas(childPosIter, lc);
}
diff --git a/src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java b/src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java
index 4a4becebf..e86c5feaf 100644
--- a/src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java
@@ -24,6 +24,7 @@ import java.awt.geom.Rectangle2D;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
+import java.util.Stack;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -397,6 +398,311 @@ public class BlockContainerLayoutManager extends BlockStackingLayoutManager
return returnList;
}
+ /** {@inheritDoc} */
+ public List getNextKnuthElements(LayoutContext context, int alignment, Stack lmStack,
+ Position restartPosition, LayoutManager restartAtLM) {
+ resetSpaces();
+ if (isAbsoluteOrFixed()) {
+ return getNextKnuthElementsAbsolute(context, alignment);
+ }
+
+ autoHeight = false;
+ //boolean rotated = (getBlockContainerFO().getReferenceOrientation() % 180 != 0);
+ int maxbpd = context.getStackLimitBP().opt;
+ int allocBPD;
+ if (height.getEnum() == EN_AUTO
+ || (!height.isAbsolute() && getAncestorBlockAreaBPD() <= 0)) {
+ //auto height when height="auto" or "if that dimension is not specified explicitly
+ //(i.e., it depends on content's block-progression-dimension)" (XSL 1.0, 7.14.1)
+ allocBPD = maxbpd;
+ autoHeight = true;
+ if (getBlockContainerFO().getReferenceOrientation() == 0) {
+ //Cannot easily inline element list when ref-or="180"
+ inlineElementList = true;
+ }
+ } else {
+ allocBPD = height.getValue(this); //this is the content-height
+ allocBPD += getBPIndents();
+ }
+ vpContentBPD = allocBPD - getBPIndents();
+
+ referenceIPD = context.getRefIPD();
+ if (width.getEnum() == EN_AUTO) {
+ updateContentAreaIPDwithOverconstrainedAdjust();
+ } else {
+ int contentWidth = width.getValue(this);
+ updateContentAreaIPDwithOverconstrainedAdjust(contentWidth);
+ }
+
+ double contentRectOffsetX = 0;
+ contentRectOffsetX += getBlockContainerFO()
+ .getCommonMarginBlock().startIndent.getValue(this);
+ double contentRectOffsetY = 0;
+ contentRectOffsetY += getBlockContainerFO()
+ .getCommonBorderPaddingBackground().getBorderBeforeWidth(false);
+ contentRectOffsetY += getBlockContainerFO()
+ .getCommonBorderPaddingBackground().getPaddingBefore(false, this);
+
+ updateRelDims(contentRectOffsetX, contentRectOffsetY, autoHeight);
+
+ int availableIPD = referenceIPD - getIPIndents();
+ if (getContentAreaIPD() > availableIPD) {
+ BlockLevelEventProducer eventProducer = BlockLevelEventProducer.Provider.get(
+ getBlockContainerFO().getUserAgent().getEventBroadcaster());
+ eventProducer.objectTooWide(this, getBlockContainerFO().getName(),
+ getContentAreaIPD(), context.getRefIPD(),
+ getBlockContainerFO().getLocator());
+ }
+
+ MinOptMax stackLimit = new MinOptMax(relDims.bpd);
+
+ List returnedList;
+ List contentList = new LinkedList();
+ List returnList = new LinkedList();
+
+ if (!breakBeforeServed) {
+ breakBeforeServed = true;
+ if (!context.suppressBreakBefore()) {
+ if (addKnuthElementsForBreakBefore(returnList, context)) {
+ return returnList;
+ }
+ }
+ }
+
+ if (!firstVisibleMarkServed) {
+ addKnuthElementsForSpaceBefore(returnList, alignment);
+ context.updateKeepWithPreviousPending(getKeepWithPrevious());
+ }
+
+ addKnuthElementsForBorderPaddingBefore(returnList, !firstVisibleMarkServed);
+ firstVisibleMarkServed = true;
+
+ if (autoHeight && inlineElementList) {
+ //Spaces, border and padding to be repeated at each break
+ addPendingMarks(context);
+
+ BlockLevelLayoutManager curLM; // currently active LM
+ BlockLevelLayoutManager prevLM = null; // previously active LM
+
+ LayoutContext childLC = new LayoutContext(0);
+ if (lmStack.isEmpty()) {
+ assert restartAtLM != null && restartAtLM.getParent() == this;
+ curLM = (BlockLevelLayoutManager) restartAtLM;
+ curLM.reset();
+ setCurrentChildLM(curLM);
+
+ childLC.copyPendingMarksFrom(context);
+ childLC.setStackLimitBP(MinOptMax.subtract(context.getStackLimitBP(), stackLimit));
+ childLC.setRefIPD(relDims.ipd);
+ childLC.setWritingMode(getBlockContainerFO().getWritingMode());
+ if (curLM == this.childLMs.get(0)) {
+ childLC.setFlags(LayoutContext.SUPPRESS_BREAK_BEFORE);
+ //Handled already by the parent (break collapsing, see above)
+ }
+
+ // get elements from curLM
+ returnedList = curLM.getNextKnuthElements(childLC, alignment);
+ } else {
+ curLM = (BlockLevelLayoutManager) lmStack.pop();
+ setCurrentChildLM(curLM);
+
+ childLC.copyPendingMarksFrom(context);
+ childLC.setStackLimitBP(MinOptMax.subtract(context.getStackLimitBP(), stackLimit));
+ childLC.setRefIPD(relDims.ipd);
+ childLC.setWritingMode(getBlockContainerFO().getWritingMode());
+ if (curLM == this.childLMs.get(0)) {
+ childLC.setFlags(LayoutContext.SUPPRESS_BREAK_BEFORE);
+ //Handled already by the parent (break collapsing, see above)
+ }
+
+ // get elements from curLM
+ returnedList = curLM.getNextKnuthElements(childLC, alignment, lmStack,
+ restartPosition, restartAtLM);
+ }
+ if (contentList.isEmpty() && childLC.isKeepWithPreviousPending()) {
+ //Propagate keep-with-previous up from the first child
+ context.updateKeepWithPreviousPending(childLC.getKeepWithPreviousPending());
+ childLC.clearKeepWithPreviousPending();
+ }
+ if (returnedList.size() == 1
+ && ((ListElement)returnedList.get(0)).isForcedBreak()) {
+ // a descendant of this block has break-before
+ /*
+ if (returnList.size() == 0) {
+ // the first child (or its first child ...) has
+ // break-before;
+ // all this block, including space before, will be put in
+ // the
+ // following page
+ bSpaceBeforeServed = false;
+ }*/
+ contentList.addAll(returnedList);
+
+ // "wrap" the Position inside each element
+ // moving the elements from contentList to returnList
+ returnedList = new LinkedList();
+ wrapPositionElements(contentList, returnList);
+
+ return returnList;
+ } else {
+ if (prevLM != null) {
+ // there is a block handled by prevLM
+ // before the one handled by curLM
+ addInBetweenBreak(contentList, context, childLC);
+ }
+ contentList.addAll(returnedList);
+ if (!returnedList.isEmpty()) {
+ if (((ListElement) ListUtil.getLast(returnedList))
+ .isForcedBreak()) {
+ // a descendant of this block has break-after
+ if (curLM.isFinished()) {
+ // there is no other content in this block;
+ // it's useless to add space after before a page break
+ setFinished(true);
+ }
+
+ returnedList = new LinkedList();
+ wrapPositionElements(contentList, returnList);
+
+ return returnList;
+ }
+ }
+ }
+ // propagate and clear
+ context.updateKeepWithNextPending(childLC.getKeepWithNextPending());
+ childLC.clearKeepsPending();
+ prevLM = curLM;
+
+ while ((curLM = (BlockLevelLayoutManager) getChildLM()) != null) {
+ curLM.reset();
+ childLC = new LayoutContext(0);
+ childLC.copyPendingMarksFrom(context);
+ // curLM is a ?
+ childLC.setStackLimitBP(MinOptMax.subtract(context.getStackLimitBP(), stackLimit));
+ childLC.setRefIPD(relDims.ipd);
+ childLC.setWritingMode(getBlockContainerFO().getWritingMode());
+ if (curLM == this.childLMs.get(0)) {
+ childLC.setFlags(LayoutContext.SUPPRESS_BREAK_BEFORE);
+ //Handled already by the parent (break collapsing, see above)
+ }
+
+ // get elements from curLM
+ returnedList = curLM.getNextKnuthElements(childLC, alignment);
+ if (contentList.isEmpty() && childLC.isKeepWithPreviousPending()) {
+ //Propagate keep-with-previous up from the first child
+ context.updateKeepWithPreviousPending(childLC.getKeepWithPreviousPending());
+ childLC.clearKeepWithPreviousPending();
+ }
+ if (returnedList.size() == 1
+ && ((ListElement)returnedList.get(0)).isForcedBreak()) {
+ // a descendant of this block has break-before
+ /*
+ if (returnList.size() == 0) {
+ // the first child (or its first child ...) has
+ // break-before;
+ // all this block, including space before, will be put in
+ // the
+ // following page
+ bSpaceBeforeServed = false;
+ }*/
+ contentList.addAll(returnedList);
+
+ // "wrap" the Position inside each element
+ // moving the elements from contentList to returnList
+ returnedList = new LinkedList();
+ wrapPositionElements(contentList, returnList);
+
+ return returnList;
+ } else {
+ if (prevLM != null) {
+ // there is a block handled by prevLM
+ // before the one handled by curLM
+ addInBetweenBreak(contentList, context, childLC);
+ }
+ contentList.addAll(returnedList);
+ if (returnedList.isEmpty()) {
+ //Avoid NoSuchElementException below (happens with empty blocks)
+ continue;
+ }
+ if (((ListElement) ListUtil.getLast(returnedList))
+ .isForcedBreak()) {
+ // a descendant of this block has break-after
+ if (curLM.isFinished()) {
+ // there is no other content in this block;
+ // it's useless to add space after before a page break
+ setFinished(true);
+ }
+
+ returnedList = new LinkedList();
+ wrapPositionElements(contentList, returnList);
+
+ return returnList;
+ }
+ }
+ // propagate and clear
+ context.updateKeepWithNextPending(childLC.getKeepWithNextPending());
+ childLC.clearKeepsPending();
+ prevLM = curLM;
+ }
+
+ returnedList = new LinkedList();
+ wrapPositionElements(contentList, returnList);
+
+ } else {
+ MinOptMax range = new MinOptMax(relDims.ipd);
+ BlockContainerBreaker breaker = new BlockContainerBreaker(this, range);
+ breaker.doLayout(relDims.bpd, autoHeight);
+ boolean contentOverflows = breaker.isOverflow();
+ if (autoHeight) {
+ //Update content BPD now that it is known
+ int newHeight = breaker.deferredAlg.totalWidth;
+ boolean switchedProgressionDirection
+ = (getBlockContainerFO().getReferenceOrientation() % 180 != 0);
+ if (switchedProgressionDirection) {
+ setContentAreaIPD(newHeight);
+ } else {
+ vpContentBPD = newHeight;
+ }
+ updateRelDims(contentRectOffsetX, contentRectOffsetY, false);
+ }
+
+ Position bcPosition = new BlockContainerPosition(this, breaker);
+ returnList.add(new KnuthBox(vpContentBPD, notifyPos(bcPosition), false));
+ //TODO Handle min/opt/max for block-progression-dimension
+ /* These two elements will be used to add stretchability to the above box
+ returnList.add(new KnuthPenalty(0, KnuthElement.INFINITE,
+ false, returnPosition, false));
+ returnList.add(new KnuthGlue(0, 1 * constantLineHeight, 0,
+ LINE_NUMBER_ADJUSTMENT, returnPosition, false));
+ */
+
+ if (contentOverflows) {
+ BlockLevelEventProducer eventProducer = BlockLevelEventProducer.Provider.get(
+ getBlockContainerFO().getUserAgent().getEventBroadcaster());
+ boolean canRecover = (getBlockContainerFO().getOverflow() != EN_ERROR_IF_OVERFLOW);
+ eventProducer.viewportOverflow(this, getBlockContainerFO().getName(),
+ breaker.getOverflowAmount(), needClip(), canRecover,
+ getBlockContainerFO().getLocator());
+ }
+ }
+ addKnuthElementsForBorderPaddingAfter(returnList, true);
+ addKnuthElementsForSpaceAfter(returnList, alignment);
+
+ //All child content is processed. Only break-after can occur now, so...
+ context.clearPendingMarks();
+ addKnuthElementsForBreakAfter(returnList, context);
+
+ context.updateKeepWithNextPending(getKeepWithNext());
+
+ setFinished(true);
+ return returnList;
+ }
+
+ /** {@inheritDoc} */
+ public boolean isRestartable() {
+ return true;
+ }
+
private List getNextKnuthElementsAbsolute(LayoutContext context, int alignment) {
autoHeight = false;
diff --git a/src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java b/src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java
index 20895a38e..126ab3796 100644
--- a/src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java
@@ -22,6 +22,7 @@ package org.apache.fop.layoutmgr;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
+import java.util.Stack;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -67,9 +68,6 @@ public class BlockLayoutManager extends BlockStackingLayoutManager
private MinOptMax effSpaceBefore;
private MinOptMax effSpaceAfter;
- /** The list of child BreakPoss instances. */
- protected List childBreaks = new java.util.ArrayList();
-
/**
* Creates a new BlockLayoutManager.
* @param inBlock the block FO object to create the layout manager for.
@@ -114,8 +112,19 @@ public class BlockLayoutManager extends BlockStackingLayoutManager
/** {@inheritDoc} */
public List getNextKnuthElements(LayoutContext context, int alignment) {
+ return getNextKnuthElements(context, alignment, null, null, null);
+ }
+
+ /** {@inheritDoc} */
+ public List getNextKnuthElements(LayoutContext context, int alignment, Stack lmStack,
+ Position restartPosition, LayoutManager restartAtLM) {
resetSpaces();
- return super.getNextKnuthElements(context, alignment);
+ if (lmStack == null) {
+ return super.getNextKnuthElements(context, alignment);
+ } else {
+ return super.getNextKnuthElements(context, alignment, lmStack, restartPosition,
+ restartAtLM);
+ }
}
private void resetSpaces() {
@@ -249,8 +258,8 @@ public class BlockLayoutManager extends BlockStackingLayoutManager
// and put them in a new list;
LinkedList positionList = new LinkedList();
Position pos;
- boolean bSpaceBefore = false;
- boolean bSpaceAfter = false;
+ boolean spaceBefore = false;
+ boolean spaceAfter = false;
Position firstPos = null;
Position lastPos = null;
while (parentIter.hasNext()) {
@@ -273,11 +282,11 @@ public class BlockLayoutManager extends BlockStackingLayoutManager
// this means the space was not discarded
if (positionList.size() == 0) {
// pos was in the element representing space-before
- bSpaceBefore = true;
+ spaceBefore = true;
//log.trace(" space before");
} else {
// pos was in the element representing space-after
- bSpaceAfter = true;
+ spaceAfter = true;
//log.trace(" space-after");
}
} else if (innerPosition.getLM() == this
@@ -302,7 +311,7 @@ public class BlockLayoutManager extends BlockStackingLayoutManager
// the Positions in positionList were inside the elements
// created by the LineLM
childPosIter = new StackingIter(positionList.listIterator());
- } else {
+ } else {
// the Positions in positionList were inside the elements
// created by the BlockLM in the createUnitElements() method
//if (((Position) positionList.getLast()) instanceof
@@ -341,7 +350,7 @@ public class BlockLayoutManager extends BlockStackingLayoutManager
// + " spacing");
// add space before and / or after the paragraph
// to reach a multiple of bpUnit
- if (bSpaceBefore && bSpaceAfter) {
+ if (spaceBefore && spaceAfter) {
foSpaceBefore = new SpaceVal(getBlockFO()
.getCommonMarginBlock().spaceBefore, this).getSpace();
foSpaceAfter = new SpaceVal(getBlockFO()
@@ -354,7 +363,7 @@ public class BlockLayoutManager extends BlockStackingLayoutManager
+ foSpaceBefore.min
+ foSpaceAfter.min)
* bpUnit - splitLength - adjustedSpaceBefore;
- } else if (bSpaceBefore) {
+ } else if (spaceBefore) {
adjustedSpaceBefore = neededUnits(splitLength
+ foSpaceBefore.min)
* bpUnit - splitLength;
@@ -547,5 +556,10 @@ public class BlockLayoutManager extends BlockStackingLayoutManager
}
}
+ /** {@inheritDoc} */
+ public boolean isRestartable() {
+ return true;
+ }
+
}
diff --git a/src/java/org/apache/fop/layoutmgr/BlockStackingLayoutManager.java b/src/java/org/apache/fop/layoutmgr/BlockStackingLayoutManager.java
index 73c8eb00d..53c529eaa 100644
--- a/src/java/org/apache/fop/layoutmgr/BlockStackingLayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/BlockStackingLayoutManager.java
@@ -23,6 +23,7 @@ import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
+import java.util.Stack;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -30,12 +31,12 @@ import org.apache.commons.logging.LogFactory;
import org.apache.fop.area.Area;
import org.apache.fop.area.Block;
import org.apache.fop.area.BlockParent;
-import org.apache.fop.fo.FObj;
import org.apache.fop.fo.Constants;
+import org.apache.fop.fo.FObj;
import org.apache.fop.fo.properties.BreakPropertySet;
import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
-import org.apache.fop.fo.properties.SpaceProperty;
import org.apache.fop.fo.properties.KeepProperty;
+import org.apache.fop.fo.properties.SpaceProperty;
import org.apache.fop.layoutmgr.inline.InlineLayoutManager;
import org.apache.fop.layoutmgr.inline.LineLayoutManager;
import org.apache.fop.traits.MinOptMax;
@@ -54,31 +55,26 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager
*/
private static Log log = LogFactory.getLog(BlockStackingLayoutManager.class);
- /**
- * Reference to FO whose areas it's managing or to the traits
- * of the FO.
- */
- //protected LayoutManager curChildLM = null; AbstractLayoutManager also defines this!
- protected BlockParent parentArea = null;
+ protected BlockParent parentArea;
/** Value of the block-progression-unit (non-standard property) */
- protected int bpUnit = 0;
+ protected int bpUnit;
/** space-before value adjusted for block-progression-unit handling */
- protected int adjustedSpaceBefore = 0;
+ protected int adjustedSpaceBefore;
/** space-after value adjusted for block-progression-unit handling */
- protected int adjustedSpaceAfter = 0;
+ protected int adjustedSpaceAfter;
/** Only used to store the original list when createUnitElements is called */
- protected List storedList = null;
+ protected List storedList;
/** Indicates whether break before has been served or not */
- protected boolean breakBeforeServed = false;
+ protected boolean breakBeforeServed;
/** Indicates whether the first visible mark has been returned by this LM, yet */
- protected boolean firstVisibleMarkServed = false;
+ protected boolean firstVisibleMarkServed;
/** Reference IPD available */
- protected int referenceIPD = 0;
+ protected int referenceIPD;
/** the effective start-indent value */
- protected int startIndent = 0;
+ protected int startIndent;
/** the effective end-indent value */
- protected int endIndent = 0;
+ protected int endIndent;
/**
* Holds the (one-time use) fo:block space-before
* and -after properties. Large fo:blocks are split
@@ -88,13 +84,13 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager
* Block and space-after at the end of the last Block
* used in rendering the fo:block.
*/
- protected MinOptMax foSpaceBefore = null;
+ protected MinOptMax foSpaceBefore;
/** see foSpaceBefore */
- protected MinOptMax foSpaceAfter = null;
+ protected MinOptMax foSpaceAfter;
private Position auxiliaryPosition;
- private int contentAreaIPD = 0;
+ private int contentAreaIPD;
/**
* @param node the fo this LM deals with
@@ -248,38 +244,27 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager
/** {@inheritDoc} */
public List getNextKnuthElements(LayoutContext context, int alignment) {
- //log.debug("BLM.getNextKnuthElements> keep-together = "
- // + layoutProps.keepTogether.getType());
- //log.debug(" keep-with-previous = " +
- // layoutProps.keepWithPrevious.getType());
- //log.debug(" keep-with-next = " +
- // layoutProps.keepWithNext.getType());
- BlockLevelLayoutManager curLM; // currently active LM
- BlockLevelLayoutManager prevLM = null; // previously active LM
-
referenceIPD = context.getRefIPD();
-
updateContentAreaIPDwithOverconstrainedAdjust();
- List returnedList = null;
List contentList = new LinkedList();
- List returnList = new LinkedList();
+ List elements = new LinkedList();
if (!breakBeforeServed) {
breakBeforeServed = true;
if (!context.suppressBreakBefore()) {
- if (addKnuthElementsForBreakBefore(returnList, context)) {
- return returnList;
+ if (addKnuthElementsForBreakBefore(elements, context)) {
+ return elements;
}
}
}
if (!firstVisibleMarkServed) {
- addKnuthElementsForSpaceBefore(returnList, alignment);
+ addKnuthElementsForSpaceBefore(elements, alignment);
context.updateKeepWithPreviousPending(getKeepWithPrevious());
}
- addKnuthElementsForBorderPaddingBefore(returnList, !firstVisibleMarkServed);
+ addKnuthElementsForBorderPaddingBefore(elements, !firstVisibleMarkServed);
firstVisibleMarkServed = true;
//Spaces, border and padding to be repeated at each break
@@ -288,142 +273,311 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager
//Used to indicate a special break-after case when all content has already been generated.
BreakElement forcedBreakAfterLast = null;
- while ((curLM = (BlockLevelLayoutManager) getChildLM()) != null) {
+ LayoutManager currentChildLM;
+ while ((currentChildLM = (LayoutManager) getChildLM()) != null) {
LayoutContext childLC = new LayoutContext(0);
- childLC.copyPendingMarksFrom(context);
- if (curLM instanceof LineLayoutManager) {
- // curLM is a LineLayoutManager
- // set stackLimit for lines (stack limit is now i-p-direction, not b-p-direction!)
- childLC.setStackLimitBP(context.getStackLimitBP());
- childLC.setStackLimitIP(new MinOptMax(getContentAreaIPD()));
- childLC.setRefIPD(getContentAreaIPD());
- } else {
- // curLM is a ?
- //childLC.setStackLimit(MinOptMax.subtract(context
- // .getStackLimit(), stackSize));
- childLC.setStackLimitBP(context.getStackLimitBP());
- childLC.setRefIPD(referenceIPD);
- }
- if (curLM == this.childLMs.get(0)) {
- childLC.setFlags(LayoutContext.SUPPRESS_BREAK_BEFORE);
- //Handled already by the parent (break collapsing, see above)
- }
- // get elements from curLM
- returnedList = curLM.getNextKnuthElements(childLC, alignment);
- if (contentList.isEmpty() && childLC.isKeepWithPreviousPending()) {
+ List childrenElements = getNextChildElements(currentChildLM, context, childLC,
+ alignment);
+
+ if (contentList.isEmpty()) {
//Propagate keep-with-previous up from the first child
context.updateKeepWithPreviousPending(childLC.getKeepWithPreviousPending());
- childLC.clearKeepWithPreviousPending();
}
- if (returnedList != null
- && returnedList.size() == 1
- && ((ListElement) returnedList.get(0)).isForcedBreak()) {
+ if (childrenElements != null && !childrenElements.isEmpty()) {
+ if (!contentList.isEmpty()
+ && !ElementListUtils.startsWithForcedBreak(childrenElements)) {
+ // there is a block handled by prevLM before the one
+ // handled by curLM, and the one handled
+ // by the current LM does not begin with a break
+ addInBetweenBreak(contentList, context, childLC);
+ }
+ if (childrenElements.size() == 1
+ && ElementListUtils.startsWithForcedBreak(childrenElements)) {
+
+ if (currentChildLM.isFinished() && !hasNextChildLM()) {
+ // a descendant of this block has break-before
+ forcedBreakAfterLast = (BreakElement) childrenElements.get(0);
+ context.clearPendingMarks();
+ break;
+ }
- if (curLM.isFinished() && !hasNextChildLM()) {
+ if (contentList.isEmpty()) {
+ // Empty fo:block, zero-length box makes sure the IDs and/or markers
+ // are registered and borders/padding are painted.
+ elements.add(new KnuthBox(0, notifyPos(new Position(this)), false));
+ }
// a descendant of this block has break-before
- forcedBreakAfterLast = (BreakElement) returnedList.get(0);
+ contentList.addAll(childrenElements);
+
+ wrapPositionElements(contentList, elements);
+
+ return elements;
+ } else {
+ contentList.addAll(childrenElements);
+ if (ElementListUtils.endsWithForcedBreak(childrenElements)) {
+ // a descendant of this block has break-after
+ if (currentChildLM.isFinished() && !hasNextChildLM()) {
+ forcedBreakAfterLast = (BreakElement) ListUtil.removeLast(contentList);
+ context.clearPendingMarks();
+ break;
+ }
+
+ wrapPositionElements(contentList, elements);
+
+ return elements;
+ }
+ }
+ context.updateKeepWithNextPending(childLC.getKeepWithNextPending());
+ }
+ }
+
+ if (!contentList.isEmpty()) {
+ wrapPositionElements(contentList, elements);
+ } else if (forcedBreakAfterLast == null) {
+ // Empty fo:block, zero-length box makes sure the IDs and/or markers
+ // are registered.
+ elements.add(new KnuthBox(0, notifyPos(new Position(this)), true));
+ }
+
+ addKnuthElementsForBorderPaddingAfter(elements, true);
+ addKnuthElementsForSpaceAfter(elements, alignment);
+
+ //All child content is processed. Only break-after can occur now, so...
+ context.clearPendingMarks();
+ if (forcedBreakAfterLast == null) {
+ addKnuthElementsForBreakAfter(elements, context);
+ } else {
+ forcedBreakAfterLast.clearPendingMarks();
+ elements.add(forcedBreakAfterLast);
+ }
+
+ context.updateKeepWithNextPending(getKeepWithNext());
+
+ setFinished(true);
+
+ return elements;
+ }
+
+ /** {@inheritDoc} */
+ public List getNextKnuthElements(LayoutContext context, int alignment, Stack lmStack,
+ Position restartPosition, LayoutManager restartAtLM) {
+ referenceIPD = context.getRefIPD();
+ updateContentAreaIPDwithOverconstrainedAdjust();
+
+ List contentList = new LinkedList();
+ List elements = new LinkedList();
+
+ if (!breakBeforeServed) {
+ breakBeforeServed = true;
+ if (!context.suppressBreakBefore()) {
+ if (addKnuthElementsForBreakBefore(elements, context)) {
+ return elements;
+ }
+ }
+ }
+
+ if (!firstVisibleMarkServed) {
+ addKnuthElementsForSpaceBefore(elements, alignment);
+ context.updateKeepWithPreviousPending(getKeepWithPrevious());
+ }
+
+ addKnuthElementsForBorderPaddingBefore(elements, !firstVisibleMarkServed);
+ firstVisibleMarkServed = true;
+
+ //Spaces, border and padding to be repeated at each break
+ addPendingMarks(context);
+
+ //Used to indicate a special break-after case when all content has already been generated.
+ BreakElement forcedBreakAfterLast = null;
+
+ LayoutContext childLC = new LayoutContext(0);
+ List childrenElements;
+ LayoutManager currentChildLM;
+ if (lmStack.isEmpty()) {
+ assert restartAtLM != null && restartAtLM.getParent() == this;
+ currentChildLM = restartAtLM;
+ currentChildLM.reset();
+ setCurrentChildLM(currentChildLM);
+
+ childrenElements = getNextChildElements(currentChildLM, context, childLC,
+ alignment);
+ } else {
+ currentChildLM = (BlockLevelLayoutManager) lmStack.pop();
+ setCurrentChildLM(currentChildLM);
+ childrenElements = getNextChildElements(currentChildLM, context, childLC, alignment,
+ lmStack, restartPosition, restartAtLM);
+ }
+
+ if (contentList.isEmpty()) {
+ //Propagate keep-with-previous up from the first child
+ context.updateKeepWithPreviousPending(childLC.getKeepWithPreviousPending());
+ }
+ if (childrenElements != null && !childrenElements.isEmpty()) {
+ if (!contentList.isEmpty()
+ && !ElementListUtils.startsWithForcedBreak(childrenElements)) {
+ // there is a block handled by prevLM before the one
+ // handled by curLM, and the one handled
+ // by the current LM does not begin with a break
+ addInBetweenBreak(contentList, context, childLC);
+ }
+ if (childrenElements.size() == 1
+ && ElementListUtils.startsWithForcedBreak(childrenElements)) {
+
+ if (currentChildLM.isFinished() && !hasNextChildLM()) {
+ // a descendant of this block has break-before
+ forcedBreakAfterLast = (BreakElement) childrenElements.get(0);
context.clearPendingMarks();
- break;
+// break; TODO
}
if (contentList.isEmpty()) {
// Empty fo:block, zero-length box makes sure the IDs and/or markers
// are registered and borders/padding are painted.
- returnList.add(new KnuthBox(0, notifyPos(new Position(this)), false));
+ elements.add(new KnuthBox(0, notifyPos(new Position(this)), false));
}
// a descendant of this block has break-before
- contentList.addAll(returnedList);
-
- /* extension: conversione di tutta la sequenza fin'ora ottenuta */
- if (bpUnit > 0) {
- storedList = contentList;
- contentList = createUnitElements(contentList);
- }
- /* end of extension */
+ contentList.addAll(childrenElements);
- // "wrap" the Position inside each element
- // moving the elements from contentList to returnList
- returnedList = new LinkedList();
- wrapPositionElements(contentList, returnList);
+ wrapPositionElements(contentList, elements);
- return returnList;
+ return elements;
} else {
- if (returnedList == null || returnedList.isEmpty()) {
- //Avoid NoSuchElementException below (happens with empty blocks)
- continue;
+ contentList.addAll(childrenElements);
+ if (ElementListUtils.endsWithForcedBreak(childrenElements)) {
+ // a descendant of this block has break-after
+ if (currentChildLM.isFinished() && !hasNextChildLM()) {
+ forcedBreakAfterLast = (BreakElement) ListUtil.removeLast(contentList);
+ context.clearPendingMarks();
+// break; TODO
+ }
+
+ wrapPositionElements(contentList, elements);
+
+ return elements;
}
- if (prevLM != null
- && !ElementListUtils.startsWithForcedBreak(returnedList)) {
+ }
+ context.updateKeepWithNextPending(childLC.getKeepWithNextPending());
+ }
+
+ while ((currentChildLM = (LayoutManager) getChildLM()) != null) {
+ currentChildLM.reset(); // TODO won't work with forced breaks
+
+ childLC = new LayoutContext(0);
+
+ childrenElements = getNextChildElements(currentChildLM, context, childLC,
+ alignment);
+
+ if (contentList.isEmpty()) {
+ //Propagate keep-with-previous up from the first child
+ context.updateKeepWithPreviousPending(childLC.getKeepWithPreviousPending());
+ }
+ if (childrenElements != null && !childrenElements.isEmpty()) {
+ if (!contentList.isEmpty()
+ && !ElementListUtils.startsWithForcedBreak(childrenElements)) {
// there is a block handled by prevLM before the one
// handled by curLM, and the one handled
// by the current LM does not begin with a break
addInBetweenBreak(contentList, context, childLC);
}
- contentList.addAll(returnedList);
- if (ElementListUtils.endsWithForcedBreak(returnedList)) {
- // a descendant of this block has break-after
- if (curLM.isFinished() && !hasNextChildLM()) {
- forcedBreakAfterLast = (BreakElement) ListUtil
- .removeLast(contentList);
+ if (childrenElements.size() == 1
+ && ElementListUtils.startsWithForcedBreak(childrenElements)) {
+
+ if (currentChildLM.isFinished() && !hasNextChildLM()) {
+ // a descendant of this block has break-before
+ forcedBreakAfterLast = (BreakElement) childrenElements.get(0);
context.clearPendingMarks();
break;
}
- /* extension: conversione di tutta la sequenza fin'ora ottenuta */
- if (bpUnit > 0) {
- storedList = contentList;
- contentList = createUnitElements(contentList);
+ if (contentList.isEmpty()) {
+ // Empty fo:block, zero-length box makes sure the IDs and/or markers
+ // are registered and borders/padding are painted.
+ elements.add(new KnuthBox(0, notifyPos(new Position(this)), false));
}
- /* end of extension */
+ // a descendant of this block has break-before
+ contentList.addAll(childrenElements);
- returnedList = new LinkedList();
- wrapPositionElements(contentList, returnList);
+ wrapPositionElements(contentList, elements);
- return returnList;
+ return elements;
+ } else {
+ contentList.addAll(childrenElements);
+ if (ElementListUtils.endsWithForcedBreak(childrenElements)) {
+ // a descendant of this block has break-after
+ if (currentChildLM.isFinished() && !hasNextChildLM()) {
+ forcedBreakAfterLast = (BreakElement) ListUtil.removeLast(contentList);
+ context.clearPendingMarks();
+ break;
+ }
+
+ wrapPositionElements(contentList, elements);
+
+ return elements;
+ }
}
+ context.updateKeepWithNextPending(childLC.getKeepWithNextPending());
}
- // propagate and clear
- context.updateKeepWithNextPending(childLC.getKeepWithNextPending());
- childLC.clearKeepsPending();
- prevLM = curLM;
- }
-
- /* Extension: conversione di tutta la sequenza fin'ora ottenuta */
- if (bpUnit > 0) {
- storedList = contentList;
- contentList = createUnitElements(contentList);
}
- /* end of extension */
- returnedList = new LinkedList();
if (!contentList.isEmpty()) {
- wrapPositionElements(contentList, returnList);
+ wrapPositionElements(contentList, elements);
} else if (forcedBreakAfterLast == null) {
// Empty fo:block, zero-length box makes sure the IDs and/or markers
// are registered.
- returnList.add(new KnuthBox(0, notifyPos(new Position(this)), true));
+ elements.add(new KnuthBox(0, notifyPos(new Position(this)), true));
}
- addKnuthElementsForBorderPaddingAfter(returnList, true);
- addKnuthElementsForSpaceAfter(returnList, alignment);
+ addKnuthElementsForBorderPaddingAfter(elements, true);
+ addKnuthElementsForSpaceAfter(elements, alignment);
//All child content is processed. Only break-after can occur now, so...
context.clearPendingMarks();
if (forcedBreakAfterLast == null) {
- addKnuthElementsForBreakAfter(returnList, context);
- }
-
- if (forcedBreakAfterLast != null) {
+ addKnuthElementsForBreakAfter(elements, context);
+ } else {
forcedBreakAfterLast.clearPendingMarks();
- returnList.add(forcedBreakAfterLast);
+ elements.add(forcedBreakAfterLast);
}
context.updateKeepWithNextPending(getKeepWithNext());
setFinished(true);
- return returnList;
+ return elements;
+ }
+
+ private List getNextChildElements(LayoutManager childLM, LayoutContext context,
+ LayoutContext childLC, int alignment) {
+ return getNextChildElements(childLM, context, childLC, alignment, null, null, null);
+ }
+
+ private List getNextChildElements(LayoutManager childLM, LayoutContext context,
+ LayoutContext childLC, int alignment, Stack lmStack, Position restartPosition,
+ LayoutManager restartAtLM) {
+ childLC.copyPendingMarksFrom(context);
+ childLC.setStackLimitBP(context.getStackLimitBP());
+ if (childLM instanceof LineLayoutManager) {
+ childLC.setRefIPD(getContentAreaIPD());
+ } else {
+ childLC.setRefIPD(referenceIPD);
+ }
+ if (childLM == this.childLMs.get(0)) {
+ childLC.setFlags(LayoutContext.SUPPRESS_BREAK_BEFORE);
+ //Handled already by the parent (break collapsing, see above)
+ }
+
+ if (lmStack == null) {
+ return childLM.getNextKnuthElements(childLC, alignment);
+ } else {
+ if (childLM instanceof LineLayoutManager) {
+ return ((LineLayoutManager) childLM).getNextKnuthElements(childLC, alignment,
+ (LeafPosition) restartPosition);
+ } else {
+ return childLM.getNextKnuthElements(childLC, alignment,
+ lmStack, restartPosition, restartAtLM);
+ }
+ }
}
/**
@@ -1654,5 +1808,13 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager
return -1;
}
+ /** {@inheritDoc} */
+ public void reset() {
+ super.reset();
+ breakBeforeServed = false;
+ firstVisibleMarkServed = false;
+ // TODO startIndent, endIndent
+ }
+
}
diff --git a/src/java/org/apache/fop/layoutmgr/BreakingAlgorithm.java b/src/java/org/apache/fop/layoutmgr/BreakingAlgorithm.java
index c6bd7bcec..3a688cce8 100644
--- a/src/java/org/apache/fop/layoutmgr/BreakingAlgorithm.java
+++ b/src/java/org/apache/fop/layoutmgr/BreakingAlgorithm.java
@@ -491,6 +491,9 @@ public abstract class BreakingAlgorithm {
elementIndex, previousIsBox, allowedBreaks).isBox();
if (activeNodeCount == 0) {
+ if (ipdChanged()) {
+ return handleIpdChange();
+ }
if (!force) {
log.debug("Could not find a set of breaking points " + threshold);
return 0;
@@ -535,6 +538,14 @@ public abstract class BreakingAlgorithm {
return line;
}
+ protected boolean ipdChanged() {
+ return false;
+ }
+
+ protected int handleIpdChange() {
+ throw new IllegalStateException();
+ }
+
/**
* Recover from a {@link KnuthNode} leading to a line that is too long.
* The default implementation creates a new node corresponding to a break
@@ -1283,12 +1294,8 @@ public abstract class BreakingAlgorithm {
* @return the width/length in millipoints
*/
protected int getLineWidth(int line) {
- if (this.lineWidth < 0) {
- throw new IllegalStateException("lineWidth must be set"
- + (this.lineWidth != 0 ? " and positive, but it is: " + this.lineWidth : ""));
- } else {
- return this.lineWidth;
- }
+ assert lineWidth >= 0;
+ return this.lineWidth;
}
/** @return the constant line/part width or -1 if there is no such value */
@@ -1321,7 +1328,7 @@ public abstract class BreakingAlgorithm {
* @param par the corresponding paragraph
* @param total the number of lines into which the paragraph will be broken
*/
- private void calculateBreakPoints(KnuthNode node, KnuthSequence par,
+ protected void calculateBreakPoints(KnuthNode node, KnuthSequence par,
int total) {
KnuthNode bestActiveNode = node;
// use bestActiveNode to determine the optimum breakpoints
diff --git a/src/java/org/apache/fop/layoutmgr/FlowLayoutManager.java b/src/java/org/apache/fop/layoutmgr/FlowLayoutManager.java
index 5a80c3318..67b9b4254 100644
--- a/src/java/org/apache/fop/layoutmgr/FlowLayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/FlowLayoutManager.java
@@ -22,6 +22,7 @@ package org.apache.fop.layoutmgr;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
+import java.util.Stack;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -29,8 +30,6 @@ import org.apache.commons.logging.LogFactory;
import org.apache.fop.area.Area;
import org.apache.fop.area.BlockParent;
import org.apache.fop.fo.pagination.Flow;
-import org.apache.fop.layoutmgr.inline.InlineLevelLayoutManager;
-import org.apache.fop.layoutmgr.inline.WrapperLayoutManager;
/**
* LayoutManager for an fo:flow object.
@@ -64,108 +63,151 @@ public class FlowLayoutManager extends BlockStackingLayoutManager
/** {@inheritDoc} */
public List getNextKnuthElements(LayoutContext context, int alignment) {
- // set layout dimensions
- int flowIPD = getCurrentPV().getCurrentSpan().getColumnWidth();
- int flowBPD = getCurrentPV().getBodyRegion().getBPD();
+ List elements = new LinkedList();
- // currently active LM
- LayoutManager curLM;
- List returnedList;
- List returnList = new LinkedList();
-
- while ((curLM = getChildLM()) != null) {
- if (!(curLM instanceof WrapperLayoutManager)
- && curLM instanceof InlineLevelLayoutManager) {
- log.error("inline area not allowed under flow - ignoring");
- curLM.setFinished(true);
- continue;
+ LayoutManager currentChildLM;
+ while ((currentChildLM = getChildLM()) != null) {
+ if (addChildElements(elements, currentChildLM, context, alignment) != null) {
+ return elements;
}
+ }
+
+ SpaceResolver.resolveElementList(elements);
+ setFinished(true);
+
+ assert !elements.isEmpty();
+ return elements;
+ }
+
+ /** {@inheritDoc} */
+ public List getNextKnuthElements(LayoutContext context, int alignment,
+ Position positionAtIPDChange, LayoutManager restartAtLM) {
+
+ List elements = new LinkedList();
- int span = EN_NONE;
- int disableColumnBalancing = EN_FALSE;
- if (curLM instanceof BlockLayoutManager) {
- span = ((BlockLayoutManager)curLM).getBlockFO().getSpan();
- disableColumnBalancing = ((BlockLayoutManager) curLM).getBlockFO()
- .getDisableColumnBalancing();
- } else if (curLM instanceof BlockContainerLayoutManager) {
- span = ((BlockContainerLayoutManager)curLM).getBlockContainerFO().getSpan();
- disableColumnBalancing = ((BlockContainerLayoutManager) curLM).getBlockContainerFO()
- .getDisableColumnBalancing();
+ LayoutManager currentChildLM = positionAtIPDChange.getLM();
+ if (currentChildLM == null) {
+ throw new IllegalStateException(
+ "Cannot find layout manager from where to re-start layout after IPD change");
+ }
+ if (restartAtLM != null && restartAtLM.getParent() == this) {
+ currentChildLM = restartAtLM;
+ setCurrentChildLM(currentChildLM);
+ currentChildLM.reset();
+ if (addChildElements(elements, currentChildLM, context, alignment) != null) {
+ return elements;
+ }
+ } else {
+ Stack lmStack = new Stack();
+ while (currentChildLM.getParent() != this) {
+ lmStack.push(currentChildLM);
+ currentChildLM = currentChildLM.getParent();
}
+ setCurrentChildLM(currentChildLM);
+ if (addChildElements(elements, currentChildLM, context, alignment, lmStack,
+ positionAtIPDChange, restartAtLM) != null) {
+ return elements;
+ }
+ }
- int currentSpan = context.getCurrentSpan();
- if (currentSpan != span) {
- if (span == EN_ALL) {
- context.setDisableColumnBalancing(disableColumnBalancing);
- }
- log.debug("span change from " + currentSpan + " to " + span);
- context.signalSpanChange(span);
- SpaceResolver.resolveElementList(returnList);
- return returnList;
+ while ((currentChildLM = getChildLM()) != null) {
+ currentChildLM.reset(); // TODO won't work with forced breaks
+ if (addChildElements(elements, currentChildLM, context, alignment) != null) {
+ return elements;
}
+ }
- // Set up a LayoutContext
- //MinOptMax bpd = context.getStackLimit();
+ SpaceResolver.resolveElementList(elements);
+ setFinished(true);
- LayoutContext childLC = new LayoutContext(0);
- childLC.setStackLimitBP(context.getStackLimitBP());
- childLC.setRefIPD(context.getRefIPD());
- childLC.setWritingMode(getCurrentPage().getSimplePageMaster().getWritingMode());
+ assert !elements.isEmpty();
+ return elements;
+ }
- // get elements from curLM
- returnedList = curLM.getNextKnuthElements(childLC, alignment);
- //log.debug("FLM.getNextKnuthElements> returnedList.size() = " + returnedList.size());
- if (returnList.size() == 0 && childLC.isKeepWithPreviousPending()) {
- context.updateKeepWithPreviousPending(childLC.getKeepWithPreviousPending());
- childLC.clearKeepWithPreviousPending();
- }
+ private List addChildElements(List elements, LayoutManager childLM, LayoutContext context,
+ int alignment) {
+ return addChildElements(elements, childLM, context, alignment, null, null, null);
+ }
- // "wrap" the Position inside each element
- List tempList = returnedList;
- returnedList = new LinkedList();
- wrapPositionElements(tempList, returnedList);
-
- if (returnedList.size() == 1
- && ElementListUtils.endsWithForcedBreak(returnedList)) {
- // a descendant of this flow has break-before
- returnList.addAll(returnedList);
- SpaceResolver.resolveElementList(returnList);
- return returnList;
- } else if (returnedList.size() > 0) {
- if (returnList.size() > 0
- && !ElementListUtils.startsWithForcedBreak(returnedList)) {
- addInBetweenBreak(returnList, context, childLC);
- }
- returnList.addAll(returnedList);
- if (ElementListUtils.endsWithForcedBreak(returnList)) {
- if (curLM.isFinished() && !hasNextChildLM()) {
- //If the layout manager is finished at this point, the pending
- //marks become irrelevant.
- childLC.clearPendingMarks();
- //setFinished(true);
- break;
- }
- // a descendant of this flow has break-after
- SpaceResolver.resolveElementList(returnList);
- return returnList;
- }
+ private List addChildElements(List elements, LayoutManager childLM, LayoutContext context,
+ int alignment, Stack lmStack, Position position, LayoutManager restartAtLM) {
+ if (handleSpanChange(childLM, elements, context)) {
+ SpaceResolver.resolveElementList(elements);
+ return elements;
+ }
+
+ LayoutContext childLC = new LayoutContext(0);
+ List childrenElements = getNextChildElements(childLM, context, childLC, alignment, lmStack,
+ position, restartAtLM);
+ if (elements.isEmpty()) {
+ context.updateKeepWithPreviousPending(childLC.getKeepWithPreviousPending());
+ }
+ if (!elements.isEmpty()
+ && !ElementListUtils.startsWithForcedBreak(childrenElements)) {
+ addInBetweenBreak(elements, context, childLC);
+ }
+ context.updateKeepWithNextPending(childLC.getKeepWithNextPending());
+
+ elements.addAll(childrenElements);
+
+ if (ElementListUtils.endsWithForcedBreak(elements)) {
+ // a descendant of this flow has break-before or break-after
+ if (childLM.isFinished() && !hasNextChildLM()) {
+ setFinished(true);
}
+ SpaceResolver.resolveElementList(elements);
+ return elements;
+ }
+ return null;
+ }
- //Propagate and clear
- context.updateKeepWithNextPending(childLC.getKeepWithNextPending());
- childLC.clearKeepWithNextPending();
+ private boolean handleSpanChange(LayoutManager childLM, List elements, LayoutContext context) {
+ int span = EN_NONE;
+ int disableColumnBalancing = EN_FALSE;
+ if (childLM instanceof BlockLayoutManager) {
+ span = ((BlockLayoutManager)childLM).getBlockFO().getSpan();
+ disableColumnBalancing = ((BlockLayoutManager) childLM).getBlockFO()
+ .getDisableColumnBalancing();
+ } else if (childLM instanceof BlockContainerLayoutManager) {
+ span = ((BlockContainerLayoutManager)childLM).getBlockContainerFO().getSpan();
+ disableColumnBalancing = ((BlockContainerLayoutManager) childLM).getBlockContainerFO()
+ .getDisableColumnBalancing();
+ }
- context.updateKeepWithNextPending(getKeepWithNext());
+ int currentSpan = context.getCurrentSpan();
+ if (currentSpan != span) {
+ if (span == EN_ALL) {
+ context.setDisableColumnBalancing(disableColumnBalancing);
+ }
+ log.debug("span change from " + currentSpan + " to " + span);
+ context.signalSpanChange(span);
+ return true;
+ } else {
+ return false;
}
+ }
- SpaceResolver.resolveElementList(returnList);
- setFinished(true);
+ private List getNextChildElements(LayoutManager childLM, LayoutContext context,
+ LayoutContext childLC, int alignment, Stack lmStack, Position restartPosition,
+ LayoutManager restartLM) {
+ childLC.setStackLimitBP(context.getStackLimitBP());
+ childLC.setRefIPD(context.getRefIPD());
+ childLC.setWritingMode(getCurrentPage().getSimplePageMaster().getWritingMode());
- if (returnList.size() > 0) {
- return returnList;
+ List childrenElements;
+ if (lmStack == null) {
+ childrenElements = childLM.getNextKnuthElements(childLC, alignment);
} else {
- return null;
+ childrenElements = childLM.getNextKnuthElements(childLC,
+ alignment, lmStack, restartPosition, restartLM);
}
+ assert !childrenElements.isEmpty();
+
+ // "wrap" the Position inside each element
+ List tempList = childrenElements;
+ childrenElements = new LinkedList();
+ wrapPositionElements(tempList, childrenElements);
+ return childrenElements;
}
/**
@@ -353,5 +395,10 @@ public class FlowLayoutManager extends BlockStackingLayoutManager
return getCurrentPV().getBodyRegion().getBPD();
}
+ /** {@inheritDoc} */
+ public boolean isRestartable() {
+ return true;
+ }
+
}
diff --git a/src/java/org/apache/fop/layoutmgr/InlineKnuthSequence.java b/src/java/org/apache/fop/layoutmgr/InlineKnuthSequence.java
index 6d11a3c24..104c71131 100644
--- a/src/java/org/apache/fop/layoutmgr/InlineKnuthSequence.java
+++ b/src/java/org/apache/fop/layoutmgr/InlineKnuthSequence.java
@@ -57,16 +57,12 @@ public class InlineKnuthSequence extends KnuthSequence {
return true;
}
- /* (non-Javadoc)
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
public boolean canAppendSequence(KnuthSequence sequence) {
return sequence.isInlineSequence() && !isClosed;
}
- /* (non-Javadoc)
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
public boolean appendSequence(KnuthSequence sequence) {
if (!canAppendSequence(sequence)) {
return false;
@@ -83,18 +79,14 @@ public class InlineKnuthSequence extends KnuthSequence {
return true;
}
- /* (non-Javadoc)
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
public boolean appendSequence(KnuthSequence sequence, boolean keepTogether,
BreakElement breakElement) {
return appendSequence(sequence);
}
- /* (non-Javadoc)
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
public KnuthSequence endSequence() {
if (!isClosed) {
add(new KnuthPenalty(0, -KnuthElement.INFINITE, false, null, false));
diff --git a/src/java/org/apache/fop/layoutmgr/LayoutContext.java b/src/java/org/apache/fop/layoutmgr/LayoutContext.java
index 41d4c5cfc..81726e57b 100644
--- a/src/java/org/apache/fop/layoutmgr/LayoutContext.java
+++ b/src/java/org/apache/fop/layoutmgr/LayoutContext.java
@@ -78,15 +78,6 @@ public class LayoutContext {
* level LM to allow them to optimize returned break possibilities.
*/
private MinOptMax stackLimitBP;
- /**
- * Total available stacking dimension for a "galley-level" layout
- * manager in inline-progression-direction. It is passed by the
- * parent LM. For LineLM, the block LM determines this based on
- * indent properties.
- * These LM <b>may</b> wish to pass this information down to lower
- * level LM to allow them to optimize returned break possibilities.
- */
- private MinOptMax stackLimitIP;
/** to keep track of spanning in multi-column layout */
private int currentSpan = Constants.NOT_SET;
@@ -158,7 +149,7 @@ public class LayoutContext {
this.flags = parentLC.flags;
this.refIPD = parentLC.refIPD;
this.writingMode = parentLC.writingMode;
- setStackLimitsFrom(parentLC);
+ setStackLimitBP(parentLC.getStackLimitBP());
this.leadingSpace = parentLC.leadingSpace; //???
this.trailingSpace = parentLC.trailingSpace; //???
this.hyphContext = parentLC.hyphContext;
@@ -183,7 +174,6 @@ public class LayoutContext {
this.flags = flags;
this.refIPD = 0;
stackLimitBP = new MinOptMax(0);
- stackLimitIP = new MinOptMax(0);
leadingSpace = null;
trailingSpace = null;
}
@@ -398,31 +388,6 @@ public class LayoutContext {
}
/**
- * Sets the stack limit in inline-progression-dimension.
- * @param limit the stack limit
- */
- public void setStackLimitIP(MinOptMax limit) {
- stackLimitIP = limit;
- }
-
- /**
- * Returns the stack limit in inline-progression-dimension.
- * @return the stack limit
- */
- public MinOptMax getStackLimitIP() {
- return stackLimitIP;
- }
-
- /**
- * Sets (Copies) the stack limits in both directions from another layout context.
- * @param context the layout context to take the values from
- */
- public void setStackLimitsFrom(LayoutContext context) {
- setStackLimitBP(context.getStackLimitBP());
- setStackLimitIP(context.getStackLimitIP());
- }
-
- /**
* Sets the inline-progression-dimension of the nearest ancestor reference area.
*/
public void setRefIPD(int ipd) {
@@ -662,8 +627,6 @@ public class LayoutContext {
return "Layout Context:"
+ "\nStack Limit BPD: \t"
+ (getStackLimitBP() == null ? "null" : getStackLimitBP().toString())
- + "\nStack Limit IPD: \t"
- + (getStackLimitIP() == null ? "null" : getStackLimitIP().toString())
+ "\nTrailing Space: \t"
+ (getTrailingSpace() == null ? "null" : getTrailingSpace().toString())
+ "\nLeading Space: \t"
diff --git a/src/java/org/apache/fop/layoutmgr/LayoutManager.java b/src/java/org/apache/fop/layoutmgr/LayoutManager.java
index f19588a77..454b8b366 100644
--- a/src/java/org/apache/fop/layoutmgr/LayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/LayoutManager.java
@@ -20,6 +20,7 @@
package org.apache.fop.layoutmgr;
import java.util.List;
+import java.util.Stack;
import org.apache.fop.area.Area;
import org.apache.fop.datatypes.PercentBaseContext;
@@ -219,4 +220,36 @@ public interface LayoutManager extends PercentBaseContext {
* @return the same Position but with a position index
*/
Position notifyPos(Position pos);
+
+ /**
+ * Re-initializes this layout manager in order to re-generate its Knuth
+ * elements according to a new IPD value.
+ */
+ void reset();
+
+ /**
+ * Returns {@code true} if this layout manager is able to re-generate its
+ * Knuth elements after an IPD change.
+ *
+ * @return {@code true} if this layout manager can be restarted after an IPD
+ * change
+ */
+ boolean isRestartable();
+
+ /**
+ * Returns an updated list of Knuth elements corresponding to this layout
+ * manager, after a change of IPD has been detected.
+ *
+ * @param context the layout context
+ * @param alignment the alignment
+ * @param lmStack the stack of LMs that are active at the IPD change
+ * @param positionAtIPDChange the position corresponding to the element
+ * finishing the page before the IPD change
+ * @param restartAtLM if not null, the layout manager from which to restart.
+ * That is, the IPD change occurs between two block elements and not inside
+ * a paragraph
+ * @return an updated list of elements, taking the new IPD into account
+ */
+ List getNextKnuthElements(LayoutContext context, int alignment, Stack lmStack,
+ Position positionAtIPDChange, LayoutManager restartAtLM);
}
diff --git a/src/java/org/apache/fop/layoutmgr/LeafPosition.java b/src/java/org/apache/fop/layoutmgr/LeafPosition.java
index ed8cc94e2..8b2a5f4bc 100644
--- a/src/java/org/apache/fop/layoutmgr/LeafPosition.java
+++ b/src/java/org/apache/fop/layoutmgr/LeafPosition.java
@@ -21,15 +21,20 @@ package org.apache.fop.layoutmgr;
public class LeafPosition extends Position {
- private int iLeafPos;
+ private int leafPos;
public LeafPosition(LayoutManager lm, int pos) {
super(lm);
- iLeafPos = pos;
+ leafPos = pos;
+ }
+
+ public LeafPosition(LayoutManager layoutManager, int pos, int index) {
+ super(layoutManager, index);
+ leafPos = pos;
}
public int getLeafPos() {
- return iLeafPos;
+ return leafPos;
}
public boolean generatesAreas() {
diff --git a/src/java/org/apache/fop/layoutmgr/PageBreaker.java b/src/java/org/apache/fop/layoutmgr/PageBreaker.java
index ed0b37602..86c3fccf8 100644
--- a/src/java/org/apache/fop/layoutmgr/PageBreaker.java
+++ b/src/java/org/apache/fop/layoutmgr/PageBreaker.java
@@ -77,6 +77,14 @@ public class PageBreaker extends AbstractBreaker {
return pslm.getPageProvider();
}
+ /**
+ * Starts the page breaking process.
+ * @param flowBPD the constant available block-progression-dimension (used for every part)
+ */
+ void doLayout(int flowBPD) {
+ doLayout(flowBPD, false);
+ }
+
/** {@inheritDoc} */
protected PageBreakingLayoutListener createLayoutListener() {
return new PageBreakingLayoutListener() {
@@ -121,6 +129,12 @@ public class PageBreaker extends AbstractBreaker {
/** {@inheritDoc} */
protected int getNextBlockList(LayoutContext childLC,
int nextSequenceStartsOn) {
+ return getNextBlockList(childLC, nextSequenceStartsOn, null, null, null);
+ }
+
+ /** {@inheritDoc} */
+ protected int getNextBlockList(LayoutContext childLC, int nextSequenceStartsOn,
+ Position positionAtIPDChange, LayoutManager restartLM, List firstElements) {
if (!firstPart) {
// if this is the first page that will be created by
// the current BlockSequence, it could have a break
@@ -132,7 +146,8 @@ public class PageBreaker extends AbstractBreaker {
pageBreakHandled = true;
pageProvider.setStartOfNextElementList(pslm.getCurrentPageNum(),
pslm.getCurrentPV().getCurrentSpan().getCurrentFlowIndex());
- return super.getNextBlockList(childLC, nextSequenceStartsOn);
+ return super.getNextBlockList(childLC, nextSequenceStartsOn, positionAtIPDChange,
+ restartLM, firstElements);
}
private boolean containsFootnotes(List contentList, LayoutContext context) {
@@ -209,6 +224,24 @@ public class PageBreaker extends AbstractBreaker {
return contentList;
}
+ /** {@inheritDoc} */
+ protected List getNextKnuthElements(LayoutContext context, int alignment,
+ Position positionAtIPDChange, LayoutManager restartAtLM) {
+ List contentList = null;
+
+ do {
+ contentList = childFLM.getNextKnuthElements(context, alignment, positionAtIPDChange,
+ restartAtLM);
+ } while (!childFLM.isFinished() && contentList == null);
+
+ // scan contentList, searching for footnotes
+ if (containsFootnotes(contentList, context)) {
+ // handle the footnote separator
+ handleFootnoteSeparator();
+ }
+ return contentList;
+ }
+
/**
* @return current display alignment
*/
diff --git a/src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java b/src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java
index fc0226cec..52238e9be 100644
--- a/src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java
+++ b/src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java
@@ -96,6 +96,9 @@ class PageBreakingAlgorithm extends BreakingAlgorithm {
//Controls whether a single part should be forced if possible (ex. block-container)
private boolean favorSinglePart = false;
+ private boolean ipdChange;
+ private KnuthNode bestNodeForIPDChange;
+
//Used to keep track of switches in keep-context
private int currentKeepContext = Constants.EN_AUTO;
private KnuthNode lastBeforeKeepContextSwitch;
@@ -1073,4 +1076,63 @@ class PageBreakingAlgorithm extends BreakingAlgorithm {
}
+ /** {@inheritDoc} */
+ protected boolean ipdChanged() {
+ return ipdChange;
+ }
+
+ /** {@inheritDoc} */
+ protected int handleIpdChange() {
+ log.trace("Best node for ipd change:" + bestNodeForIPDChange);
+ // TODO finish()
+ /*
+ * The third parameter is used to determine if this is the last page, so
+ * if the content must be vertically justified or not. If we are here
+ * this means that there is further content and the next page has a
+ * different ipd. So tweak the parameter to fall into the non-last-page
+ * case.
+ */
+ calculateBreakPoints(bestNodeForIPDChange, par, bestNodeForIPDChange.line + 1);
+ activeLines = null;
+ return bestNodeForIPDChange.line;
+ }
+
+ /**
+ * Add a node at the end of the given line's existing active nodes.
+ * If this is the first node in the line, adjust endLine accordingly.
+ * @param line number of the line ending at the node's corresponding breakpoint
+ * @param node the active node to add
+ */
+ protected void addNode(int line, KnuthNode node) {
+ if (node.position < par.size() - 1 && line > 0 && ipdChange(line - 1)) {
+ log.trace("IPD changes at page " + line);
+ ipdChange = true;
+ if (bestNodeForIPDChange == null
+ || node.totalDemerits < bestNodeForIPDChange.totalDemerits) {
+ bestNodeForIPDChange = node;
+ }
+ } else {
+ if (node.position == par.size() - 1) {
+ /*
+ * The whole sequence could actually fit on the last page before
+ * the IPD change. No need to do any special handling.
+ */
+ ipdChange = false;
+ }
+ super.addNode(line, node);
+ }
+ }
+
+ KnuthNode getBestNodeBeforeIPDChange() {
+ return bestNodeForIPDChange;
+ }
+
+ /** {@inheritDoc} */
+ protected boolean ipdChange(int line) {
+ if (pageProvider == null) {
+ return false;
+ }
+ return pageProvider.ipdChange(line);
+ }
+
}
diff --git a/src/java/org/apache/fop/layoutmgr/PageProvider.java b/src/java/org/apache/fop/layoutmgr/PageProvider.java
index c03aea091..bd556366a 100644
--- a/src/java/org/apache/fop/layoutmgr/PageProvider.java
+++ b/src/java/org/apache/fop/layoutmgr/PageProvider.java
@@ -161,6 +161,33 @@ public class PageProvider implements Constants {
}
/**
+ * Returns true if the part following the given one has a different IPD.
+ *
+ * @param index index of the current part
+ * @return true if the following part has a different IPD, false otherwise
+ */
+ public boolean ipdChange(int index) {
+ int columnCount = 0;
+ int colIndex = startColumnOfCurrentElementList + index;
+ int pageIndex = -1;
+ Page page;
+ do {
+ colIndex -= columnCount;
+ pageIndex++;
+ page = getPage(false, pageIndex, RELTO_CURRENT_ELEMENT_LIST);
+ columnCount = page.getPageViewport().getCurrentSpan().getColumnCount();
+ } while (colIndex >= columnCount);
+ if (colIndex + 1 < columnCount) {
+ // Next part is a column on same page => same IPD
+ return false;
+ } else {
+ Page nextPage = getPage(false, pageIndex + 1, RELTO_CURRENT_ELEMENT_LIST);
+ return page.getPageViewport().getBodyRegion().getIPD()
+ != nextPage.getPageViewport().getBodyRegion().getIPD();
+ }
+ }
+
+ /**
* Checks if a break at the passed index would start a new page
* @param index the index of the element before the break
* @return {@code true} if the break starts a new page
diff --git a/src/java/org/apache/fop/layoutmgr/Position.java b/src/java/org/apache/fop/layoutmgr/Position.java
index 42034cab4..10ad5878e 100644
--- a/src/java/org/apache/fop/layoutmgr/Position.java
+++ b/src/java/org/apache/fop/layoutmgr/Position.java
@@ -28,6 +28,11 @@ public class Position {
layoutManager = lm;
}
+ public Position(LayoutManager lm, int index) {
+ this(lm);
+ setIndex(index);
+ }
+
public LayoutManager getLM() {
return layoutManager;
}
diff --git a/src/java/org/apache/fop/layoutmgr/SpaceResolver.java b/src/java/org/apache/fop/layoutmgr/SpaceResolver.java
index 416ee924d..ff464ce6a 100644
--- a/src/java/org/apache/fop/layoutmgr/SpaceResolver.java
+++ b/src/java/org/apache/fop/layoutmgr/SpaceResolver.java
@@ -19,7 +19,6 @@
package org.apache.fop.layoutmgr;
-import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
@@ -565,6 +564,11 @@ public class SpaceResolver {
public Position getOriginalBreakPosition() {
return this.originalPosition;
}
+
+ public Position getPosition() {
+ return originalPosition;
+ }
+
}
/**
diff --git a/src/java/org/apache/fop/layoutmgr/StaticContentLayoutManager.java b/src/java/org/apache/fop/layoutmgr/StaticContentLayoutManager.java
index 4bfbd46f5..d5949f4a2 100644
--- a/src/java/org/apache/fop/layoutmgr/StaticContentLayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/StaticContentLayoutManager.java
@@ -21,10 +21,6 @@ package org.apache.fop.layoutmgr;
import java.util.LinkedList;
import java.util.List;
-import java.util.ListIterator;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
import org.apache.fop.area.Area;
import org.apache.fop.area.Block;
@@ -35,10 +31,7 @@ import org.apache.fop.fo.pagination.PageSequence;
import org.apache.fop.fo.pagination.SideRegion;
import org.apache.fop.fo.pagination.StaticContent;
import org.apache.fop.layoutmgr.PageBreakingAlgorithm.PageBreakingLayoutListener;
-import org.apache.fop.layoutmgr.inline.InlineLevelLayoutManager;
import org.apache.fop.layoutmgr.inline.TextLayoutManager;
-import org.apache.fop.traits.MinOptMax;
-import org.apache.fop.util.ListUtil;
/**
* LayoutManager for an fo:flow object.
@@ -48,11 +41,6 @@ import org.apache.fop.util.ListUtil;
*/
public class StaticContentLayoutManager extends BlockStackingLayoutManager {
- /**
- * logging instance
- */
- private static Log log = LogFactory.getLog(StaticContentLayoutManager.class);
-
private RegionReference targetRegion;
private Block targetBlock;
private SideRegion regionFO;
@@ -89,96 +77,7 @@ public class StaticContentLayoutManager extends BlockStackingLayoutManager {
/** {@inheritDoc} */
public List getNextKnuthElements(LayoutContext context, int alignment) {
- if (true) {
- throw new UnsupportedOperationException(
- "Shouldn't this method be emptied because it's never called at all?");
- }
- //TODO Empty this method?!?
- // set layout dimensions
- setContentAreaIPD(context.getRefIPD());
- setContentAreaBPD(context.getStackLimitBP().opt);
-
- //TODO Copied from elsewhere. May be worthwhile to factor out the common parts.
- // currently active LM
- BlockLevelLayoutManager curLM;
- BlockLevelLayoutManager prevLM = null;
- MinOptMax stackSize = new MinOptMax();
- List returnedList;
- List returnList = new LinkedList();
-
- while ((curLM = ((BlockLevelLayoutManager) getChildLM())) != null) {
- if (curLM instanceof InlineLevelLayoutManager) {
- log.error("inline area not allowed under flow - ignoring");
- curLM.setFinished(true);
- continue;
- }
-
- // Set up a LayoutContext
- MinOptMax bpd = context.getStackLimitBP();
-
- LayoutContext childLC = new LayoutContext(0);
- childLC.setStackLimitBP(MinOptMax.subtract(bpd, stackSize));
- childLC.setRefIPD(context.getRefIPD());
-
- // get elements from curLM
- returnedList = curLM.getNextKnuthElements(childLC, alignment);
- //log.debug("FLM.getNextKnuthElements> returnedList.size() = "
- // + returnedList.size());
-
- // "wrap" the Position inside each element
- List tempList = returnedList;
- KnuthElement tempElement;
- returnedList = new LinkedList();
- ListIterator listIter = tempList.listIterator();
- while (listIter.hasNext()) {
- tempElement = (KnuthElement)listIter.next();
- tempElement.setPosition(new NonLeafPosition(this, tempElement.getPosition()));
- returnedList.add(tempElement);
- }
-
- if (returnedList.size() == 1
- && ((KnuthElement)returnedList.get(0)).isPenalty()
- && ((KnuthPenalty)returnedList.get(0)).getP() == -KnuthElement.INFINITE) {
- // a descendant of this flow has break-before
- returnList.addAll(returnedList);
- return returnList;
- } else {
- if (!returnList.isEmpty()) {
- // there is a block before this one
- if (prevLM.mustKeepWithNext()
- || curLM.mustKeepWithPrevious()) {
- // add an infinite penalty to forbid a break between blocks
- returnList.add(new KnuthPenalty(0,
- KnuthElement.INFINITE, false,
- new Position(this), false));
- } else if (!((KnuthElement) ListUtil.getLast(returnList))
- .isGlue()) {
- // add a null penalty to allow a break between blocks
- returnList.add(new KnuthPenalty(0, 0, false, new Position(this), false));
- }
- }
-/*LF*/ if (!returnedList.isEmpty()) { // controllare!
- returnList.addAll(returnedList);
- final KnuthElement last = (KnuthElement) ListUtil
- .getLast(returnedList);
- if (last.isPenalty()
- && ((KnuthPenalty) last).getP() == -KnuthElement.INFINITE) {
- // a descendant of this flow has break-after
-/*LF*/ //log.debug("FLM - break after!!");
- return returnList;
- }
-/*LF*/ }
- }
- prevLM = curLM;
- }
-
- setFinished(true);
-
- if (returnList.isEmpty()) {
- return null;
- } else {
- return returnList;
- }
+ throw new IllegalStateException();
}
/**
diff --git a/src/java/org/apache/fop/layoutmgr/inline/ContentLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/ContentLayoutManager.java
index a5247d652..95f798161 100644
--- a/src/java/org/apache/fop/layoutmgr/inline/ContentLayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/inline/ContentLayoutManager.java
@@ -27,6 +27,7 @@ import java.util.ListIterator;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+
import org.apache.fop.area.Area;
import org.apache.fop.area.Block;
import org.apache.fop.area.LineArea;
@@ -43,7 +44,6 @@ import org.apache.fop.layoutmgr.PageSequenceLayoutManager;
import org.apache.fop.layoutmgr.Position;
import org.apache.fop.layoutmgr.PositionIterator;
import org.apache.fop.layoutmgr.SpaceSpecifier;
-import org.apache.fop.traits.MinOptMax;
/**
* Content Layout Manager.
@@ -111,8 +111,6 @@ public class ContentLayoutManager extends AbstractBaseLayoutManager
LayoutContext childLC = new LayoutContext(LayoutContext.NEW_AREA);
childLC.setLeadingSpace(new SpaceSpecifier(false));
childLC.setTrailingSpace(new SpaceSpecifier(false));
- // set stackLimit for lines
- childLC.setStackLimitIP(new MinOptMax(ipd));
childLC.setRefIPD(ipd);
int lineHeight = 14000;
@@ -129,8 +127,7 @@ public class ContentLayoutManager extends AbstractBaseLayoutManager
stackSize = 0;
- List contentList =
- getNextKnuthElements(childLC, Constants.EN_START);
+ List contentList = getNextKnuthElements(childLC, Constants.EN_START);
ListIterator contentIter = contentList.listIterator();
while (contentIter.hasNext()) {
KnuthElement element = (KnuthElement) contentIter.next();
@@ -149,8 +146,7 @@ public class ContentLayoutManager extends AbstractBaseLayoutManager
lc.setFlags(LayoutContext.RESOLVE_LEADING_SPACE, true);
lc.setLeadingSpace(new SpaceSpecifier(false));
lc.setTrailingSpace(new SpaceSpecifier(false));
- KnuthPossPosIter contentPosIter =
- new KnuthPossPosIter(contentList, 0, contentList.size());
+ KnuthPossPosIter contentPosIter = new KnuthPossPosIter(contentList, 0, contentList.size());
curLM.addAreas(contentPosIter, lc);
}
diff --git a/src/java/org/apache/fop/layoutmgr/inline/InlineLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/InlineLayoutManager.java
index 0c332281f..6e0c34a82 100755
--- a/src/java/org/apache/fop/layoutmgr/inline/InlineLayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/inline/InlineLayoutManager.java
@@ -248,8 +248,6 @@ public class InlineLayoutManager extends InlineStackingLayoutManager {
List returnList = new LinkedList();
KnuthSequence lastSequence = null;
- SpaceSpecifier leadingSpace = context.getLeadingSpace();
-
if (fobj instanceof Title) {
alignmentContext = new AlignmentContext(font,
lineHeight.getOptimum(this).getLength().getValue(this),
@@ -274,14 +272,6 @@ public class InlineLayoutManager extends InlineStackingLayoutManager {
if (getSpaceStart() != null) {
context.getLeadingSpace().addSpace(new SpaceVal(getSpaceStart(), this));
}
-
- // Check for "fence"
- if (hasLeadingFence(!context.isFirstArea())) {
- // Reset leading space sequence for child areas
- leadingSpace = new SpaceSpecifier(false);
- }
- // Reset state variables
- clearPrevIPD(); // Clear stored prev content dimensions
}
StringBuffer trace = new StringBuffer("InlineLM:");
diff --git a/src/java/org/apache/fop/layoutmgr/inline/InlineStackingLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/InlineStackingLayoutManager.java
index 963b98b37..65e59554f 100644
--- a/src/java/org/apache/fop/layoutmgr/inline/InlineStackingLayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/inline/InlineStackingLayoutManager.java
@@ -19,12 +19,13 @@
package org.apache.fop.layoutmgr.inline;
-import java.util.LinkedList;
import java.util.Iterator;
+import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
-import java.util.HashMap;
+import org.apache.fop.area.Area;
+import org.apache.fop.area.inline.Space;
import org.apache.fop.fo.FObj;
import org.apache.fop.fo.properties.SpaceProperty;
import org.apache.fop.layoutmgr.AbstractLayoutManager;
@@ -34,8 +35,6 @@ import org.apache.fop.layoutmgr.LayoutManager;
import org.apache.fop.layoutmgr.NonLeafPosition;
import org.apache.fop.layoutmgr.Position;
import org.apache.fop.layoutmgr.PositionIterator;
-import org.apache.fop.area.Area;
-import org.apache.fop.area.inline.Space;
import org.apache.fop.traits.MinOptMax;
/**
@@ -62,12 +61,6 @@ public abstract class InlineStackingLayoutManager extends AbstractLayoutManager
}
}
-
- /**
- * Size of any start or end borders and padding.
- */
- private MinOptMax allocIPD = new MinOptMax(0);
-
/**
* Size of border and padding in BPD (ie, before and after).
*/
@@ -78,9 +71,6 @@ public abstract class InlineStackingLayoutManager extends AbstractLayoutManager
/** The child layout context */
protected LayoutContext childLC;
- /** Used to store previous content IPD for each child LM. */
- private HashMap hmPrevIPD = new HashMap();
-
/**
* Create an inline stacking layout manager.
* This is used for fo's that create areas that
@@ -149,22 +139,6 @@ public abstract class InlineStackingLayoutManager extends AbstractLayoutManager
}
/**
- * TODO: Explain this method
- * @param lm ???
- * @return ???
- */
- protected MinOptMax getPrevIPD(LayoutManager lm) {
- return (MinOptMax) hmPrevIPD.get(lm);
- }
-
- /**
- * Clear the previous IPD calculation.
- */
- protected void clearPrevIPD() {
- hmPrevIPD.clear();
- }
-
- /**
* Returns the current area.
* @return the current area
*/
diff --git a/src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java
index aea851f54..7c30ab9bb 100644
--- a/src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java
@@ -20,6 +20,7 @@
package org.apache.fop.layoutmgr.inline;
import java.util.ArrayList;
+import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
@@ -116,8 +117,8 @@ public class LineLayoutManager extends InlineStackingLayoutManager
* inline break positions.
*/
private static class LineBreakPosition extends LeafPosition {
- private int iParIndex; // index of the Paragraph this Position refers to
- private int iStartIndex; //index of the first element this Position refers to
+ private int parIndex; // index of the Paragraph this Position refers to
+ private int startIndex; //index of the first element this Position refers to
private int availableShrink;
private int availableStretch;
private int difference;
@@ -130,16 +131,16 @@ public class LineLayoutManager extends InlineStackingLayoutManager
private int spaceAfter;
private int baseline;
- LineBreakPosition(LayoutManager lm, int index, int iStartIndex, int iBreakIndex,
+ LineBreakPosition(LayoutManager lm, int index, int startIndex, int breakIndex,
int shrink, int stretch, int diff,
double ipdA, double adjust, int ind,
int lh, int lw, int sb, int sa, int bl) {
- super(lm, iBreakIndex);
+ super(lm, breakIndex);
availableShrink = shrink;
availableStretch = stretch;
difference = diff;
- iParIndex = index;
- this.iStartIndex = iStartIndex;
+ parIndex = index;
+ this.startIndex = startIndex;
ipdAdjust = ipdA;
dAdjust = adjust;
startIndent = ind;
@@ -167,18 +168,18 @@ public class LineLayoutManager extends InlineStackingLayoutManager
private Length lineHeight;
private int lead;
private int follow;
- private AlignmentContext alignmentContext = null;
+ private AlignmentContext alignmentContext;
- private List knuthParagraphs = null;
- private int iReturnedLBP = 0;
-
- // parameters of Knuth's algorithm:
- // penalty value for flagged penalties
- private int flaggedPenalty = 50;
+ private List knuthParagraphs;
private LineLayoutPossibilities lineLayouts;
private List lineLayoutsList;
- private int iLineWidth = 0;
+ private int ipd = 0;
+ /**
+ * When layout must be re-started due to a change of IPD, there is no need
+ * to perform hyphenation on the remaining Knuth sequence once again.
+ */
+ private boolean hyphenationPerformed;
/**
* this constant is used to create elements when text-align is center:
@@ -238,7 +239,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager
} else {
lineFiller = new MinOptMax(lastLineEndIndent,
lastLineEndIndent,
- layoutManager.iLineWidth);
+ layoutManager.ipd);
}
// add auxiliary elements at the beginning of the paragraph
@@ -319,11 +320,9 @@ public class LineLayoutManager extends InlineStackingLayoutManager
private int activePossibility;
private int addedPositions;
private int textIndent;
- private int fillerMinWidth;
private int lineHeight;
private int lead;
private int follow;
- private int maxDiff;
private static final double MAX_DEMERITS = 10e6;
public LineBreakingAlgorithm (int pageAlign,
@@ -334,22 +333,17 @@ public class LineLayoutManager extends InlineStackingLayoutManager
super(textAlign, textAlignLast, first, false, maxFlagCount);
pageAlignment = pageAlign;
textIndent = indent;
- fillerMinWidth = fillerWidth;
lineHeight = lh;
lead = ld;
follow = fl;
thisLLM = llm;
activePossibility = -1;
- maxDiff = fobj.getWidows() >= fobj.getOrphans()
- ? fobj.getWidows()
- : fobj.getOrphans();
}
public void updateData1(int lineCount, double demerits) {
lineLayouts.addPossibility(lineCount, demerits);
- if (super.log.isTraceEnabled()) {
- super.log.trace(
- "Layout possibility in " + lineCount + " lines; break at position:");
+ if (log.isTraceEnabled()) {
+ log.trace("Layout possibility in " + lineCount + " lines; break at position:");
}
}
@@ -430,7 +424,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager
// true if this line contains only zero-height, auxiliary boxes
// and the actual line width is 0; in this case, the line "collapses"
// i.e. the line area will have bpd = 0
- boolean bZeroHeightLine = (difference == iLineWidth);
+ boolean bZeroHeightLine = (difference == ipd);
// if line-stacking-strategy is "font-height", the line height
// is not affected by its content
@@ -486,7 +480,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager
firstElementIndex, lastElementIndex,
availableShrink, availableStretch,
difference, ratio, 0, indent,
- 0, iLineWidth, 0, 0, 0);
+ 0, ipd, 0, 0, 0);
} else {
return new LineBreakPosition(thisLLM,
knuthParagraphs.indexOf(par),
@@ -494,18 +488,11 @@ public class LineLayoutManager extends InlineStackingLayoutManager
availableShrink, availableStretch,
difference, ratio, 0, indent,
lineLead + lineFollow,
- iLineWidth, spaceBefore, spaceAfter,
+ ipd, spaceBefore, spaceAfter,
lineLead);
}
}
- public int findBreakingPoints(Paragraph par, /*int lineWidth,*/
- double threshold, boolean force,
- int allowedBreaks) {
- return super.findBreakingPoints(par, /*lineWidth,*/
- threshold, force, allowedBreaks);
- }
-
protected int filterActiveNodes() {
KnuthNode bestActiveNode = null;
@@ -578,13 +565,10 @@ public class LineLayoutManager extends InlineStackingLayoutManager
FontInfo fi = fobj.getFOEventHandler().getFontInfo();
FontTriplet[] fontkeys = fobj.getCommonFont().getFontState(fi);
Font fs = fi.getFontInstance(fontkeys[0], fobj.getCommonFont().fontSize.getValue(this));
- alignmentContext
- = new AlignmentContext(fs, lineHeight.getValue(this), context.getWritingMode());
+ alignmentContext = new AlignmentContext(fs, lineHeight.getValue(this),
+ context.getWritingMode());
context.setAlignmentContext(alignmentContext);
- // Get a break from currently active child LM
- // Set up constraints for inline level managers
-
- clearPrevIPD();
+ ipd = context.getRefIPD();
//PHASE 1: Create Knuth elements
if (knuthParagraphs == null) {
@@ -606,34 +590,33 @@ public class LineLayoutManager extends InlineStackingLayoutManager
//PHASE 2: Create line breaks
return createLineBreaks(context.getBPAlignment(), context);
- /*
- LineBreakPosition lbp = null;
- if (breakpoints == null) {
- // find the optimal line breaking points for each paragraph
- breakpoints = new ArrayList();
- ListIterator paragraphsIterator
- = knuthParagraphs.listIterator(knuthParagraphs.size());
- Paragraph currPar = null;
- while (paragraphsIterator.hasPrevious()) {
- currPar = (Paragraph) paragraphsIterator.previous();
- findBreakingPoints(currPar, context.getStackLimit().opt);
- }
- }*/
+ }
- //PHASE 3: Return lines
+ public List getNextKnuthElements(LayoutContext context, int alignment,
+ LeafPosition restartPosition) {
+ log.trace("Restarting line breaking from index " + restartPosition.getIndex());
+ int parIndex = restartPosition.getLeafPos();
+ Paragraph paragraph = (Paragraph) knuthParagraphs.get(parIndex);
+ for (int i = 0; i <= restartPosition.getIndex(); i++) {
+ paragraph.remove(0);
+ }
+ Iterator iter = paragraph.iterator();
+ while (iter.hasNext() && !((KnuthElement) iter.next()).isBox()) {
+ iter.remove();
+ }
+ if (!iter.hasNext()) {
+ knuthParagraphs.remove(parIndex);
+ }
- /*
- // get a break point from the list
- lbp = (LineBreakPosition) breakpoints.get(iReturnedLBP ++);
- if (iReturnedLBP == breakpoints.size()) {
+ // return finished when there's no content
+ if (knuthParagraphs.size() == 0) {
setFinished(true);
+ return null;
}
- BreakPoss curLineBP = new BreakPoss(lbp);
- curLineBP.setFlag(BreakPoss.ISLAST, isFinished());
- curLineBP.setStackingSize(new MinOptMax(lbp.lineHeight));
- return curLineBP;
- */
+ ipd = context.getRefIPD();
+ //PHASE 2: Create line breaks
+ return createLineBreaks(context.getBPAlignment(), context);
}
/**
@@ -643,22 +626,18 @@ public class LineLayoutManager extends InlineStackingLayoutManager
private void collectInlineKnuthElements(LayoutContext context) {
LayoutContext inlineLC = new LayoutContext(context);
- InlineLevelLayoutManager curLM;
- List returnedList = null;
- iLineWidth = context.getStackLimitIP().opt;
-
// convert all the text in a sequence of paragraphs made
// of KnuthBox, KnuthGlue and KnuthPenalty objects
- boolean bPrevWasKnuthBox = false;
+ boolean previousIsBox = false;
StringBuffer trace = new StringBuffer("LineLM:");
Paragraph lastPar = null;
+ InlineLevelLayoutManager curLM;
while ((curLM = (InlineLevelLayoutManager) getChildLM()) != null) {
- returnedList = curLM.getNextKnuthElements(inlineLC, effectiveAlignment);
- if (returnedList == null
- || returnedList.size() == 0) {
+ List inlineElements = curLM.getNextKnuthElements(inlineLC, effectiveAlignment);
+ if (inlineElements == null || inlineElements.size() == 0) {
/* curLM.getNextKnuthElements() returned null or an empty list;
* this can happen if there is nothing more to layout,
* so just iterate once more to see if there are other children */
@@ -666,7 +645,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager
}
if (lastPar != null) {
- KnuthSequence firstSeq = (KnuthSequence) returnedList.get(0);
+ KnuthSequence firstSeq = (KnuthSequence) inlineElements.get(0);
// finish last paragraph before a new block sequence
if (!firstSeq.isInlineSequence()) {
@@ -676,7 +655,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager
if (log.isTraceEnabled()) {
trace.append(" ]");
}
- bPrevWasKnuthBox = false;
+ previousIsBox = false;
}
// does the first element of the first paragraph add to an existing word?
@@ -684,27 +663,24 @@ public class LineLayoutManager extends InlineStackingLayoutManager
KnuthElement thisElement;
thisElement = (KnuthElement) firstSeq.get(0);
if (thisElement.isBox() && !thisElement.isAuxiliary()
- && bPrevWasKnuthBox) {
+ && previousIsBox) {
lastPar.addALetterSpace();
}
}
}
// loop over the KnuthSequences (and single KnuthElements) in returnedList
- ListIterator iter = returnedList.listIterator();
+ ListIterator iter = inlineElements.listIterator();
while (iter.hasNext()) {
KnuthSequence sequence = (KnuthSequence) iter.next();
// the sequence contains inline Knuth elements
if (sequence.isInlineSequence()) {
// look at the last element
ListElement lastElement = sequence.getLast();
- if (lastElement == null) {
- throw new NullPointerException(
- "Sequence was empty! lastElement is null");
- }
- bPrevWasKnuthBox = lastElement.isBox()
- && !((KnuthElement) lastElement).isAuxiliary()
- && ((KnuthElement) lastElement).getW() != 0;
+ assert lastElement != null;
+ previousIsBox = lastElement.isBox()
+ && !((KnuthElement) lastElement).isAuxiliary()
+ && ((KnuthElement) lastElement).getW() != 0;
// if last paragraph is open, add the new elements to the paragraph
// else this is the last paragraph
@@ -729,8 +705,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager
// finish last paragraph if it was closed with a linefeed
if (lastElement.isPenalty()
- && ((KnuthPenalty) lastElement).getP()
- == -KnuthPenalty.INFINITE) {
+ && ((KnuthPenalty) lastElement).getP() == -KnuthPenalty.INFINITE) {
// a penalty item whose value is -inf
// represents a preserved linefeed,
// which forces a line break
@@ -738,7 +713,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager
if (!lastPar.containsBox()) {
//only a forced linefeed on this line
//-> compensate with an auxiliary glue
- lastPar.add(new KnuthGlue(iLineWidth, 0, iLineWidth, null, true));
+ lastPar.add(new KnuthGlue(ipd, 0, ipd, null, true));
}
lastPar.endParagraph();
ElementListObserver.observe(lastPar, "line", null);
@@ -746,7 +721,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager
if (log.isTraceEnabled()) {
trace.append(" ]");
}
- bPrevWasKnuthBox = false;
+ previousIsBox = false;
}
} else { // the sequence is a block sequence
// the positions will be wrapped with this LM in postProcessLineBreaks
@@ -768,144 +743,14 @@ public class LineLayoutManager extends InlineStackingLayoutManager
}
/**
- * Find a set of breaking points.
- * This method is called only once by getNextBreakPoss, and it
- * subsequently calls the other findBreakingPoints() method with
- * different parameters, until a set of breaking points is found.
- *
- * @param par the list of elements that must be parted
- * into lines
- * @param lineWidth the desired length ot the lines
- */
- /*
- private void findBreakingPoints(Paragraph par, int lineWidth) {
- // maximum adjustment ratio permitted
- float maxAdjustment = 1;
-
- // first try
- if (!findBreakingPoints(par, lineWidth, maxAdjustment, false)) {
- // the first try failed, now try something different
- log.debug("No set of breaking points found with maxAdjustment = " + maxAdjustment);
- if (hyphenationProperties.hyphenate == Constants.EN_TRUE) {
- // consider every hyphenation point as a legal break
- findHyphenationPoints(par);
- } else {
- // try with a higher threshold
- maxAdjustment = 5;
- }
-
- if (!findBreakingPoints(par, lineWidth, maxAdjustment, false)) {
- // the second try failed too, try with a huge threshold;
- // if this fails too, use a different algorithm
- log.debug("No set of breaking points found with maxAdjustment = " + maxAdjustment
- + (hyphenationProperties.hyphenate == Constants.EN_TRUE ? " and hyphenation" : ""));
- maxAdjustment = 20;
- if (!findBreakingPoints(par, lineWidth, maxAdjustment, true)) {
- log.debug("No set of breaking points found, using first-fit algorithm");
- }
- }
- }
- }
-
- private boolean findBreakingPoints(Paragraph par, int lineWidth,
- double threshold, boolean force) {
- KnuthParagraph knuthPara = new KnuthParagraph(par);
- int lines = knuthPara.findBreakPoints(lineWidth, threshold, force);
- if (lines == 0) {
- return false;
- }
-
- for (int i = lines-1; i >= 0; i--) {
- int line = i+1;
- if (log.isTraceEnabled()) {
- log.trace("Making line from " + knuthPara.getStart(i) + " to " +
- knuthPara.getEnd(i));
- }
- // compute indent and adjustment ratio, according to
- // the value of text-align and text-align-last
-
- int difference = knuthPara.getDifference(i);
- if (line == lines) {
- difference += par.lineFillerWidth;
- }
- int textAlign = (line < lines)
- ? textAlignment : textAlignmentLast;
- int indent = (textAlign == EN_CENTER)
- ? difference / 2
- : (textAlign == EN_END) ? difference : 0;
- indent += (line == 1 && knuthParagraphs.indexOf(par) == 0)
- ? textIndent.getValue(this) : 0;
- double ratio = (textAlign == EN_JUSTIFY)
- ? knuthPara.getAdjustRatio(i) : 0;
-
- int start = knuthPara.getStart(i);
- int end = knuthPara.getEnd(i);
- makeLineBreakPosition(par, start, end, 0, ratio, indent);
- }
- return true;
- }
-
- private void makeLineBreakPosition(Paragraph par,
- int firstElementIndex, int lastElementIndex,
- int insertIndex, double ratio, int indent) {
- // line height calculation
-
- int halfLeading = (lineHeight - lead - follow) / 2;
- // height above the main baseline
- int lineLead = lead + halfLeading;
- // maximum size of top and bottom alignment
- int lineFollow = follow + halfLeading;
-
- ListIterator inlineIterator
- = par.listIterator(firstElementIndex);
- for (int j = firstElementIndex;
- j <= lastElementIndex;
- j++) {
- KnuthElement element = (KnuthElement) inlineIterator.next();
- if (element.isBox()) {
- KnuthInlineBox box = (KnuthInlineBox)element;
- if (box.getLead() > lineLead) {
- lineLead = box.getLead();
- }
- if (box.getTotal() > lineFollow) {
- lineFollow = box.getTotal();
- }
- if (box.getMiddle() > lineLead + middleShift) {
- lineLead += box.getMiddle()
- - lineLead - middleShift;
- }
- if (box.getMiddle() > middlefollow - middleShift) {
- middlefollow += box.getMiddle()
- - middlefollow + middleShift;
- }
- }
- }
-
- if (lineFollow - lineLead > middlefollow) {
- middlefollow = lineFollow - lineLead;
- }
-
- breakpoints.add(insertIndex,
- new LineBreakPosition(this,
- knuthParagraphs.indexOf(par),
- lastElementIndex ,
- ratio, 0, indent,
- lineLead + middlefollow,
- lineLead));
- }*/
-
-
- /**
* Phase 2 of Knuth algorithm: find optimal break points.
* @param alignment alignment in BP direction of the paragraph
* @param context the layout context
* @return a list of Knuth elements representing broken lines
*/
private List createLineBreaks(int alignment, LayoutContext context) {
-
// find the optimal line breaking points for each paragraph
- ListIterator paragraphsIterator
- = knuthParagraphs.listIterator(knuthParagraphs.size());
+ ListIterator paragraphsIterator = knuthParagraphs.listIterator(knuthParagraphs.size());
lineLayoutsList = new ArrayList(knuthParagraphs.size());
LineLayoutPossibilities llPoss;
while (paragraphsIterator.hasPrevious()) {
@@ -947,7 +792,8 @@ public class LineLayoutManager extends InlineStackingLayoutManager
this);
if (hyphenationProperties.hyphenate.getEnum() == EN_TRUE
- && fobj.getWrapOption() != EN_NO_WRAP) {
+ && fobj.getWrapOption() != EN_NO_WRAP && !hyphenationPerformed) {
+ hyphenationPerformed = true;
findHyphenationPoints(currPar);
}
@@ -958,7 +804,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager
} else {
allowedBreaks = BreakingAlgorithm.NO_FLAGGED_PENALTIES;
}
- alg.setConstantLineWidth(iLineWidth);
+ alg.setConstantLineWidth(ipd);
iBPcount = alg.findBreakingPoints(currPar,
maxAdjustment, false, allowedBreaks);
if (iBPcount == 0 || alignment == EN_JUSTIFY) {
@@ -1014,26 +860,26 @@ public class LineLayoutManager extends InlineStackingLayoutManager
alg.resetAlgorithm();
lineLayouts.savePossibilities(true);
// try with shorter lines
- int savedLineWidth = iLineWidth;
- iLineWidth = (int) (iLineWidth * 0.95);
+ int savedLineWidth = ipd;
+ ipd = (int) (ipd * 0.95);
iBPcount = alg.findBreakingPoints(currPar,
- maxAdjustment, true, allowedBreaks);
+ maxAdjustment, true, allowedBreaks);
// use normal lines, when possible
lineLayouts.restorePossibilities();
- iLineWidth = savedLineWidth;
+ ipd = savedLineWidth;
}
if (!lineLayouts.canUseLessLines()) {
alg.resetAlgorithm();
lineLayouts.savePossibilities(true);
// try with longer lines
- int savedLineWidth = iLineWidth;
- iLineWidth = (int) (iLineWidth * 1.05);
- alg.setConstantLineWidth(iLineWidth);
+ int savedLineWidth = ipd;
+ ipd = (int) (ipd * 1.05);
+ alg.setConstantLineWidth(ipd);
iBPcount = alg.findBreakingPoints(currPar,
maxAdjustment, true, allowedBreaks);
// use normal lines, when possible
lineLayouts.restorePossibilities();
- iLineWidth = savedLineWidth;
+ ipd = savedLineWidth;
}
//log.debug("LLM.getNextKnuthElements> now, layouts with more lines? " + lineLayouts.canUseMoreLines());
//log.debug(" now, layouts with fewer lines? " + lineLayouts.canUseLessLines());
@@ -1052,6 +898,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager
List returnList = new LinkedList();
+ int endIndex = -1;
for (int p = 0; p < knuthParagraphs.size(); p++) {
// penalty between paragraphs
if (p > 0) {
@@ -1089,7 +936,6 @@ public class LineLayoutManager extends InlineStackingLayoutManager
} else {
/* "normal" vertical alignment: create a sequence whose boxes
represent effective lines, and contain LineBreakPositions */
- Position returnPosition = new LeafPosition(this, p);
int startIndex = 0;
for (int i = 0;
i < llPoss.getChosenLineCount();
@@ -1101,13 +947,12 @@ public class LineLayoutManager extends InlineStackingLayoutManager
// penalty allowing a page break between lines
Keep keep = getKeepTogether();
returnList.add(new BreakElement(
- new Position(this),
+ new LeafPosition(this, p, endIndex),
keep.getPenalty(),
keep.getContext(),
context));
}
- int endIndex
- = ((LineBreakPosition) llPoss.getChosenPosition(i)).getLeafPos();
+ endIndex = ((LineBreakPosition) llPoss.getChosenPosition(i)).getLeafPos();
// create a list of the FootnoteBodyLM handling footnotes
// whose citations are in this line
List footnoteList = new LinkedList();
@@ -1115,15 +960,14 @@ public class LineLayoutManager extends InlineStackingLayoutManager
while (elementIterator.nextIndex() <= endIndex) {
KnuthElement element = (KnuthElement) elementIterator.next();
if (element instanceof KnuthInlineBox
- && ((KnuthInlineBox) element).isAnchor()) {
+ && ((KnuthInlineBox) element).isAnchor()) {
footnoteList.add(((KnuthInlineBox) element).getFootnoteBodyLM());
} else if (element instanceof KnuthBlockBox) {
footnoteList.addAll(((KnuthBlockBox) element).getFootnoteBodyLMs());
}
}
startIndex = endIndex + 1;
- LineBreakPosition lbp
- = (LineBreakPosition) llPoss.getChosenPosition(i);
+ LineBreakPosition lbp = (LineBreakPosition) llPoss.getChosenPosition(i);
returnList.add(new KnuthBlockBox
(lbp.lineHeight + lbp.spaceBefore + lbp.spaceAfter,
footnoteList, lbp, false));
@@ -1597,7 +1441,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager
Position pos = (Position) parentIter.next();
boolean isLastPosition = !parentIter.hasNext();
if (pos instanceof LineBreakPosition) {
- addInlineArea(context, pos, isLastPosition);
+ addInlineArea(context, (LineBreakPosition) pos, isLastPosition);
} else if ((pos instanceof NonLeafPosition) && pos.generatesAreas()) {
addBlockArea(context, pos, isLastPosition);
} else {
@@ -1617,147 +1461,129 @@ public class LineLayoutManager extends InlineStackingLayoutManager
* @param pos the position for which the line is generated
* @param isLastPosition true if this is the last position of this LM
*/
- private void addInlineArea(LayoutContext context, Position pos, boolean isLastPosition) {
- ListIterator seqIterator = null;
- KnuthElement tempElement = null;
- // the TLM which created the last KnuthElement in this line
- LayoutManager lastLM = null;
-
- LineBreakPosition lbp = (LineBreakPosition) pos;
- int iCurrParIndex;
- iCurrParIndex = lbp.iParIndex;
- KnuthSequence seq = (KnuthSequence) knuthParagraphs.get(iCurrParIndex);
- int iStartElement = lbp.iStartIndex;
- int iEndElement = lbp.getLeafPos();
-
- LineArea lineArea
- = new LineArea((lbp.getLeafPos() < seq.size() - 1
- ? textAlignment : textAlignmentLast),
- lbp.difference, lbp.availableStretch, lbp.availableShrink);
- if (lbp.startIndent != 0) {
- lineArea.addTrait(Trait.START_INDENT, new Integer(lbp.startIndent));
- }
- lineArea.setBPD(lbp.lineHeight);
- lineArea.setIPD(lbp.lineWidth);
- lineArea.addTrait(Trait.SPACE_BEFORE, new Integer(lbp.spaceBefore));
- lineArea.addTrait(Trait.SPACE_AFTER, new Integer(lbp.spaceAfter));
- alignmentContext.resizeLine(lbp.lineHeight, lbp.baseline);
-
- if (seq instanceof Paragraph) {
- Paragraph currPar = (Paragraph) seq;
- // ignore the first elements added by the LineLayoutManager
- iStartElement += (iStartElement == 0) ? currPar.ignoreAtStart : 0;
-
- // if this is the last line area that for this paragraph,
- // ignore the last elements added by the LineLayoutManager and
- // subtract the last-line-end-indent from the area ipd
- if (iEndElement == (currPar.size() - 1)) {
- iEndElement -= currPar.ignoreAtEnd;
- lineArea.setIPD(lineArea.getIPD() - lastLineEndIndent.getValue(this));
- }
+ private void addInlineArea(LayoutContext context, LineBreakPosition lbp,
+ boolean isLastPosition) {
+ // the TLM which created the last KnuthElement in this line
+ LayoutManager lastLM = null;
+
+ KnuthSequence seq = (KnuthSequence) knuthParagraphs.get(lbp.parIndex);
+ int startElementIndex = lbp.startIndex;
+ int endElementIndex = lbp.getLeafPos();
+
+ LineArea lineArea = new LineArea(
+ (lbp.getLeafPos() < seq.size() - 1 ? textAlignment : textAlignmentLast),
+ lbp.difference, lbp.availableStretch, lbp.availableShrink);
+ if (lbp.startIndent != 0) {
+ lineArea.addTrait(Trait.START_INDENT, new Integer(lbp.startIndent));
+ }
+ lineArea.setBPD(lbp.lineHeight);
+ lineArea.setIPD(lbp.lineWidth);
+ lineArea.addTrait(Trait.SPACE_BEFORE, new Integer(lbp.spaceBefore));
+ lineArea.addTrait(Trait.SPACE_AFTER, new Integer(lbp.spaceAfter));
+ alignmentContext.resizeLine(lbp.lineHeight, lbp.baseline);
+
+ if (seq instanceof Paragraph) {
+ Paragraph currPar = (Paragraph) seq;
+ // ignore the first elements added by the LineLayoutManager
+ startElementIndex += (startElementIndex == 0) ? currPar.ignoreAtStart : 0;
+
+ // if this is the last line area that for this paragraph,
+ // ignore the last elements added by the LineLayoutManager and
+ // subtract the last-line-end-indent from the area ipd
+ if (endElementIndex == (currPar.size() - 1)) {
+ endElementIndex -= currPar.ignoreAtEnd;
+ lineArea.setIPD(lineArea.getIPD() - lastLineEndIndent.getValue(this));
}
+ }
- // Remove trailing spaces if allowed so
- if (whiteSpaceTreament == EN_IGNORE_IF_SURROUNDING_LINEFEED
+ // Remove trailing spaces if allowed so
+ if (whiteSpaceTreament == EN_IGNORE_IF_SURROUNDING_LINEFEED
|| whiteSpaceTreament == EN_IGNORE
|| whiteSpaceTreament == EN_IGNORE_IF_BEFORE_LINEFEED) {
- // ignore the last element in the line if it is a KnuthGlue object
- seqIterator = seq.listIterator(iEndElement);
- tempElement = (KnuthElement) seqIterator.next();
- if (tempElement.isGlue()) {
- iEndElement--;
- // this returns the same KnuthElement
- seqIterator.previous();
- if (seqIterator.hasPrevious()) {
- tempElement = (KnuthElement) seqIterator.previous();
- } else {
- tempElement = null;
- }
- }
- if (tempElement != null) {
- lastLM = tempElement.getLayoutManager();
+ // ignore the last element in the line if it is a KnuthGlue object
+ ListIterator seqIterator = seq.listIterator(endElementIndex);
+ KnuthElement lastElement = (KnuthElement) seqIterator.next();
+ lastLM = lastElement.getLayoutManager();
+ if (lastElement.isGlue()) {
+ endElementIndex--;
+ // this returns the same KnuthElement
+ seqIterator.previous();
+ if (seqIterator.hasPrevious()) {
+ lastLM = ((KnuthElement) seqIterator.previous()).getLayoutManager();
}
}
+ }
- // Remove leading spaces if allowed so
- if (whiteSpaceTreament == EN_IGNORE_IF_SURROUNDING_LINEFEED
+ // Remove leading spaces if allowed so
+ if (whiteSpaceTreament == EN_IGNORE_IF_SURROUNDING_LINEFEED
|| whiteSpaceTreament == EN_IGNORE
|| whiteSpaceTreament == EN_IGNORE_IF_AFTER_LINEFEED) {
- // ignore KnuthGlue and KnuthPenalty objects
- // at the beginning of the line
- seqIterator = seq.listIterator(iStartElement);
- tempElement = (KnuthElement) seqIterator.next();
- while (!tempElement.isBox() && seqIterator.hasNext()) {
- tempElement = (KnuthElement) seqIterator.next();
- iStartElement++;
- }
- }
- // Add the inline areas to lineArea
- PositionIterator inlinePosIter
- = new KnuthPossPosIter(seq, iStartElement, iEndElement + 1);
-
- iStartElement = lbp.getLeafPos() + 1;
- if (iStartElement == seq.size()) {
- // advance to next paragraph
- iStartElement = 0;
+ // ignore KnuthGlue and KnuthPenalty objects
+ // at the beginning of the line
+ ListIterator seqIterator = seq.listIterator(startElementIndex);
+ while (seqIterator.hasNext() && !((KnuthElement) seqIterator.next()).isBox()) {
+ startElementIndex++;
}
+ }
+ // Add the inline areas to lineArea
+ PositionIterator inlinePosIter = new KnuthPossPosIter(seq, startElementIndex,
+ endElementIndex + 1);
- LayoutContext lc = new LayoutContext(0);
- lc.setAlignmentContext(alignmentContext);
- lc.setSpaceAdjust(lbp.dAdjust);
- lc.setIPDAdjust(lbp.ipdAdjust);
- lc.setLeadingSpace(new SpaceSpecifier(true));
- lc.setTrailingSpace(new SpaceSpecifier(false));
- lc.setFlags(LayoutContext.RESOLVE_LEADING_SPACE, true);
-
- /*
- * extension (not in the XSL FO recommendation): if the left and right margins
- * have been optimized, recompute indents and / or adjust ratio, according
- * to the paragraph horizontal alignment
- */
- if (false && textAlignment == EN_JUSTIFY) {
- // re-compute space adjust ratio
- int updatedDifference = context.getStackLimitIP().opt
- - lbp.lineWidth + lbp.difference;
- double updatedRatio = 0.0;
- if (updatedDifference > 0) {
- updatedRatio = (float) updatedDifference / lbp.availableStretch;
- } else if (updatedDifference < 0) {
- updatedRatio = (float) updatedDifference / lbp.availableShrink;
- }
- lc.setIPDAdjust(updatedRatio);
- //log.debug("LLM.addAreas> old difference = " + lbp.difference + " new difference = " + updatedDifference);
- //log.debug(" old ratio = " + lbp.ipdAdjust + " new ratio = " + updatedRatio);
- } else if (false && textAlignment == EN_CENTER) {
- // re-compute indent
- int updatedIndent = lbp.startIndent
- + (context.getStackLimitIP().opt - lbp.lineWidth) / 2;
- lineArea.addTrait(Trait.START_INDENT, new Integer(updatedIndent));
- } else if (false && textAlignment == EN_END) {
- // re-compute indent
- int updatedIndent = lbp.startIndent
- + (context.getStackLimitIP().opt - lbp.lineWidth);
- lineArea.addTrait(Trait.START_INDENT, new Integer(updatedIndent));
- }
+ LayoutContext lc = new LayoutContext(0);
+ lc.setAlignmentContext(alignmentContext);
+ lc.setSpaceAdjust(lbp.dAdjust);
+ lc.setIPDAdjust(lbp.ipdAdjust);
+ lc.setLeadingSpace(new SpaceSpecifier(true));
+ lc.setTrailingSpace(new SpaceSpecifier(false));
+ lc.setFlags(LayoutContext.RESOLVE_LEADING_SPACE, true);
- setCurrentArea(lineArea);
- setChildContext(lc);
- LayoutManager childLM;
- while ((childLM = inlinePosIter.getNextChildLM()) != null) {
- lc.setFlags(LayoutContext.LAST_AREA, (childLM == lastLM));
- childLM.addAreas(inlinePosIter, lc);
- lc.setLeadingSpace(lc.getTrailingSpace());
- lc.setTrailingSpace(new SpaceSpecifier(false));
+ /*
+ * extension (not in the XSL FO recommendation): if the left and right margins
+ * have been optimized, recompute indents and / or adjust ratio, according
+ * to the paragraph horizontal alignment
+ */
+ if (false && textAlignment == EN_JUSTIFY) {
+ // re-compute space adjust ratio
+ int updatedDifference = context.getRefIPD()
+ - lbp.lineWidth + lbp.difference;
+ double updatedRatio = 0.0;
+ if (updatedDifference > 0) {
+ updatedRatio = (float) updatedDifference / lbp.availableStretch;
+ } else if (updatedDifference < 0) {
+ updatedRatio = (float) updatedDifference / lbp.availableShrink;
}
+ lc.setIPDAdjust(updatedRatio);
+ //log.debug("LLM.addAreas> old difference = " + lbp.difference + " new difference = " + updatedDifference);
+ //log.debug(" old ratio = " + lbp.ipdAdjust + " new ratio = " + updatedRatio);
+ } else if (false && textAlignment == EN_CENTER) {
+ // re-compute indent
+ int updatedIndent = lbp.startIndent
+ + (context.getRefIPD() - lbp.lineWidth) / 2;
+ lineArea.addTrait(Trait.START_INDENT, new Integer(updatedIndent));
+ } else if (false && textAlignment == EN_END) {
+ // re-compute indent
+ int updatedIndent = lbp.startIndent
+ + (context.getRefIPD() - lbp.lineWidth);
+ lineArea.addTrait(Trait.START_INDENT, new Integer(updatedIndent));
+ }
- // when can this be null?
- // if display-align is distribute, add space after
- if (context.getSpaceAfter() > 0
- && (!context.isLastArea() || !isLastPosition)) {
- lineArea.setBPD(lineArea.getBPD() + context.getSpaceAfter());
- }
- lineArea.finalise();
- parentLM.addChildArea(lineArea);
+ setCurrentArea(lineArea);
+ setChildContext(lc);
+ LayoutManager childLM;
+ while ((childLM = inlinePosIter.getNextChildLM()) != null) {
+ lc.setFlags(LayoutContext.LAST_AREA, (childLM == lastLM));
+ childLM.addAreas(inlinePosIter, lc);
+ lc.setLeadingSpace(lc.getTrailingSpace());
+ lc.setTrailingSpace(new SpaceSpecifier(false));
+ }
+
+ // if display-align is distribute, add space after
+ if (context.getSpaceAfter() > 0
+ && (!context.isLastArea() || !isLastPosition)) {
+ lineArea.setBPD(lineArea.getBPD() + context.getSpaceAfter());
+ }
+ lineArea.finalise();
+ parentLM.addChildArea(lineArea);
}
/**
@@ -1800,7 +1626,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager
// set last area flag
blocklc.setFlags(LayoutContext.LAST_AREA,
(context.isLastArea() && childLM == lastLM));
- blocklc.setStackLimitsFrom(context);
+ blocklc.setStackLimitBP(context.getStackLimitBP());
// Add the line areas to Area
childLM.addAreas(childPosIter, blocklc);
blocklc.setLeadingSpace(blocklc.getTrailingSpace());
@@ -1841,5 +1667,11 @@ public class LineLayoutManager extends InlineStackingLayoutManager
public boolean getGeneratesLineArea() {
return true;
}
+
+ /** {@inheritDoc} */
+ public boolean isRestartable() {
+ return true;
+ }
+
}
diff --git a/src/java/org/apache/fop/layoutmgr/list/ListItemLayoutManager.java b/src/java/org/apache/fop/layoutmgr/list/ListItemLayoutManager.java
index 7000a8748..fb88bb79d 100644
--- a/src/java/org/apache/fop/layoutmgr/list/ListItemLayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/list/ListItemLayoutManager.java
@@ -702,6 +702,13 @@ public class ListItemLayoutManager extends BlockStackingLayoutManager
}
}
+ /** {@inheritDoc} */
+ public void reset() {
+ super.reset();
+ label.reset();
+ body.reset();
+ }
+
}
diff --git a/src/java/org/apache/fop/render/pdf/PDFEventProducer.xml b/src/java/org/apache/fop/render/pdf/PDFEventProducer.xml
index 420f16a09..fd57d5099 100644
--- a/src/java/org/apache/fop/render/pdf/PDFEventProducer.xml
+++ b/src/java/org/apache/fop/render/pdf/PDFEventProducer.xml
@@ -1,3 +1,4 @@
-<?xml version="1.0" encoding="UTF-8"?><catalogue xml:lang="en">
+<?xml version="1.0" encoding="UTF-8"?>
+<catalogue xml:lang="en">
<message key="org.apache.fop.render.pdf.PDFEventProducer.nonFullyResolvedLinkTargets">{count} link target{count,equals,1,,s} could not be fully resolved and now point{count,equals,1,,s} to the top of the page or {count,equals,1,is,are} dysfunctional.</message>
</catalogue>
diff --git a/test/layoutengine/standard-testcases/flow_changing-ipd_1.xml b/test/layoutengine/standard-testcases/flow_changing-ipd_1.xml
new file mode 100644
index 000000000..d4db6e696
--- /dev/null
+++ b/test/layoutengine/standard-testcases/flow_changing-ipd_1.xml
@@ -0,0 +1,97 @@
+<?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 that blocks of texts are re-laid out after a change of the flow ipd.
+ </p>
+ </info>
+ <fo>
+ <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
+ <fo:layout-master-set>
+ <fo:simple-page-master master-name="narrow"
+ page-height="300pt" page-width="400pt" margin="50pt">
+ <fo:region-body background-color="#F0F0F0"/>
+ </fo:simple-page-master>
+ <fo:simple-page-master master-name="wide"
+ page-height="300pt" page-width="600pt" margin="50pt">
+ <fo:region-body background-color="#F0F0F0"/>
+ </fo:simple-page-master>
+ <fo:page-sequence-master master-name="pages">
+ <fo:single-page-master-reference master-reference="narrow"/>
+ <fo:repeatable-page-master-reference master-reference="wide"/>
+ </fo:page-sequence-master>
+ </fo:layout-master-set>
+ <fo:page-sequence master-reference="pages">
+ <fo:flow flow-name="xsl-region-body" language="en" hyphenate="true">
+ <fo:block text-align="justify" id="surrounding"
+ space-before.minimum="10pt"
+ space-before.optimum="12pt"
+ space-before.maximum="50pt">
+ <fo:block space-before="inherit" id="b1">In olden times when wishing still helped one,
+ there lived a king whose daughters were all beautiful, but the youngest was so
+ beautiful that the sun itself, which has seen so much, was astonished whenever it
+ shone in her face.</fo:block>
+ <fo:block space-before="inherit" id="b2">In olden times when wishing still helped one,
+ there lived a king whose daughters were all beautiful, but the youngest was so
+ beautiful that the sun itself, which has seen so much, was astonished whenever it
+ shone in her face.</fo:block>
+ <fo:block space-before="inherit" id="b3" border-top="1pt solid black"
+ border-before-width.conditionality="retain">In olden times when wishing still helped
+ one, there lived a king whose daughters were all beautiful, but the youngest was so
+ beautiful that the sun itself, which has seen so much, was astonished whenever it
+ shone in her face. In olden times when wishing still helped one, there lived a king
+ whose daughters were all beautiful, but the youngest was so beautiful that the sun
+ itself, which has seen so much, was astonished whenever it shone in her
+ face.</fo:block>
+ <fo:block space-before="inherit" id="b4" border-top="1pt solid black">In olden times
+ when wishing still helped one, there lived a king whose daughters were all beautiful,
+ but the youngest was so beautiful that the sun itself, which has seen so much, was
+ astonished whenever it shone in her face.</fo:block>
+ <fo:block space-before="inherit" id="b5">In olden times when wishing still helped one,
+ there lived a king whose daughters were all beautiful, but the youngest was so
+ beautiful that the sun itself, which has seen so much, was astonished whenever it
+ shone in her face.</fo:block>
+ </fo:block>
+ </fo:flow>
+ </fo:page-sequence>
+ </fo:root>
+ </fo>
+ <checks>
+ <eval expected="13100" xpath="//pageViewport[1]//flow/block/block[2]/@space-before"/>
+ <eval expected="13100" xpath="//pageViewport[1]//flow/block/block[3]/@space-before"/>
+ <eval expected="(solid,#000000,1000)"
+ xpath="//pageViewport[1]//flow/block/block[3]/@border-before"/>
+ <eval expected="In" xpath="//pageViewport[1]//flow/block/block[3]/lineArea[4]/text/word[position()=last()]"/>
+ <eval expected="500000" xpath="//pageViewport[2]//flow/block/@ipd"/>
+ <eval expected="(solid,#000000,1000)"
+ xpath="//pageViewport[2]//flow/block/block[1]/@border-before"/>
+ <eval expected="500000" xpath="//pageViewport[2]//flow/block/block[1]/@ipd"/>
+ <eval expected="500000" xpath="//pageViewport[2]//flow/block/block[1]/lineArea[1]/@ipd"/>
+ <eval expected="olden" xpath="//pageViewport[2]//flow/block/block[1]/lineArea[1]/text/word[1]"/>
+ <eval expected="500000" xpath="//pageViewport[2]//flow/block/block[2]/@ipd"/>
+ <eval expected="12000" xpath="//pageViewport[2]//flow/block/block[2]/@space-before"/>
+ <eval expected="(solid,#000000,1000)"
+ xpath="//pageViewport[2]//flow/block/block[2]/@border-before"/>
+ <eval expected="500000" xpath="//pageViewport[2]//flow/block/block[2]/lineArea[1]/@ipd"/>
+ <eval expected="500000" xpath="//pageViewport[2]//flow/block/block[3]/@ipd"/>
+ <eval expected="12000" xpath="//pageViewport[2]//flow/block/block[3]/@space-before"/>
+ <eval expected="500000" xpath="//pageViewport[2]//flow/block/block[3]/lineArea[1]/@ipd"/>
+ </checks>
+</testcase>
diff --git a/test/layoutengine/standard-testcases/flow_changing-ipd_2.xml b/test/layoutengine/standard-testcases/flow_changing-ipd_2.xml
new file mode 100644
index 000000000..dbe002e43
--- /dev/null
+++ b/test/layoutengine/standard-testcases/flow_changing-ipd_2.xml
@@ -0,0 +1,75 @@
+<?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 that blocks of texts are re-laid out after a change of the flow ipd.
+ </p>
+ </info>
+ <fo>
+ <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
+ <fo:layout-master-set>
+ <fo:simple-page-master master-name="narrow"
+ page-height="300pt" page-width="400pt" margin="50pt">
+ <fo:region-body background-color="#F0F0F0"/>
+ </fo:simple-page-master>
+ <fo:simple-page-master master-name="wide"
+ page-height="300pt" page-width="600pt" margin="50pt">
+ <fo:region-body background-color="#F0F0F0"/>
+ </fo:simple-page-master>
+ <fo:page-sequence-master master-name="pages">
+ <fo:single-page-master-reference master-reference="narrow"/>
+ <fo:repeatable-page-master-reference master-reference="wide"/>
+ </fo:page-sequence-master>
+ </fo:layout-master-set>
+ <fo:page-sequence master-reference="pages">
+ <fo:flow flow-name="xsl-region-body">
+ <fo:block id="b1">In olden times when wishing still helped one, there lived a king whose
+ daughters were all beautiful, but the youngest was so beautiful that the sun itself,
+ which has seen so much, was astonished whenever it shone in her face.</fo:block>
+ <fo:block id="b2">In olden times when wishing still helped one, there lived a king whose
+ daughters were all beautiful, but the youngest was so beautiful that the sun itself,
+ which has seen so much, was astonished whenever it shone in her face.</fo:block>
+ <fo:block id="b3">In olden times when wishing still helped one, there lived a king whose
+ daughters were all beautiful, but the youngest was so beautiful that the sun itself,
+ which has seen so much, was astonished whenever it shone in her face. In olden times
+ when wishing still helped one, there lived a king whose daughters were all beautiful,
+ but the youngest was so beautiful that the sun itself, which has seen so much, was
+ astonished whenever it shone in her face.</fo:block>
+ <fo:block id="b4">In olden times when wishing still helped one, there lived a king whose
+ daughters were all beautiful, but the youngest was so beautiful that the sun itself,
+ which has seen so much, was astonished whenever it shone in her face.</fo:block>
+ <fo:block id="b5">In olden times when wishing still helped one, there lived a king whose
+ daughters were all beautiful, but the youngest was so beautiful that the sun itself,
+ which has seen so much, was astonished whenever it shone in her face.</fo:block>
+ </fo:flow>
+ </fo:page-sequence>
+ </fo:root>
+ </fo>
+ <checks>
+ <eval expected="has" xpath="//pageViewport[1]//flow/block[3]/lineArea[3]/text/word[position()=last()]"/>
+ <eval expected="500000" xpath="//pageViewport[2]//flow/block[1]/@ipd"/>
+ <eval expected="500000" xpath="//pageViewport[2]//flow/block[1]/lineArea[1]/@ipd"/>
+ <eval expected="seen" xpath="//pageViewport[2]//flow/block[1]/lineArea[1]/text/word[1]"/>
+ <eval expected="500000" xpath="//pageViewport[2]//flow/block[2]/@ipd"/>
+ <eval expected="500000" xpath="//pageViewport[2]//flow/block[2]/lineArea[1]/@ipd"/>
+ <eval expected="500000" xpath="//pageViewport[2]//flow/block[3]/@ipd"/>
+ <eval expected="500000" xpath="//pageViewport[2]//flow/block[3]/lineArea[1]/@ipd"/>
+ </checks>
+</testcase>
diff --git a/test/layoutengine/standard-testcases/flow_changing-ipd_3.xml b/test/layoutengine/standard-testcases/flow_changing-ipd_3.xml
new file mode 100644
index 000000000..2badfe71e
--- /dev/null
+++ b/test/layoutengine/standard-testcases/flow_changing-ipd_3.xml
@@ -0,0 +1,86 @@
+<?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 that a change of IPD between two blocks is correctly handled.
+ </p>
+ </info>
+ <fo>
+ <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
+ <fo:layout-master-set>
+ <fo:simple-page-master master-name="narrow"
+ page-height="300pt" page-width="400pt" margin="50pt">
+ <fo:region-body background-color="#F0F0F0"/>
+ </fo:simple-page-master>
+ <fo:simple-page-master master-name="wide"
+ page-height="300pt" page-width="600pt" margin="50pt">
+ <fo:region-body background-color="#F0F0F0"/>
+ </fo:simple-page-master>
+ <fo:page-sequence-master master-name="pages">
+ <fo:single-page-master-reference master-reference="narrow"/>
+ <fo:repeatable-page-master-reference master-reference="wide"/>
+ </fo:page-sequence-master>
+ </fo:layout-master-set>
+ <fo:page-sequence master-reference="pages">
+ <fo:flow flow-name="xsl-region-body">
+ <fo:block text-align="justify" id="surrounding"
+ space-before.minimum="10pt"
+ space-before.optimum="12pt"
+ space-before.maximum="50pt">
+ <fo:block space-before="inherit" id="b1">In olden times when wishing still helped one,
+ there lived a king whose daughters were all beautiful, but the youngest was so
+ beautiful that the sun itself, which has seen so much, was astonished whenever it
+ shone in her face.</fo:block>
+ <fo:block space-before="inherit" id="b2">In olden times when wishing still helped one,
+ there lived a king whose daughters were all beautiful, but the youngest was so
+ beautiful that the sun itself, which has seen so much, was astonished whenever it
+ shone in her face.</fo:block>
+ <fo:block space-before="inherit" id="b3">In olden times when wishing still helped one,
+ there lived a king whose daughters were all beautiful, but the youngest was so
+ beautiful that the sun itself, which has seen so much, was astonished whenever it
+ shone in her face.</fo:block>
+ <fo:block border-top="1pt solid black" space-before.minimum="10pt"
+ space-before.optimum="12pt" space-before.maximum="50pt"
+ space-before.conditionality="retain" id="b4">In olden times when wishing still helped
+ one, there lived a king whose daughters were all beautiful, but the youngest was so
+ beautiful that the sun itself, which has seen so much, was astonished whenever it
+ shone in her face.</fo:block>
+ <fo:block space-before="inherit" id="b5">In olden times when wishing still helped one,
+ there lived a king whose daughters were all beautiful, but the youngest was so
+ beautiful that the sun itself, which has seen so much, was astonished whenever it
+ shone in her face.</fo:block>
+ </fo:block>
+ </fo:flow>
+ </fo:page-sequence>
+ </fo:root>
+ </fo>
+ <checks>
+ <eval expected="face." xpath="//pageViewport[1]//flow/block/block[3]/lineArea[4]/text/word[position()=last()]"/>
+ <eval expected="12000" xpath="//pageViewport[2]//flow/block/block[1]/@space-before"/>
+ <eval expected="500000" xpath="//pageViewport[2]//flow/block/block[1]/@ipd"/>
+ <eval expected="500000" xpath="//pageViewport[2]//flow/block/block[1]/lineArea[1]/@ipd"/>
+ <eval expected="(solid,#000000,1000)"
+ xpath="//pageViewport[2]//flow/block/block[1]/@border-before"/>
+ <eval expected="In" xpath="//pageViewport[2]//flow/block/block[1]/lineArea[1]/text/word[1]"/>
+ <eval expected="olden" xpath="//pageViewport[2]//flow/block/block[1]/lineArea[1]/text/word[2]"/>
+ <eval expected="500000" xpath="//pageViewport[2]//flow/block/block[2]/@ipd"/>
+ <eval expected="500000" xpath="//pageViewport[2]//flow/block/block[2]/lineArea[1]/@ipd"/>
+ </checks>
+</testcase>
diff --git a/test/layoutengine/standard-testcases/flow_changing-ipd_4.xml b/test/layoutengine/standard-testcases/flow_changing-ipd_4.xml
new file mode 100644
index 000000000..fe166d05c
--- /dev/null
+++ b/test/layoutengine/standard-testcases/flow_changing-ipd_4.xml
@@ -0,0 +1,159 @@
+<?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 that non-restartable elements still show up at IPD change, even if not
+ re-laid out.
+ </p>
+ </info>
+ <fo>
+ <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
+ <fo:layout-master-set>
+ <fo:simple-page-master master-name="narrow"
+ page-height="300pt" page-width="400pt" margin="50pt">
+ <fo:region-body background-color="#F0F0F0"/>
+ </fo:simple-page-master>
+ <fo:simple-page-master master-name="wide"
+ page-height="300pt" page-width="600pt" margin="50pt">
+ <fo:region-body background-color="#F0F0F0"/>
+ </fo:simple-page-master>
+ <fo:page-sequence-master master-name="pages">
+ <fo:single-page-master-reference master-reference="narrow"/>
+ <fo:repeatable-page-master-reference master-reference="wide"/>
+ </fo:page-sequence-master>
+ </fo:layout-master-set>
+ <fo:page-sequence master-reference="pages">
+ <fo:flow flow-name="xsl-region-body" text-align="justify">
+ <fo:block space-before="10pt" id="b1_1">In olden times when wishing still helped one, there
+ lived a king whose daughters were all beautiful, but the youngest was so beautiful that
+ the sun itself, which has seen so much, was astonished whenever it shone in her
+ face.</fo:block>
+ <fo:block space-before="10pt" id="b1_2">In olden times when wishing still helped one, there
+ lived a king whose daughters were all beautiful, but the youngest was so beautiful that
+ the sun itself, which has seen so much, was astonished whenever it shone in her
+ face.</fo:block>
+ <fo:table table-layout="fixed" width="100%" border="1pt solid black" space-before="10pt"
+ padding="2pt" border-collapse="separate">
+ <fo:table-body>
+ <fo:table-row>
+ <fo:table-cell>
+ <fo:block space-before="10pt" id="b1_3">In olden times when wishing still helped
+ one, there lived a king whose daughters were all beautiful, but the youngest was
+ so beautiful that the sun itself, which has seen so much, was astonished
+ whenever it shone in her face.</fo:block>
+ <fo:block space-before="10pt" id="b1_4">In olden times when wishing still helped
+ one, there lived a king whose daughters were all beautiful, but the youngest was
+ so beautiful that the sun itself, which has seen so much, was astonished
+ whenever it shone in her face.</fo:block>
+ </fo:table-cell>
+ </fo:table-row>
+ </fo:table-body>
+ </fo:table>
+ <fo:block space-before="10pt" id="b1_5" border-top="1pt solid red">In olden times when
+ wishing still helped one, there lived a king whose daughters were all beautiful, but the
+ youngest was so beautiful that the sun itself, which has seen so much, was astonished
+ whenever it shone in her face.</fo:block>
+ <fo:block space-before="10pt" id="b1_6">In olden times when wishing still helped one, there
+ lived a king whose daughters were all beautiful, but the youngest was so beautiful that
+ the sun itself, which has seen so much, was astonished whenever it shone in her
+ face.</fo:block>
+ </fo:flow>
+ </fo:page-sequence>
+ <fo:page-sequence master-reference="pages">
+ <fo:flow flow-name="xsl-region-body" text-align="justify">
+ <fo:block space-before="10pt" id="b2_1">In olden times when wishing still helped one, there
+ lived a king whose daughters were all beautiful, but the youngest was so beautiful that
+ the sun itself, which has seen so much, was astonished whenever it shone in her
+ face.</fo:block>
+ <fo:block space-before="10pt" id="b2_2">In olden times when wishing still helped one, there
+ lived a king whose daughters were all beautiful, but the youngest was so beautiful that
+ the sun itself, which has seen so much, was astonished whenever it shone in her
+ face.</fo:block>
+ <fo:list-block space-before="10pt" provisional-distance-between-starts="0.5cm">
+ <fo:list-item>
+ <fo:list-item-label end-indent="label-end()">
+ <fo:block start-indent="2pt">•</fo:block>
+ </fo:list-item-label>
+ <fo:list-item-body start-indent="body-start()">
+ <fo:block space-before="10pt" id="b2_3">In olden times when wishing still helped
+ one, there lived a king whose daughters were all beautiful, but the youngest was
+ so beautiful that the sun itself, which has seen so much, was
+ astonished…</fo:block>
+ </fo:list-item-body>
+ </fo:list-item>
+ <fo:list-item>
+ <fo:list-item-label end-indent="label-end()">
+ <fo:block start-indent="2pt">•</fo:block>
+ </fo:list-item-label>
+ <fo:list-item-body start-indent="body-start()">
+ <fo:block id="b2_4">In olden times when wishing still helped one, there lived a king
+ whose daughters were all beautiful, but the youngest was so beautiful that the sun
+ itself, which has seen so much, was astonished…</fo:block>
+ </fo:list-item-body>
+ </fo:list-item>
+ </fo:list-block>
+ <fo:block space-before="10pt" space-before.conditionality="retain" border-top="1pt solid
+ red" id="b2_5">In olden times when wishing still helped one, there lived a king whose
+ daughters were all beautiful, but the youngest was so beautiful that the sun itself,
+ which has seen so much, was astonished whenever it shone in her face.</fo:block>
+ <fo:block space-before="10pt" id="b2_6">In olden times when wishing still helped one, there
+ lived a king whose daughters were all beautiful, but the youngest was so beautiful that
+ the sun itself, which has seen so much, was astonished whenever it shone in her
+ face.</fo:block>
+ </fo:flow>
+ </fo:page-sequence>
+ </fo:root>
+ </fo>
+ <checks>
+ <!-- First page sequence – table -->
+ <eval expected="(solid,#000000,1000)"
+ xpath="//pageSequence[1]/pageViewport[2]//flow/block[1]/@border-after"/>
+ <eval expected="300000" xpath="//pageSequence[1]/pageViewport[2]//flow/block[1]//lineArea[1]/@ipd"/>
+ <eval expected="b1_4" xpath="//pageSequence[1]/pageViewport[2]//flow/block[1]/block/block/@prod-id"/>
+ <eval expected="In" xpath="//pageSequence[1]/pageViewport[2]//flow/block[1]//lineArea[1]/text/word[1]"/>
+ <eval expected="olden" xpath="//pageSequence[1]/pageViewport[2]//flow/block[1]//lineArea[1]/text/word[2]"/>
+ <eval expected="her" xpath="//pageSequence[1]/pageViewport[2]//flow/block[1]//lineArea[4]/text/word[position()=last()-1]"/>
+ <eval expected="face." xpath="//pageSequence[1]/pageViewport[2]//flow/block[1]//lineArea[4]/text/word[position()=last()]"/>
+
+ <eval expected="b1_5" xpath="//pageSequence[1]/pageViewport[2]//flow/block[2]/@prod-id"/>
+ <eval expected="500000" xpath="//pageSequence[1]/pageViewport[2]//flow/block[2]/@ipd"/>
+ <eval expected="(solid,#ff0000,1000)"
+ xpath="//pageSequence[1]/pageViewport[2]//flow/block[2]/@border-before"/>
+ <eval expected="In" xpath="//pageSequence[1]/pageViewport[2]//flow/block[2]//lineArea[1]/text/word[1]"/>
+ <eval expected="olden" xpath="//pageSequence[1]/pageViewport[2]//flow/block[2]//lineArea[1]/text/word[2]"/>
+
+ <!-- Second page sequence – list -->
+ <eval expected="300000" xpath="//pageSequence[2]/pageViewport[2]//flow/block[1]/@ipd"/>
+ <eval expected="b2_4" xpath="//pageSequence[2]/pageViewport[2]//flow/block[1]/block/block[2]/block/@prod-id"/>
+ <eval expected="In" xpath="//pageSequence[2]/pageViewport[2]//flow/block[1]/block/block[2]/block/lineArea[1]/text/word[1]"/>
+ <eval expected="olden" xpath="//pageSequence[2]/pageViewport[2]//flow/block[1]/block/block[2]/block/lineArea[1]/text/word[2]"/>
+ <eval expected="was" xpath="//pageSequence[2]/pageViewport[2]//flow/block[1]/block/block[2]/block/lineArea[4]/text/word[position()=last()-1]"/>
+ <eval expected="astonished…"
+ xpath="//pageSequence[2]/pageViewport[2]//flow/block[1]/block/block[2]/block/lineArea[4]/text/word[position()=last()]"/>
+
+ <eval expected="b2_5" xpath="//pageSequence[2]/pageViewport[2]//flow/block[2]/@prod-id"/>
+ <eval expected="500000" xpath="//pageSequence[2]/pageViewport[2]//flow/block[2]/@ipd"/>
+ <eval expected="10000" xpath="//pageSequence[2]/pageViewport[2]//flow/block[2]/@space-before"/>
+ <eval expected="(solid,#ff0000,1000)"
+ xpath="//pageSequence[2]/pageViewport[2]//flow/block[2]/@border-before"/>
+ <eval expected="In" xpath="//pageSequence[2]/pageViewport[2]//flow/block[2]//lineArea[1]/text/word[1]"/>
+ <eval expected="olden" xpath="//pageSequence[2]/pageViewport[2]//flow/block[2]//lineArea[1]/text/word[2]"/>
+ </checks>
+</testcase>
diff --git a/test/layoutengine/standard-testcases/flow_changing-ipd_block-container_1.xml b/test/layoutengine/standard-testcases/flow_changing-ipd_block-container_1.xml
new file mode 100644
index 000000000..82b757d46
--- /dev/null
+++ b/test/layoutengine/standard-testcases/flow_changing-ipd_block-container_1.xml
@@ -0,0 +1,101 @@
+<?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 that block-container elements correctly support an IPD change.
+ </p>
+ <!-- NOTE: This test case is a copy of flow_changing-ipd_1.xml, modified to simply surround
+ block 3 with a block-container. -->
+ </info>
+ <fo>
+ <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
+ <fo:layout-master-set>
+ <fo:simple-page-master master-name="narrow"
+ page-height="300pt" page-width="400pt" margin="50pt">
+ <fo:region-body background-color="#F0F0F0"/>
+ </fo:simple-page-master>
+ <fo:simple-page-master master-name="wide"
+ page-height="300pt" page-width="600pt" margin="50pt">
+ <fo:region-body background-color="#F0F0F0"/>
+ </fo:simple-page-master>
+ <fo:page-sequence-master master-name="pages">
+ <fo:single-page-master-reference master-reference="narrow"/>
+ <fo:repeatable-page-master-reference master-reference="wide"/>
+ </fo:page-sequence-master>
+ </fo:layout-master-set>
+ <fo:page-sequence master-reference="pages">
+ <fo:flow flow-name="xsl-region-body">
+ <fo:block text-align="justify" id="surrounding"
+ space-before.minimum="10pt"
+ space-before.optimum="12pt"
+ space-before.maximum="50pt">
+ <fo:block space-before="inherit" id="b1">In olden times when wishing still helped one,
+ there lived a king whose daughters were all beautiful, but the youngest was so
+ beautiful that the sun itself, which has seen so much, was astonished whenever it
+ shone in her face.</fo:block>
+ <fo:block space-before="inherit" id="b2">In olden times when wishing still helped one,
+ there lived a king whose daughters were all beautiful, but the youngest was so
+ beautiful that the sun itself, which has seen so much, was astonished whenever it
+ shone in her face.</fo:block>
+ <fo:block-container space-before="inherit">
+ <fo:block id="b3" border-top="1pt solid black"
+ border-before-width.conditionality="retain">In olden times when wishing still helped
+ one, there lived a king whose daughters were all beautiful, but the youngest was so
+ beautiful that the sun itself, which has seen so much, was astonished whenever it
+ shone in her face. In olden times when wishing still helped one, there lived a king
+ whose daughters were all beautiful, but the youngest was so beautiful that the sun
+ itself, which has seen so much, was astonished whenever it shone in her
+ face.</fo:block>
+ </fo:block-container>
+ <fo:block space-before="inherit" id="b4" border-top="1pt solid black">In olden times
+ when wishing still helped one, there lived a king whose daughters were all beautiful,
+ but the youngest was so beautiful that the sun itself, which has seen so much, was
+ astonished whenever it shone in her face.</fo:block>
+ <fo:block space-before="inherit" id="b5">In olden times when wishing still helped one,
+ there lived a king whose daughters were all beautiful, but the youngest was so
+ beautiful that the sun itself, which has seen so much, was astonished whenever it
+ shone in her face.</fo:block>
+ </fo:block>
+ </fo:flow>
+ </fo:page-sequence>
+ </fo:root>
+ </fo>
+ <checks>
+ <eval expected="13100" xpath="//pageViewport[1]//flow/block/block[2]/@space-before"/>
+ <eval expected="13100" xpath="//pageViewport[1]//flow/block/block[3]/@space-before"/>
+ <eval expected="(solid,#000000,1000)"
+ xpath="//pageViewport[1]//flow/block/block[3]/block/block/@border-before"/>
+ <eval expected="In" xpath="//pageViewport[1]//flow/block/block[3]/block/block/lineArea[4]/text/word[position()=last()]"/>
+ <eval expected="500000" xpath="//pageViewport[2]//flow/block/@ipd"/>
+ <eval expected="(solid,#000000,1000)"
+ xpath="//pageViewport[2]//flow/block/block[1]/block/block/@border-before"/>
+ <eval expected="500000" xpath="//pageViewport[2]//flow/block/block[1]/block/block/@ipd"/>
+ <eval expected="500000" xpath="//pageViewport[2]//flow/block/block[1]/block/block/lineArea[1]/@ipd"/>
+ <eval expected="olden" xpath="//pageViewport[2]//flow/block/block[1]/block/block/lineArea[1]/text/word[1]"/>
+ <eval expected="500000" xpath="//pageViewport[2]//flow/block/block[2]/@ipd"/>
+ <eval expected="12000" xpath="//pageViewport[2]//flow/block/block[2]/@space-before"/>
+ <eval expected="(solid,#000000,1000)"
+ xpath="//pageViewport[2]//flow/block/block[2]/@border-before"/>
+ <eval expected="500000" xpath="//pageViewport[2]//flow/block/block[2]/lineArea[1]/@ipd"/>
+ <eval expected="500000" xpath="//pageViewport[2]//flow/block/block[3]/@ipd"/>
+ <eval expected="12000" xpath="//pageViewport[2]//flow/block/block[3]/@space-before"/>
+ <eval expected="500000" xpath="//pageViewport[2]//flow/block/block[3]/lineArea[1]/@ipd"/>
+ </checks>
+</testcase>
diff --git a/test/layoutengine/standard-testcases/flow_changing-ipd_block-container_2.xml b/test/layoutengine/standard-testcases/flow_changing-ipd_block-container_2.xml
new file mode 100644
index 000000000..7a2bb9b19
--- /dev/null
+++ b/test/layoutengine/standard-testcases/flow_changing-ipd_block-container_2.xml
@@ -0,0 +1,89 @@
+<?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 that a change of IPD between two blocks surrounded by a block-container is
+ correctly handled.
+ </p>
+ <!-- NOTE: This test case is a copy of flow_changing-ipd_3.xml, with the surrounding block
+ replaced with a block-container. -->
+ </info>
+ <fo>
+ <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
+ <fo:layout-master-set>
+ <fo:simple-page-master master-name="narrow"
+ page-height="300pt" page-width="400pt" margin="50pt">
+ <fo:region-body background-color="#F0F0F0"/>
+ </fo:simple-page-master>
+ <fo:simple-page-master master-name="wide"
+ page-height="300pt" page-width="600pt" margin="50pt">
+ <fo:region-body background-color="#F0F0F0"/>
+ </fo:simple-page-master>
+ <fo:page-sequence-master master-name="pages">
+ <fo:single-page-master-reference master-reference="narrow"/>
+ <fo:repeatable-page-master-reference master-reference="wide"/>
+ </fo:page-sequence-master>
+ </fo:layout-master-set>
+ <fo:page-sequence master-reference="pages">
+ <fo:flow flow-name="xsl-region-body">
+ <fo:block-container text-align="justify" id="surrounding"
+ space-before.minimum="10pt"
+ space-before.optimum="12pt"
+ space-before.maximum="50pt">
+ <fo:block space-before="inherit" id="b1">In olden times when wishing still helped one,
+ there lived a king whose daughters were all beautiful, but the youngest was so
+ beautiful that the sun itself, which has seen so much, was astonished whenever it
+ shone in her face.</fo:block>
+ <fo:block space-before="inherit" id="b2">In olden times when wishing still helped one,
+ there lived a king whose daughters were all beautiful, but the youngest was so
+ beautiful that the sun itself, which has seen so much, was astonished whenever it
+ shone in her face.</fo:block>
+ <fo:block space-before="inherit" id="b3">In olden times when wishing still helped one,
+ there lived a king whose daughters were all beautiful, but the youngest was so
+ beautiful that the sun itself, which has seen so much, was astonished whenever it
+ shone in her face.</fo:block>
+ <fo:block border-top="1pt solid black" space-before.minimum="10pt"
+ space-before.optimum="12pt" space-before.maximum="50pt"
+ space-before.conditionality="retain" id="b4">In olden times when wishing still helped
+ one, there lived a king whose daughters were all beautiful, but the youngest was so
+ beautiful that the sun itself, which has seen so much, was astonished whenever it
+ shone in her face.</fo:block>
+ <fo:block space-before="inherit" id="b5">In olden times when wishing still helped one,
+ there lived a king whose daughters were all beautiful, but the youngest was so
+ beautiful that the sun itself, which has seen so much, was astonished whenever it
+ shone in her face.</fo:block>
+ </fo:block-container>
+ </fo:flow>
+ </fo:page-sequence>
+ </fo:root>
+ </fo>
+ <checks>
+ <eval expected="face." xpath="//pageViewport[1]//flow/block/block/block[3]/lineArea[4]/text/word[position()=last()]"/>
+ <eval expected="12000" xpath="//pageViewport[2]//flow/block/block/block[1]/@space-before"/>
+ <eval expected="500000" xpath="//pageViewport[2]//flow/block/block/block[1]/@ipd"/>
+ <eval expected="500000" xpath="//pageViewport[2]//flow/block/block/block[1]/lineArea[1]/@ipd"/>
+ <eval expected="(solid,#000000,1000)"
+ xpath="//pageViewport[2]//flow/block/block/block[1]/@border-before"/>
+ <eval expected="In" xpath="//pageViewport[2]//flow/block/block/block[1]/lineArea[1]/text/word[1]"/>
+ <eval expected="olden" xpath="//pageViewport[2]//flow/block/block/block[1]/lineArea[1]/text/word[2]"/>
+ <eval expected="500000" xpath="//pageViewport[2]//flow/block/block/block[2]/@ipd"/>
+ <eval expected="500000" xpath="//pageViewport[2]//flow/block/block/block[2]/lineArea[1]/@ipd"/>
+ </checks>
+</testcase>