aboutsummaryrefslogtreecommitdiffstats
path: root/src/java/org/apache/fop
diff options
context:
space:
mode:
Diffstat (limited to 'src/java/org/apache/fop')
-rw-r--r--src/java/org/apache/fop/area/Area.java16
-rw-r--r--src/java/org/apache/fop/area/Block.java16
-rw-r--r--src/java/org/apache/fop/area/BlockParent.java21
-rw-r--r--src/java/org/apache/fop/area/BlockViewport.java4
-rw-r--r--src/java/org/apache/fop/area/LineArea.java14
-rw-r--r--src/java/org/apache/fop/area/SideFloat.java31
-rw-r--r--src/java/org/apache/fop/area/inline/InlineViewport.java3
-rw-r--r--src/java/org/apache/fop/area/inline/TextArea.java3
-rw-r--r--src/java/org/apache/fop/fo/XMLWhiteSpaceHandler.java8
-rw-r--r--src/java/org/apache/fop/fo/flow/Float.java45
-rw-r--r--src/java/org/apache/fop/layoutmgr/AbstractBreaker.java67
-rw-r--r--src/java/org/apache/fop/layoutmgr/AbstractLayoutManager.java7
-rw-r--r--src/java/org/apache/fop/layoutmgr/BreakingAlgorithm.java33
-rw-r--r--src/java/org/apache/fop/layoutmgr/FloatContentLayoutManager.java141
-rw-r--r--src/java/org/apache/fop/layoutmgr/FlowLayoutManager.java22
-rw-r--r--src/java/org/apache/fop/layoutmgr/KnuthBlockBox.java20
-rw-r--r--src/java/org/apache/fop/layoutmgr/LayoutManagerMapping.java13
-rw-r--r--src/java/org/apache/fop/layoutmgr/PageBreaker.java282
-rw-r--r--src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java161
-rw-r--r--src/java/org/apache/fop/layoutmgr/PageSequenceLayoutManager.java64
-rw-r--r--src/java/org/apache/fop/layoutmgr/SpaceResolver.java2
-rw-r--r--src/java/org/apache/fop/layoutmgr/inline/FloatLayoutManager.java98
-rw-r--r--src/java/org/apache/fop/layoutmgr/inline/KnuthInlineBox.java16
-rw-r--r--src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java43
-rw-r--r--src/java/org/apache/fop/layoutmgr/list/ListBlockLayoutManager.java12
-rw-r--r--src/java/org/apache/fop/layoutmgr/list/ListItemContentLayoutManager.java11
-rw-r--r--src/java/org/apache/fop/layoutmgr/list/ListItemLayoutManager.java143
27 files changed, 1196 insertions, 100 deletions
diff --git a/src/java/org/apache/fop/area/Area.java b/src/java/org/apache/fop/area/Area.java
index 628e9e3ad..895367c19 100644
--- a/src/java/org/apache/fop/area/Area.java
+++ b/src/java/org/apache/fop/area/Area.java
@@ -111,6 +111,8 @@ public class Area extends AreaTreeObject implements Serializable {
/** the area's block-progression-dimension */
protected int bpd;
+ protected int effectiveIPD = -1;
+
/**
* Resolved bidirectional level for area.
*/
@@ -208,6 +210,10 @@ public class Area extends AreaTreeObject implements Serializable {
return getBorderAndPaddingWidthStart() + getIPD() + getBorderAndPaddingWidthEnd();
}
+ public int getEffectiveAllocIPD() {
+ return getBorderAndPaddingWidthStart() + getEffectiveIPD() + getBorderAndPaddingWidthEnd();
+ }
+
/**
* Get the allocation block progression dimension of this area.
* This adds the content, borders, padding and spaces to find the
@@ -499,4 +505,14 @@ public class Area extends AreaTreeObject implements Serializable {
sb.append("}");
return sb.toString();
}
+
+ public int getEffectiveIPD() {
+ return 0;
+ }
+
+ public void activateEffectiveIPD() {
+ if (effectiveIPD != -1) {
+ ipd = effectiveIPD;
+ }
+ }
}
diff --git a/src/java/org/apache/fop/area/Block.java b/src/java/org/apache/fop/area/Block.java
index e04a5dc43..565146415 100644
--- a/src/java/org/apache/fop/area/Block.java
+++ b/src/java/org/apache/fop/area/Block.java
@@ -184,5 +184,21 @@ public class Block extends BlockParent {
return location;
}
+ // maybe this can be done in the parent?
+ public int getEffectiveIPD() {
+ int eIPD = super.getEffectiveIPD();
+ if (eIPD != 0) {
+ effectiveIPD = eIPD;
+ }
+ return eIPD;
+ }
+
+ // maybe this can be done in the parent?
+ public void activateEffectiveIPD() {
+ super.activateEffectiveIPD();
+ if (effectiveIPD != -1) {
+ ipd = effectiveIPD;
+ }
+ }
}
diff --git a/src/java/org/apache/fop/area/BlockParent.java b/src/java/org/apache/fop/area/BlockParent.java
index 72baaeccf..fa599f31a 100644
--- a/src/java/org/apache/fop/area/BlockParent.java
+++ b/src/java/org/apache/fop/area/BlockParent.java
@@ -123,4 +123,25 @@ public class BlockParent extends Area {
public int getYOffset() {
return yOffset;
}
+
+ public int getEffectiveIPD() {
+ int maxIPD = 0;
+ if (children != null) {
+ for (Area area : children) {
+ int effectiveIPD = area.getEffectiveIPD();
+ if (effectiveIPD > maxIPD) {
+ maxIPD = effectiveIPD;
+ }
+ }
+ }
+ return maxIPD;
+ }
+
+ public void activateEffectiveIPD() {
+ if (children != null) {
+ for (Area area : children) {
+ area.activateEffectiveIPD();
+ }
+ }
+ }
}
diff --git a/src/java/org/apache/fop/area/BlockViewport.java b/src/java/org/apache/fop/area/BlockViewport.java
index 58d8d2106..d33a060e4 100644
--- a/src/java/org/apache/fop/area/BlockViewport.java
+++ b/src/java/org/apache/fop/area/BlockViewport.java
@@ -93,5 +93,9 @@ public class BlockViewport extends Block implements Viewport {
return null;
}
}
+
+ public int getEffectiveIPD() {
+ return getIPD();
+ }
}
diff --git a/src/java/org/apache/fop/area/LineArea.java b/src/java/org/apache/fop/area/LineArea.java
index 3213eb588..8639b8201 100644
--- a/src/java/org/apache/fop/area/LineArea.java
+++ b/src/java/org/apache/fop/area/LineArea.java
@@ -283,5 +283,19 @@ public class LineArea extends Area {
// been handled, modifying the line indent
}
}
+
+ public int getEffectiveIPD() {
+ int maxIPD = 0;
+ if (inlineAreas != null) {
+ for (Area area : inlineAreas) {
+ int effectiveIPD = area.getEffectiveIPD();
+ if (effectiveIPD > maxIPD) {
+ maxIPD = effectiveIPD;
+ }
+ }
+ }
+ return maxIPD;
+ }
+
}
diff --git a/src/java/org/apache/fop/area/SideFloat.java b/src/java/org/apache/fop/area/SideFloat.java
new file mode 100644
index 000000000..af653efbf
--- /dev/null
+++ b/src/java/org/apache/fop/area/SideFloat.java
@@ -0,0 +1,31 @@
+/*
+ * 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$ */
+
+package org.apache.fop.area;
+
+public class SideFloat extends Block {
+
+ private static final long serialVersionUID = 2058594336594375047L;
+
+ public SideFloat() {
+ setAreaClass(Area.CLASS_SIDE_FLOAT);
+ addTrait(Trait.IS_REFERENCE_AREA, Boolean.TRUE);
+ setPositioning(Block.ABSOLUTE);
+ }
+}
diff --git a/src/java/org/apache/fop/area/inline/InlineViewport.java b/src/java/org/apache/fop/area/inline/InlineViewport.java
index 32c4c1235..e111bdd9d 100644
--- a/src/java/org/apache/fop/area/inline/InlineViewport.java
+++ b/src/java/org/apache/fop/area/inline/InlineViewport.java
@@ -149,4 +149,7 @@ public class InlineViewport extends InlineArea implements Viewport {
this.content = (Area) in.readObject();
}
+ public int getEffectiveIPD() {
+ return getIPD();
+ }
}
diff --git a/src/java/org/apache/fop/area/inline/TextArea.java b/src/java/org/apache/fop/area/inline/TextArea.java
index a8d07148f..91a75d558 100644
--- a/src/java/org/apache/fop/area/inline/TextArea.java
+++ b/src/java/org/apache/fop/area/inline/TextArea.java
@@ -209,5 +209,8 @@ public class TextArea extends AbstractTextArea {
}
}
+ public int getEffectiveIPD() {
+ return getIPD();
+ }
}
diff --git a/src/java/org/apache/fop/fo/XMLWhiteSpaceHandler.java b/src/java/org/apache/fop/fo/XMLWhiteSpaceHandler.java
index e37618736..cc06ca26a 100644
--- a/src/java/org/apache/fop/fo/XMLWhiteSpaceHandler.java
+++ b/src/java/org/apache/fop/fo/XMLWhiteSpaceHandler.java
@@ -23,6 +23,7 @@ import java.util.List;
import java.util.Stack;
import org.apache.fop.fo.flow.Block;
+import org.apache.fop.fo.flow.Float;
import org.apache.fop.util.CharUtilities;
/**
@@ -157,6 +158,10 @@ public class XMLWhiteSpaceHandler {
charIter = new RecursiveCharIterator(fo, firstTextNode);
inWhiteSpace = false;
+ if (firstTextNode.siblings != null && firstTextNode.siblings[0] != null
+ && firstTextNode.siblings[0].getNameId() == Constants.FO_FLOAT) {
+ inWhiteSpace = ((Float) firstTextNode.siblings[0]).getInWhiteSpace();
+ }
if (fo == currentBlock
|| currentBlock == null
@@ -232,6 +237,9 @@ public class XMLWhiteSpaceHandler {
firstWhiteSpaceInSeq = null;
}
}
+ if (nextChild instanceof Float) {
+ ((Float) nextChild).setInWhiteSpace(inWhiteSpace);
+ }
}
/**
diff --git a/src/java/org/apache/fop/fo/flow/Float.java b/src/java/org/apache/fop/fo/flow/Float.java
index 3fb273042..a10d9c74d 100644
--- a/src/java/org/apache/fop/fo/flow/Float.java
+++ b/src/java/org/apache/fop/fo/flow/Float.java
@@ -20,6 +20,7 @@
package org.apache.fop.fo.flow;
// XML
+import org.xml.sax.Attributes;
import org.xml.sax.Locator;
import org.apache.fop.apps.FOPException;
@@ -34,11 +35,11 @@ import org.apache.fop.fo.ValidationException;
*/
public class Float extends FObj {
// The value of properties relevant for fo:float (commented out for performance.
- // private int float_;
- // private int clear;
+ private int foFloat;
+ private int clear;
// End of property values
-
- private static boolean notImplementedWarningGiven;
+ private boolean inWhiteSpace;
+ private boolean disabled;
/**
* Base constructor
@@ -47,17 +48,13 @@ public class Float extends FObj {
*/
public Float(FONode parent) {
super(parent);
-
- if (!notImplementedWarningGiven) {
- getFOValidationEventProducer().unimplementedFeature(this, getName(),
- getName(), getLocator());
- notImplementedWarningGiven = true;
- }
}
/** {@inheritDoc} */
public void bind(PropertyList pList) throws FOPException {
- // No active properties -> Nothing to do.
+ super.bind(pList);
+ foFloat = pList.get(PR_FLOAT).getEnum();
+ clear = pList.get(PR_CLEAR).getEnum();
}
/**
@@ -92,4 +89,30 @@ public class Float extends FObj {
public int getNameId() {
return FO_FLOAT;
}
+
+ public int getFloat() {
+ return foFloat;
+ }
+
+ public void setInWhiteSpace(boolean iws) {
+ inWhiteSpace = iws;
+ }
+
+ public boolean getInWhiteSpace() {
+ return inWhiteSpace;
+ }
+
+ public void processNode(String elementName, Locator locator, Attributes attlist, PropertyList pList)
+ throws FOPException {
+ if (findAncestor(FO_TABLE) > 0) {
+ disabled = true;
+ getFOValidationEventProducer().unimplementedFeature(this, "fo:table", getName(), getLocator());
+ } else {
+ super.processNode(elementName, locator, attlist, pList);
+ }
+ }
+
+ public boolean isDisabled() {
+ return disabled;
+ }
}
diff --git a/src/java/org/apache/fop/layoutmgr/AbstractBreaker.java b/src/java/org/apache/fop/layoutmgr/AbstractBreaker.java
index cdfa48295..e1c6b3a74 100644
--- a/src/java/org/apache/fop/layoutmgr/AbstractBreaker.java
+++ b/src/java/org/apache/fop/layoutmgr/AbstractBreaker.java
@@ -67,6 +67,17 @@ public abstract class AbstractBreaker {
}
}
+ public static class FloatPosition extends LeafPosition {
+ double bpdAdjust; // Percentage to adjust (stretch or shrink)
+ int difference;
+
+ FloatPosition(LayoutManager lm, int breakIndex, double bpdA, int diff) {
+ super(lm, breakIndex);
+ bpdAdjust = bpdA;
+ difference = diff;
+ }
+ }
+
/**
* Helper method, mainly used to improve debug/trace output
* @param breakClassId the {@link Constants} enum value.
@@ -195,9 +206,12 @@ public abstract class AbstractBreaker {
}
// used by doLayout and getNextBlockList*
- private List<BlockSequence> blockLists;
+ protected List<BlockSequence> blockLists;
private boolean empty = true;
+ /** blockListIndex of the current BlockSequence in blockLists */
+ protected int blockListIndex;
+
/** desired text alignment */
protected int alignment;
@@ -372,7 +386,7 @@ public abstract class AbstractBreaker {
//*** Phases 2 and 3 ***
log.debug("PLM> blockLists.size() = " + blockLists.size());
- for (int blockListIndex = 0; blockListIndex < blockLists.size(); blockListIndex++) {
+ for (blockListIndex = 0; blockListIndex < blockLists.size(); blockListIndex++) {
blockList = blockLists.get(blockListIndex);
//debug code start
@@ -394,7 +408,10 @@ public abstract class AbstractBreaker {
alg.setConstantLineWidth(flowBPD);
int optimalPageCount = alg.findBreakingPoints(blockList, 1, true,
BreakingAlgorithm.ALL_BREAKS);
- if (Math.abs(alg.getIPDdifference()) > 1) {
+
+ if (alg.handlingFloat()) {
+ nextSequenceStartsOn = handleFloatLayout(alg, optimalPageCount, blockList, childLC);
+ } else if (Math.abs(alg.getIPDdifference()) > 1) {
addAreas(alg, optimalPageCount, blockList, blockList);
// *** redo Phase 1 ***
log.trace("IPD changes after page " + optimalPageCount);
@@ -476,14 +493,14 @@ public abstract class AbstractBreaker {
for (int p = startPart; p < startPart + partCount; p++) {
PageBreakPosition pbp = alg.getPageBreaks().get(p);
- //Check the last break position for forced breaks
+ // Check the last break position for forced breaks
int lastBreakClass;
if (p == 0) {
lastBreakClass = effectiveList.getStartOn();
} else {
ListElement lastBreakElement = effectiveList.getElement(endElementIndex);
if (lastBreakElement.isPenalty()) {
- KnuthPenalty pen = (KnuthPenalty)lastBreakElement;
+ KnuthPenalty pen = (KnuthPenalty) lastBreakElement;
if (pen.getPenalty() == KnuthPenalty.INFINITE) {
/**
* That means that there was a keep.within-page="always", but that
@@ -500,14 +517,12 @@ public abstract class AbstractBreaker {
}
}
- //the end of the new part
+ // the end of the new part
endElementIndex = pbp.getLeafPos();
// ignore the first elements added by the
// PageSequenceLayoutManager
- startElementIndex += (startElementIndex == 0)
- ? effectiveList.ignoreAtStart
- : 0;
+ startElementIndex += (startElementIndex == 0) ? effectiveList.ignoreAtStart : 0;
log.debug("PLM> part: " + (p + 1)
+ ", start at pos " + startElementIndex
@@ -518,20 +533,17 @@ public abstract class AbstractBreaker {
int displayAlign = getCurrentDisplayAlign();
- //The following is needed by SpaceResolver.performConditionalsNotification()
- //further down as there may be important Position elements in the element list trailer
+ // The following is needed by SpaceResolver.performConditionalsNotification()
+ // further down as there may be important Position elements in the element list trailer
int notificationEndElementIndex = endElementIndex;
// ignore the last elements added by the
// PageSequenceLayoutManager
- endElementIndex -= (endElementIndex == (originalList.size() - 1))
- ? effectiveList.ignoreAtEnd
- : 0;
+ endElementIndex -= (endElementIndex == (originalList.size() - 1)) ? effectiveList.ignoreAtEnd : 0;
// ignore the last element in the page if it is a KnuthGlue
// object
- if (((KnuthElement) effectiveList.get(endElementIndex))
- .isGlue()) {
+ if (((KnuthElement) effectiveList.get(endElementIndex)).isGlue()) {
endElementIndex--;
}
@@ -556,13 +568,12 @@ public abstract class AbstractBreaker {
}
// Handle SpaceHandling(Break)Positions, see SpaceResolver!
- SpaceResolver.performConditionalsNotification(effectiveList,
- startElementIndex, notificationEndElementIndex, lastBreak);
+ SpaceResolver.performConditionalsNotification(effectiveList, startElementIndex,
+ notificationEndElementIndex, lastBreak);
// Add areas now!
- addAreas(new KnuthPossPosIter(effectiveList,
- startElementIndex, endElementIndex + 1), childLC);
+ addAreas(new KnuthPossPosIter(effectiveList, startElementIndex, endElementIndex + 1), childLC);
} else {
- //no content for this part
+ // no content for this part
handleEmptyContent();
}
@@ -571,6 +582,10 @@ public abstract class AbstractBreaker {
lastBreak = endElementIndex;
startElementIndex = pbp.getLeafPos() + 1;
}
+ if (alg.handlingFloat()) {
+ addAreasForFloats(alg, startPart, partCount, originalList, effectiveList, childLC, lastBreak,
+ startElementIndex, endElementIndex);
+ }
}
/**
* Notifies the layout managers about the space and conditional length situation based on
@@ -774,4 +789,14 @@ public abstract class AbstractBreaker {
return nextSequenceStartsOn;
}
+ protected int handleFloatLayout(PageBreakingAlgorithm alg, int optimalPageCount, BlockSequence blockList,
+ LayoutContext childLC) {
+ throw new IllegalStateException();
+ }
+
+ protected void addAreasForFloats(PageBreakingAlgorithm alg, int startPart, int partCount,
+ BlockSequence originalList, BlockSequence effectiveList, final LayoutContext childLC,
+ int lastBreak, int startElementIndex, int endElementIndex) {
+ throw new IllegalStateException();
+ }
}
diff --git a/src/java/org/apache/fop/layoutmgr/AbstractLayoutManager.java b/src/java/org/apache/fop/layoutmgr/AbstractLayoutManager.java
index 2dd18e4ee..5eac70548 100644
--- a/src/java/org/apache/fop/layoutmgr/AbstractLayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/AbstractLayoutManager.java
@@ -537,4 +537,11 @@ public abstract class AbstractLayoutManager extends AbstractBaseLayoutManager im
}
((AbstractLayoutManager) lm).possiblyRegisterMarkersForTables(markers, isStarting, isFirst, isLast);
}
+
+ public boolean handlingFloat() {
+ if (parentLayoutManager != null && parentLayoutManager instanceof AbstractLayoutManager) {
+ return ((AbstractLayoutManager) parentLayoutManager).handlingFloat();
+ }
+ return false;
+ }
}
diff --git a/src/java/org/apache/fop/layoutmgr/BreakingAlgorithm.java b/src/java/org/apache/fop/layoutmgr/BreakingAlgorithm.java
index d57588db8..e060226c4 100644
--- a/src/java/org/apache/fop/layoutmgr/BreakingAlgorithm.java
+++ b/src/java/org/apache/fop/layoutmgr/BreakingAlgorithm.java
@@ -558,6 +558,9 @@ public abstract class BreakingAlgorithm {
elementIndex, previousIsBox, allowedBreaks).isBox();
if (activeNodeCount == 0) {
+ if (handlingFloat()) {
+ return handleFloat();
+ }
if (getIPDdifference() != 0) {
return handleIpdChange();
}
@@ -945,8 +948,11 @@ public abstract class BreakingAlgorithm {
log.trace("\tline=" + line);
}
+ if (element.isForcedBreak() && handlingFloat()) {
+ disableFloatHandling(); // so that we do not create a float edge position later
+ }
// The line would be too long.
- if (r < -1 || element.isForcedBreak()) {
+ if (r < -1 || element.isForcedBreak() || handlingFloat()) {
deactivateNode(node, line);
}
@@ -1028,6 +1034,13 @@ public abstract class BreakingAlgorithm {
}
}
+ createForcedNodes(node, line, elementIdx, difference, r, demerits, fitnessClass, availableShrink,
+ availableStretch, newWidth, newStretch, newShrink);
+ }
+
+ protected void createForcedNodes(KnuthNode node, int line, int elementIdx, int difference, double r,
+ double demerits, int fitnessClass, int availableShrink, int availableStretch, int newWidth,
+ int newStretch, int newShrink) {
if (r <= -1) {
log.debug("Considering tooLong, demerits=" + demerits);
if (lastTooLong == null || demerits < lastTooLong.totalDemerits) {
@@ -1042,10 +1055,9 @@ public abstract class BreakingAlgorithm {
} else {
if (lastTooShort == null || demerits <= lastTooShort.totalDemerits) {
if (considerTooShort) {
- //consider possibilities which are too short
- best.addRecord(demerits, node, r,
- availableShrink, availableStretch,
- difference, fitnessClass);
+ // consider possibilities which are too short
+ best.addRecord(demerits, node, r, availableShrink, availableStretch, difference,
+ fitnessClass);
}
lastTooShort = createNode(elementIdx, line + 1, fitnessClass,
newWidth, newStretch, newShrink,
@@ -1451,4 +1463,15 @@ public abstract class BreakingAlgorithm {
return this.alignmentLast;
}
+ protected boolean handlingFloat() {
+ return false;
+ }
+
+ protected int handleFloat() {
+ throw new IllegalStateException();
+ }
+
+ protected void disableFloatHandling() {
+ throw new IllegalStateException();
+ }
}
diff --git a/src/java/org/apache/fop/layoutmgr/FloatContentLayoutManager.java b/src/java/org/apache/fop/layoutmgr/FloatContentLayoutManager.java
new file mode 100644
index 000000000..5c6f6c685
--- /dev/null
+++ b/src/java/org/apache/fop/layoutmgr/FloatContentLayoutManager.java
@@ -0,0 +1,141 @@
+/*
+ * 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$ */
+
+package org.apache.fop.layoutmgr;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.ListIterator;
+
+import org.apache.fop.area.Area;
+import org.apache.fop.area.SideFloat;
+import org.apache.fop.fo.Constants;
+import org.apache.fop.fo.flow.Float;
+import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
+import org.apache.fop.layoutmgr.inline.FloatLayoutManager;
+import org.apache.fop.layoutmgr.inline.KnuthInlineBox;
+
+public class FloatContentLayoutManager extends SpacedBorderedPaddedBlockLayoutManager {
+
+ private SideFloat floatContentArea;
+ private int side;
+ private int yOffset;
+
+ public FloatContentLayoutManager(Float node) {
+ super(node);
+ generatesReferenceArea = true;
+ side = node.getFloat();
+ }
+
+ public Keep getKeepTogether() {
+ return getParentKeepTogether();
+ }
+
+ public Keep getKeepWithNext() {
+ return Keep.KEEP_AUTO;
+ }
+
+ public Keep getKeepWithPrevious() {
+ return Keep.KEEP_ALWAYS;
+ }
+
+ public void addAreas(PositionIterator parentIter, LayoutContext layoutContext) {
+ floatContentArea = new SideFloat();
+ AreaAdditionUtil.addAreas(this, parentIter, layoutContext);
+ flush();
+ }
+
+ public void addChildArea(Area childArea) {
+ floatContentArea.addChildArea(childArea);
+ floatContentArea.setBPD(childArea.getAllocBPD());
+ int effectiveContentIPD = childArea.getEffectiveAllocIPD();
+ int contentIPD = childArea.getIPD();
+ int xOffset = childArea.getBorderAndPaddingWidthStart();
+ floatContentArea.setIPD(effectiveContentIPD);
+ childArea.activateEffectiveIPD();
+ if (side == Constants.EN_END || side == Constants.EN_RIGHT) {
+ xOffset += getStartIndent();
+ floatContentArea.setXOffset(xOffset + contentIPD - effectiveContentIPD);
+ } else if (side == Constants.EN_START || side == Constants.EN_LEFT) {
+ floatContentArea.setXOffset(xOffset);
+ }
+ LayoutManager lm = parentLayoutManager;
+ while (!lm.getGeneratesReferenceArea()) {
+ lm = lm.getParent();
+ }
+ yOffset = lm.getParentArea(floatContentArea).getBPD();
+ lm.addChildArea(floatContentArea);
+ if (side == Constants.EN_END || side == Constants.EN_RIGHT) {
+ lm.getPSLM().setEndIntrusionAdjustment(effectiveContentIPD);
+ } else if (side == Constants.EN_START || side == Constants.EN_LEFT) {
+ lm.getPSLM().setStartIntrusionAdjustment(effectiveContentIPD);
+ }
+ }
+
+ public static List<FloatContentLayoutManager> checkForFloats(List<ListElement> elemenList,
+ int startIndex, int endIndex) {
+ ListIterator<ListElement> iter = elemenList.listIterator(startIndex);
+ List<FloatContentLayoutManager> floats = new ArrayList<FloatContentLayoutManager>();
+ while (iter.nextIndex() <= endIndex) {
+ ListElement element = iter.next();
+ if (element instanceof KnuthInlineBox && ((KnuthInlineBox) element).isFloatAnchor()) {
+ floats.add(((KnuthInlineBox) element).getFloatContentLM());
+ } else if (element instanceof KnuthBlockBox && ((KnuthBlockBox) element).hasFloatAnchors()) {
+ floats.addAll(((KnuthBlockBox) element).getFloatContentLMs());
+ }
+ }
+ if (floats.isEmpty()) {
+ return Collections.emptyList();
+ } else {
+ return floats;
+ }
+ }
+
+ protected CommonBorderPaddingBackground getCommonBorderPaddingBackground() {
+ return null;
+ }
+
+ public void processAreas(LayoutContext layoutContext) {
+ if (getParent() instanceof FloatLayoutManager) {
+ FloatLayoutManager flm = (FloatLayoutManager) getParent();
+ flm.processAreas(layoutContext);
+ }
+ }
+
+ public int getFloatHeight() {
+ return floatContentArea.getAllocBPD();
+ }
+
+ public int getFloatYOffset() {
+ return yOffset;
+ }
+
+ private int getStartIndent() {
+ int startIndent = 0;
+ LayoutManager lm = getParent();
+ while (!(lm instanceof BlockLayoutManager)) {
+ lm = lm.getParent();
+ }
+ if (lm instanceof BlockLayoutManager) {
+ startIndent = ((BlockLayoutManager) lm).startIndent;
+ }
+ return startIndent;
+ }
+}
diff --git a/src/java/org/apache/fop/layoutmgr/FlowLayoutManager.java b/src/java/org/apache/fop/layoutmgr/FlowLayoutManager.java
index d37f3b021..227acbfd3 100644
--- a/src/java/org/apache/fop/layoutmgr/FlowLayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/FlowLayoutManager.java
@@ -49,6 +49,8 @@ public class FlowLayoutManager extends BlockStackingLayoutManager {
/** Array of areas currently being filled stored by area class */
private final BlockParent[] currentAreas = new BlockParent[Area.CLASS_MAX];
+ private boolean handlingFloat;
+
/**
* This is the top level layout manager.
* It is created by the PageSequence FO.
@@ -374,6 +376,10 @@ public class FlowLayoutManager extends BlockStackingLayoutManager {
*/
@Override
public void addChildArea(Area childArea) {
+ if (childArea instanceof BlockParent && handlingFloat()) {
+ BlockParent bp = (BlockParent) childArea;
+ bp.setXOffset(getPSLM().getStartIntrusionAdjustment());
+ }
getParentArea(childArea);
addChildToArea(childArea,
this.currentAreas[childArea.getAreaClass()]);
@@ -385,7 +391,7 @@ public class FlowLayoutManager extends BlockStackingLayoutManager {
BlockParent parentArea = null;
int aclass = childArea.getAreaClass();
- if (aclass == Area.CLASS_NORMAL) {
+ if (aclass == Area.CLASS_NORMAL || aclass == Area.CLASS_SIDE_FLOAT) {
parentArea = getCurrentPV().getCurrentFlow();
} else if (aclass == Area.CLASS_BEFORE_FLOAT) {
parentArea = getCurrentPV().getBodyRegion().getBeforeFloat();
@@ -407,7 +413,8 @@ public class FlowLayoutManager extends BlockStackingLayoutManager {
*/
@Override
public int getContentAreaIPD() {
- return getCurrentPV().getCurrentSpan().getColumnWidth();
+ int flowIPD = getPSLM().getCurrentColumnWidth();
+ return flowIPD;
}
/**
@@ -425,5 +432,16 @@ public class FlowLayoutManager extends BlockStackingLayoutManager {
return true;
}
+ public void handleFloatOn() {
+ handlingFloat = true;
+ }
+
+ public void handleFloatOff() {
+ handlingFloat = false;
+ }
+
+ public boolean handlingFloat() {
+ return handlingFloat;
+ }
}
diff --git a/src/java/org/apache/fop/layoutmgr/KnuthBlockBox.java b/src/java/org/apache/fop/layoutmgr/KnuthBlockBox.java
index 530c6609a..92ae1aacf 100644
--- a/src/java/org/apache/fop/layoutmgr/KnuthBlockBox.java
+++ b/src/java/org/apache/fop/layoutmgr/KnuthBlockBox.java
@@ -36,6 +36,7 @@ public class KnuthBlockBox extends KnuthBox {
*/
private int bpd;
private List<FootnoteBodyLayoutManager> footnoteList;
+ private List<FloatContentLayoutManager> floatContentLMs;
/** List of Knuth elements. This is a list of LinkedList elements. */
private List elementLists;
@@ -53,6 +54,7 @@ public class KnuthBlockBox extends KnuthBox {
ipdRange = range;
bpd = bpdim;
footnoteList = new LinkedList<FootnoteBodyLayoutManager>();
+ floatContentLMs = new LinkedList<FloatContentLayoutManager>();
}
/**
@@ -69,6 +71,16 @@ public class KnuthBlockBox extends KnuthBox {
ipdRange = MinOptMax.ZERO;
bpd = 0;
footnoteList = new LinkedList<FootnoteBodyLayoutManager>(list);
+ floatContentLMs = new LinkedList<FloatContentLayoutManager>();
+ }
+
+ public KnuthBlockBox(int width, List list, Position pos, boolean auxiliary,
+ List<FloatContentLayoutManager> fclms) {
+ super(width, pos, auxiliary);
+ ipdRange = MinOptMax.ZERO;
+ bpd = 0;
+ footnoteList = new LinkedList<FootnoteBodyLayoutManager>(list);
+ floatContentLMs = new LinkedList<FloatContentLayoutManager>(fclms);
}
/**
@@ -122,4 +134,12 @@ public class KnuthBlockBox extends KnuthBox {
public int getBPD() {
return bpd;
}
+
+ public List<FloatContentLayoutManager> getFloatContentLMs() {
+ return floatContentLMs;
+ }
+
+ public boolean hasFloatAnchors() {
+ return (floatContentLMs.size() > 0);
+ }
}
diff --git a/src/java/org/apache/fop/layoutmgr/LayoutManagerMapping.java b/src/java/org/apache/fop/layoutmgr/LayoutManagerMapping.java
index 88c52b383..7c0f9c999 100644
--- a/src/java/org/apache/fop/layoutmgr/LayoutManagerMapping.java
+++ b/src/java/org/apache/fop/layoutmgr/LayoutManagerMapping.java
@@ -41,6 +41,7 @@ import org.apache.fop.fo.flow.Block;
import org.apache.fop.fo.flow.BlockContainer;
import org.apache.fop.fo.flow.Character;
import org.apache.fop.fo.flow.ExternalGraphic;
+import org.apache.fop.fo.flow.Float;
import org.apache.fop.fo.flow.Footnote;
import org.apache.fop.fo.flow.Inline;
import org.apache.fop.fo.flow.InlineContainer;
@@ -74,6 +75,7 @@ import org.apache.fop.layoutmgr.inline.BidiLayoutManager;
import org.apache.fop.layoutmgr.inline.CharacterLayoutManager;
import org.apache.fop.layoutmgr.inline.ContentLayoutManager;
import org.apache.fop.layoutmgr.inline.ExternalGraphicLayoutManager;
+import org.apache.fop.layoutmgr.inline.FloatLayoutManager;
import org.apache.fop.layoutmgr.inline.FootnoteLayoutManager;
import org.apache.fop.layoutmgr.inline.InlineContainerLayoutManager;
import org.apache.fop.layoutmgr.inline.InlineLayoutManager;
@@ -113,7 +115,7 @@ public class LayoutManagerMapping implements LayoutManagerMaker {
registerMaker(FObjMixed.class, new Maker());
registerMaker(BidiOverride.class, new BidiOverrideLayoutManagerMaker());
registerMaker(Inline.class, new InlineLayoutManagerMaker());
- registerMaker(Footnote.class, new FootnodeLayoutManagerMaker());
+ registerMaker(Footnote.class, new FootnoteLayoutManagerMaker());
registerMaker(InlineContainer.class,
new InlineContainerLayoutManagerMaker());
registerMaker(BasicLink.class, new BasicLinkLayoutManagerMaker());
@@ -146,6 +148,7 @@ public class LayoutManagerMapping implements LayoutManagerMaker {
registerMaker(Title.class, new InlineLayoutManagerMaker());
registerMaker(MultiCase.class, new MultiCaseLayoutManagerMaker());
registerMaker(MultiSwitch.class, new MultiSwitchLayoutManagerMaker());
+ registerMaker(Float.class, new FloatLayoutManagerMaker());
}
/**
@@ -267,7 +270,7 @@ public class LayoutManagerMapping implements LayoutManagerMaker {
}
/** a layout manager maker */
- public static class FootnodeLayoutManagerMaker extends Maker {
+ public static class FootnoteLayoutManagerMaker extends Maker {
/** {@inheritDoc} */
public void make(FONode node, List lms) {
lms.add(new FootnoteLayoutManager((Footnote) node));
@@ -463,4 +466,10 @@ public class LayoutManagerMapping implements LayoutManagerMaker {
}
}
+ public static class FloatLayoutManagerMaker extends Maker {
+ public void make(FONode node, List lms) {
+ lms.add(new FloatLayoutManager((Float) node));
+ }
+ }
+
}
diff --git a/src/java/org/apache/fop/layoutmgr/PageBreaker.java b/src/java/org/apache/fop/layoutmgr/PageBreaker.java
index faff4ee17..ba676ab89 100644
--- a/src/java/org/apache/fop/layoutmgr/PageBreaker.java
+++ b/src/java/org/apache/fop/layoutmgr/PageBreaker.java
@@ -20,6 +20,8 @@
package org.apache.fop.layoutmgr;
import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
@@ -32,7 +34,9 @@ import org.apache.fop.fo.FObj;
import org.apache.fop.fo.pagination.Region;
import org.apache.fop.fo.pagination.RegionBody;
import org.apache.fop.fo.pagination.StaticContent;
+import org.apache.fop.layoutmgr.BreakingAlgorithm.KnuthNode;
import org.apache.fop.layoutmgr.PageBreakingAlgorithm.PageBreakingLayoutListener;
+import org.apache.fop.layoutmgr.list.ListItemLayoutManager;
import org.apache.fop.traits.MinOptMax;
/**
@@ -47,6 +51,23 @@ public class PageBreaker extends AbstractBreaker {
private PageProvider pageProvider;
private Block separatorArea;
private boolean spanAllActive;
+ private boolean handlingStartOfFloat;
+ private boolean handlingEndOfFloat;
+ private int floatHeight;
+ private int floatYOffset;
+
+ private List relayedFootnotesList;
+ private List relayedLengthList;
+ private int relayedTotalFootnotesLength;
+ private int relayedInsertedFootnotesLength;
+ private boolean relayedFootnotesPending;
+ private boolean relayedNewFootnotes;
+ private int relayedFirstNewFootnoteIndex;
+ private int relayedFootnoteListIndex;
+ private int relayedFootnoteElementIndex = -1;
+ private MinOptMax relayedFootnoteSeparatorLength;
+ private int previousFootnoteListIndex = -2;
+ private int previousFootnoteElementIndex = -2;
/**
* The FlowLayoutManager object, which processes
@@ -69,7 +90,7 @@ public class PageBreaker extends AbstractBreaker {
/** {@inheritDoc} */
protected void updateLayoutContext(LayoutContext context) {
- int flowIPD = pslm.getCurrentPV().getCurrentSpan().getColumnWidth();
+ int flowIPD = pslm.getCurrentColumnWidth();
context.setRefIPD(flowIPD);
}
@@ -140,18 +161,20 @@ public class PageBreaker extends AbstractBreaker {
/** {@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
- // condition that must be satisfied;
- // otherwise, we may simply need a new page
- handleBreakTrait(nextSequenceStartsOn);
- }
- firstPart = false;
- pageBreakHandled = true;
+ if (!handlingFloat()) {
+ if (!firstPart) {
+ // if this is the first page that will be created by
+ // the current BlockSequence, it could have a break
+ // condition that must be satisfied;
+ // otherwise, we may simply need a new page
+ handleBreakTrait(nextSequenceStartsOn);
+ }
+ firstPart = false;
+ pageBreakHandled = true;
- pageProvider.setStartOfNextElementList(pslm.getCurrentPageNum(),
- pslm.getCurrentPV().getCurrentSpan().getCurrentFlowIndex(), this.spanAllActive);
+ pageProvider.setStartOfNextElementList(pslm.getCurrentPageNum(), pslm.getCurrentPV()
+ .getCurrentSpan().getCurrentFlowIndex(), this.spanAllActive);
+ }
return super.getNextBlockList(childLC, nextSequenceStartsOn, positionAtIPDChange,
restartLM, firstElements);
}
@@ -234,6 +257,7 @@ public class PageBreaker extends AbstractBreaker {
// handle the footnote separator
handleFootnoteSeparator();
}
+
return contentList;
}
@@ -616,4 +640,238 @@ public class PageBreaker extends AbstractBreaker {
return true;
}
}
+
+ protected boolean handlingStartOfFloat() {
+ return handlingStartOfFloat;
+ }
+
+ protected void handleStartOfFloat(int fHeight, int fYOffset) {
+ handlingStartOfFloat = true;
+ handlingEndOfFloat = false;
+ floatHeight = fHeight;
+ floatYOffset = fYOffset;
+ childFLM.handleFloatOn();
+ }
+
+ protected int getFloatHeight() {
+ return floatHeight;
+ }
+
+ protected int getFloatYOffset() {
+ return floatYOffset;
+ }
+
+ protected boolean handlingEndOfFloat() {
+ return handlingEndOfFloat;
+ }
+
+ protected void handleEndOfFloat(int fHeight) {
+ handlingEndOfFloat = true;
+ handlingStartOfFloat = false;
+ floatHeight = fHeight;
+ childFLM.handleFloatOff();
+ }
+
+ protected boolean handlingFloat() {
+ return (handlingStartOfFloat || handlingEndOfFloat);
+ }
+
+ public int getOffsetDueToFloat() {
+ handlingEndOfFloat = false;
+ return floatHeight + floatYOffset;
+ }
+
+ protected int handleFloatLayout(PageBreakingAlgorithm alg, int optimalPageCount, BlockSequence blockList,
+ LayoutContext childLC) {
+ pageBreakHandled = true;
+ List firstElements = Collections.EMPTY_LIST;
+ KnuthNode floatNode = alg.getBestFloatEdgeNode();
+ int floatPosition = floatNode.position;
+ KnuthElement floatElem = alg.getElement(floatPosition);
+ Position positionAtBreak = floatElem.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();
+ addAreas(alg, optimalPageCount, blockList, blockList);
+ blockLists.clear();
+ blockListIndex = -1;
+ LayoutManager restartAtLM = null;
+ if (positionAtBreak != null && positionAtBreak.getIndex() == -1) {
+ if (positionAtBreak instanceof ListItemLayoutManager.ListItemPosition) {
+ restartAtLM = positionAtBreak.getLM();
+ } else {
+ Position position;
+ Iterator iter = blockList.listIterator(floatPosition + 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();
+ }
+ }
+ int nextSequenceStartsOn = getNextBlockList(childLC, Constants.EN_COLUMN, positionAtBreak,
+ restartAtLM, firstElements);
+ return nextSequenceStartsOn;
+ }
+
+ protected void addAreasForFloats(PageBreakingAlgorithm alg, int startPart, int partCount,
+ BlockSequence originalList, BlockSequence effectiveList, final LayoutContext childLC,
+ int lastBreak, int startElementIndex, int endElementIndex) {
+ FloatPosition pbp = alg.getFloatPosition();
+
+ // Check the last break position for forced breaks
+ int lastBreakClass;
+ if (startElementIndex == 0) {
+ lastBreakClass = effectiveList.getStartOn();
+ } else {
+ ListElement lastBreakElement = effectiveList.getElement(endElementIndex);
+ if (lastBreakElement.isPenalty()) {
+ KnuthPenalty pen = (KnuthPenalty) lastBreakElement;
+ if (pen.getPenalty() == KnuthPenalty.INFINITE) {
+ /**
+ * That means that there was a keep.within-page="always", but that
+ * it's OK to break at a column. TODO The break class is being
+ * abused to implement keep.within-column and keep.within-page.
+ * This is very misleading and must be revised.
+ */
+ lastBreakClass = Constants.EN_COLUMN;
+ } else {
+ lastBreakClass = pen.getBreakClass();
+ }
+ } else {
+ lastBreakClass = Constants.EN_COLUMN;
+ }
+ }
+
+ // the end of the new part
+ endElementIndex = pbp.getLeafPos();
+
+ // ignore the first elements added by the
+ // PageSequenceLayoutManager
+ startElementIndex += (startElementIndex == 0) ? effectiveList.ignoreAtStart : 0;
+
+ log.debug("PLM> part: " + (startPart + partCount + 1) + ", start at pos " + startElementIndex
+ + ", break at pos " + endElementIndex + ", break class = "
+ + getBreakClassName(lastBreakClass));
+
+ startPart(effectiveList, lastBreakClass);
+
+ int displayAlign = getCurrentDisplayAlign();
+
+ // The following is needed by SpaceResolver.performConditionalsNotification()
+ // further down as there may be important Position elements in the element list trailer
+ int notificationEndElementIndex = endElementIndex;
+
+ // ignore the last elements added by the
+ // PageSequenceLayoutManager
+ endElementIndex -= (endElementIndex == (originalList.size() - 1)) ? effectiveList.ignoreAtEnd : 0;
+
+ // ignore the last element in the page if it is a KnuthGlue
+ // object
+ if (((KnuthElement) effectiveList.get(endElementIndex)).isGlue()) {
+ endElementIndex--;
+ }
+
+ // ignore KnuthGlue and KnuthPenalty objects
+ // at the beginning of the line
+ startElementIndex = alg.par.getFirstBoxIndex(startElementIndex);
+
+ if (startElementIndex <= endElementIndex) {
+ if (log.isDebugEnabled()) {
+ log.debug(" addAreas from " + startElementIndex + " to " + endElementIndex);
+ }
+ // set the space adjustment ratio
+ childLC.setSpaceAdjust(pbp.bpdAdjust);
+ // add space before if display-align is center or bottom
+ // add space after if display-align is distribute and
+ // this is not the last page
+ if (pbp.difference != 0 && displayAlign == Constants.EN_CENTER) {
+ childLC.setSpaceBefore(pbp.difference / 2);
+ } else if (pbp.difference != 0 && displayAlign == Constants.EN_AFTER) {
+ childLC.setSpaceBefore(pbp.difference);
+ }
+
+ // Handle SpaceHandling(Break)Positions, see SpaceResolver!
+ SpaceResolver.performConditionalsNotification(effectiveList, startElementIndex,
+ notificationEndElementIndex, lastBreak);
+ // Add areas of lines, in the current page, before the float or during float
+ addAreas(new KnuthPossPosIter(effectiveList, startElementIndex, endElementIndex + 1), childLC);
+ // add areas for the float, if applicable
+ if (alg.handlingStartOfFloat()) {
+ for (int k = startElementIndex; k < endElementIndex + 1; k++) {
+ ListElement le = effectiveList.getElement(k);
+ if (le instanceof KnuthBlockBox) {
+ KnuthBlockBox kbb = (KnuthBlockBox) le;
+ for (FloatContentLayoutManager fclm : kbb.getFloatContentLMs()) {
+ fclm.processAreas(childLC);
+ int floatHeight = fclm.getFloatHeight();
+ int floatYOffset = fclm.getFloatYOffset();
+ PageSequenceLayoutManager pslm = (PageSequenceLayoutManager) getTopLevelLM();
+ pslm.recordStartOfFloat(floatHeight, floatYOffset);
+ }
+ }
+ }
+ }
+ if (alg.handlingEndOfFloat()) {
+ PageSequenceLayoutManager pslm = (PageSequenceLayoutManager) getTopLevelLM();
+ pslm.setEndIntrusionAdjustment(0);
+ pslm.setStartIntrusionAdjustment(0);
+ int effectiveFloatHeight = alg.getFloatHeight();
+ pslm.recordEndOfFloat(effectiveFloatHeight);
+ }
+ if (alg.handlingFloat()) {
+ PageSequenceLayoutManager pslm = (PageSequenceLayoutManager) getTopLevelLM();
+ alg.relayFootnotes(pslm);
+ }
+ } else {
+ // no content for this part
+ handleEmptyContent();
+ }
+
+ pageBreakHandled = true;
+ }
+
+ public void holdFootnotes(List fl, List ll, int tfl, int ifl, boolean fp, boolean nf, int fnfi, int fli,
+ int fei, MinOptMax fsl, int pfli, int pfei) {
+ relayedFootnotesList = fl;
+ relayedLengthList = ll;
+ relayedTotalFootnotesLength = tfl;
+ relayedInsertedFootnotesLength = ifl;
+ relayedFootnotesPending = fp;
+ relayedNewFootnotes = nf;
+ relayedFirstNewFootnoteIndex = fnfi;
+ relayedFootnoteListIndex = fli;
+ relayedFootnoteElementIndex = fei;
+ relayedFootnoteSeparatorLength = fsl;
+ previousFootnoteListIndex = pfli;
+ previousFootnoteElementIndex = pfei;
+ }
+
+ public void retrieveFootones(PageBreakingAlgorithm alg) {
+ if (relayedFootnotesList != null && relayedFootnotesList.size() > 0) {
+ alg.loadFootnotes(relayedFootnotesList, relayedLengthList, relayedTotalFootnotesLength,
+ relayedInsertedFootnotesLength, relayedFootnotesPending, relayedNewFootnotes,
+ relayedFirstNewFootnoteIndex, relayedFootnoteListIndex, relayedFootnoteElementIndex,
+ relayedFootnoteSeparatorLength, previousFootnoteListIndex,
+ previousFootnoteElementIndex);
+ relayedFootnotesList = null;
+ relayedLengthList = null;
+ relayedTotalFootnotesLength = 0;
+ relayedInsertedFootnotesLength = 0;
+ relayedFootnotesPending = false;
+ relayedNewFootnotes = false;
+ relayedFirstNewFootnoteIndex = 0;
+ relayedFootnoteListIndex = 0;
+ relayedFootnoteElementIndex = -1;
+ relayedFootnoteSeparatorLength = null;
+ }
+ }
}
diff --git a/src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java b/src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java
index cdd9a703a..008ec2265 100644
--- a/src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java
+++ b/src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java
@@ -29,6 +29,7 @@ import org.apache.commons.logging.LogFactory;
import org.apache.fop.fo.Constants;
import org.apache.fop.fo.FObj;
+import org.apache.fop.layoutmgr.AbstractBreaker.FloatPosition;
import org.apache.fop.layoutmgr.AbstractBreaker.PageBreakPosition;
import org.apache.fop.layoutmgr.WhitespaceManagementPenalty.Variant;
import org.apache.fop.traits.MinOptMax;
@@ -99,6 +100,16 @@ class PageBreakingAlgorithm extends BreakingAlgorithm {
private int currentKeepContext = Constants.EN_AUTO;
private KnuthNode lastBeforeKeepContextSwitch;
+ // just one float for now...
+ private boolean handlingStartOfFloat;
+ private boolean handlingEndOfFloat;
+ private int floatHeight;
+ private KnuthNode bestFloatEdgeNode;
+ private FloatPosition floatPosition;
+ private int previousFootnoteListIndex = -2;
+ private int previousFootnoteElementIndex = -2;
+ private boolean relayingFootnotes;
+
/**
* Construct a page breaking algorithm.
* @param topLevelLM the top level layout manager
@@ -235,6 +246,18 @@ class PageBreakingAlgorithm extends BreakingAlgorithm {
insertedFootnotesLength = 0;
footnoteListIndex = 0;
footnoteElementIndex = -1;
+ if (topLevelLM instanceof PageSequenceLayoutManager) {
+ PageSequenceLayoutManager pslm = (PageSequenceLayoutManager) topLevelLM;
+ if (pslm.handlingStartOfFloat() || pslm.handlingEndOfFloat()) {
+ pslm.retrieveFootnotes(this);
+ }
+ if (pslm.handlingStartOfFloat()) {
+ floatHeight = Math.min(pslm.getFloatHeight(), lineWidth - pslm.getFloatYOffset());
+ }
+ if (pslm.handlingEndOfFloat()) {
+ totalWidth += pslm.getOffsetDueToFloat() + insertedFootnotesLength;
+ }
+ }
}
/**
@@ -352,6 +375,12 @@ class PageBreakingAlgorithm extends BreakingAlgorithm {
firstNewFootnoteIndex = footnotesList.size() - 1;
}
}
+ if (box instanceof KnuthBlockBox && ((KnuthBlockBox) box).hasFloatAnchors()) {
+ handlingStartOfFloat = true;
+ }
+ if (floatHeight != 0 && totalWidth >= floatHeight) {
+ handlingEndOfFloat = true;
+ }
}
/**
@@ -1064,17 +1093,6 @@ class PageBreakingAlgorithm extends BreakingAlgorithm {
difference = 0;
}
}
- // compute the indexes of the first footnote list and the first element in that list
- int firstListIndex = ((KnuthPageNode) bestActiveNode.previous).footnoteListIndex;
- int firstElementIndex = ((KnuthPageNode) bestActiveNode.previous).footnoteElementIndex;
- if (footnotesList != null
- && firstElementIndex == getFootnoteList(firstListIndex).size() - 1) {
- // advance to the next list
- firstListIndex++;
- firstElementIndex = 0;
- } else {
- firstElementIndex++;
- }
// add nodes at the beginning of the list, as they are found
// backwards, from the last one to the first one
@@ -1082,12 +1100,31 @@ class PageBreakingAlgorithm extends BreakingAlgorithm {
log.debug("BBA> difference=" + difference + " ratio=" + ratio
+ " position=" + bestActiveNode.position);
}
- insertPageBreakAsFirst(new PageBreakPosition(this.topLevelLM,
- bestActiveNode.position,
- firstListIndex, firstElementIndex,
- ((KnuthPageNode) bestActiveNode).footnoteListIndex,
- ((KnuthPageNode) bestActiveNode).footnoteElementIndex,
- ratio, difference));
+ if (handlingFloat() && floatPosition == null) {
+ floatPosition = new FloatPosition(this.topLevelLM, bestActiveNode.position, ratio, difference);
+ } else {
+ boolean useRelayedFootnotes = relayingFootnotes && bestActiveNode.previous.position == 0;
+ // compute the indexes of the first footnote list and the first element in that list
+ int firstListIndex = (useRelayedFootnotes) ? previousFootnoteListIndex
+ : ((KnuthPageNode) bestActiveNode.previous).footnoteListIndex;
+ int firstElementIndex = (useRelayedFootnotes) ? previousFootnoteElementIndex
+ : ((KnuthPageNode) bestActiveNode.previous).footnoteElementIndex;
+ if (useRelayedFootnotes) {
+ previousFootnoteListIndex = -2;
+ previousFootnoteElementIndex = -2;
+ relayingFootnotes = false;
+ }
+ if (footnotesList != null && firstElementIndex == getFootnoteList(firstListIndex).size() - 1) {
+ // advance to the next list
+ firstListIndex++;
+ firstElementIndex = 0;
+ } else {
+ firstElementIndex++;
+ }
+ insertPageBreakAsFirst(new PageBreakPosition(this.topLevelLM, bestActiveNode.position,
+ firstListIndex, firstElementIndex, ((KnuthPageNode) bestActiveNode).footnoteListIndex,
+ ((KnuthPageNode) bestActiveNode).footnoteElementIndex, ratio, difference));
+ }
}
/** {@inheritDoc} */
@@ -1233,4 +1270,94 @@ class PageBreakingAlgorithm extends BreakingAlgorithm {
}
return pageProvider.compareIPDs(line);
}
+
+ protected boolean handlingFloat() {
+ return (handlingStartOfFloat || handlingEndOfFloat);
+ }
+
+ protected void createForcedNodes(KnuthNode node, int line, int elementIdx, int difference, double r,
+ double demerits, int fitnessClass, int availableShrink, int availableStretch, int newWidth,
+ int newStretch, int newShrink) {
+ if (handlingFloat()) {
+ if (bestFloatEdgeNode == null || demerits <= bestFloatEdgeNode.totalDemerits) {
+ bestFloatEdgeNode = createNode(elementIdx, line + 1, fitnessClass, newWidth, newStretch,
+ newShrink, r, availableShrink, availableStretch, difference, demerits, node);
+ }
+ } else {
+ super.createForcedNodes(node, line, elementIdx, difference, r, demerits, fitnessClass,
+ availableShrink, availableStretch, newWidth, newStretch, newShrink);
+ }
+ }
+
+ protected int handleFloat() {
+ calculateBreakPoints(bestFloatEdgeNode, par, bestFloatEdgeNode.line);
+ activeLines = null;
+ return bestFloatEdgeNode.line - 1;
+ }
+
+ protected KnuthNode getBestFloatEdgeNode() {
+ return bestFloatEdgeNode;
+ }
+
+ protected FloatPosition getFloatPosition() {
+ return floatPosition;
+ }
+
+ protected int getFloatHeight() {
+ return floatHeight;
+ }
+
+ protected boolean handlingStartOfFloat() {
+ return handlingStartOfFloat;
+ }
+
+ protected boolean handlingEndOfFloat() {
+ return handlingEndOfFloat;
+ }
+
+ /**
+ * Deactivate the given node
+ *
+ * @param node the node
+ * @param line the line number
+ */
+ protected void deactivateNode(KnuthNode node, int line) {
+ super.deactivateNode(node, line);
+ if (handlingEndOfFloat) {
+ floatHeight = totalWidth;
+ }
+ }
+
+ protected void disableFloatHandling() {
+ handlingEndOfFloat = false;
+ handlingStartOfFloat = false;
+ }
+
+ public void loadFootnotes(List fl, List ll, int tfl, int ifl, boolean fp, boolean nf, int fnfi, int fli,
+ int fei, MinOptMax fsl, int pfli, int pfei) {
+ footnotesList = fl;
+ lengthList = ll;
+ totalFootnotesLength = tfl;
+ insertedFootnotesLength = ifl;
+ footnotesPending = fp;
+ newFootnotes = nf;
+ firstNewFootnoteIndex = fnfi;
+ footnoteListIndex = fli;
+ footnoteElementIndex = fei;
+ footnoteSeparatorLength = fsl;
+ previousFootnoteListIndex = pfli;
+ previousFootnoteElementIndex = pfei;
+ relayingFootnotes = !(previousFootnoteListIndex == -2 && previousFootnoteElementIndex == -2);
+ }
+
+ public void relayFootnotes(PageSequenceLayoutManager pslm) {
+ if (!relayingFootnotes) {
+ previousFootnoteListIndex = ((KnuthPageNode) bestFloatEdgeNode.previous).footnoteListIndex;
+ previousFootnoteElementIndex = ((KnuthPageNode) bestFloatEdgeNode.previous).footnoteElementIndex;
+ }
+ pslm.holdFootnotes(footnotesList, lengthList, totalFootnotesLength, insertedFootnotesLength,
+ footnotesPending, newFootnotes, firstNewFootnoteIndex, footnoteListIndex,
+ footnoteElementIndex, footnoteSeparatorLength, previousFootnoteListIndex,
+ previousFootnoteElementIndex);
+ }
}
diff --git a/src/java/org/apache/fop/layoutmgr/PageSequenceLayoutManager.java b/src/java/org/apache/fop/layoutmgr/PageSequenceLayoutManager.java
index 70f02f896..20c4616bd 100644
--- a/src/java/org/apache/fop/layoutmgr/PageSequenceLayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/PageSequenceLayoutManager.java
@@ -36,6 +36,7 @@ import org.apache.fop.fo.pagination.PageSequenceMaster;
import org.apache.fop.fo.pagination.SideRegion;
import org.apache.fop.fo.pagination.StaticContent;
import org.apache.fop.layoutmgr.inline.ContentLayoutManager;
+import org.apache.fop.traits.MinOptMax;
/**
* LayoutManager for a PageSequence. This class is instantiated by
@@ -56,6 +57,9 @@ public class PageSequenceLayoutManager extends AbstractPageSequenceLayoutManager
/** Footnotes coming from repeated table footers, to be added after any other footnote. */
private List<List<KnuthElement>> tableFooterFootnotes;
+ private int startIntrusionAdjustment;
+ private int endIntrusionAdjustment;
+
/**
* Constructor
*
@@ -293,4 +297,64 @@ public class PageSequenceLayoutManager extends AbstractPageSequenceLayoutManager
}
}
+ public void setStartIntrusionAdjustment(int sia) {
+ startIntrusionAdjustment = sia;
+ }
+
+ public void setEndIntrusionAdjustment(int eia) {
+ endIntrusionAdjustment = eia;
+ }
+
+ public int getStartIntrusionAdjustment() {
+ return startIntrusionAdjustment;
+ }
+
+ public int getEndIntrusionAdjustment() {
+ return endIntrusionAdjustment;
+ }
+
+ public void recordEndOfFloat(int fHeight) {
+ pageBreaker.handleEndOfFloat(fHeight);
+ }
+
+ public boolean handlingEndOfFloat() {
+ return pageBreaker.handlingEndOfFloat();
+ }
+
+ public int getOffsetDueToFloat() {
+ return pageBreaker.getOffsetDueToFloat();
+ }
+
+ public void recordStartOfFloat(int fHeight, int fYOffset) {
+ pageBreaker.handleStartOfFloat(fHeight, fYOffset);
+ }
+
+ public boolean handlingStartOfFloat() {
+ return pageBreaker.handlingStartOfFloat();
+ }
+
+ public int getFloatHeight() {
+ return pageBreaker.getFloatHeight();
+ }
+
+ public int getFloatYOffset() {
+ return pageBreaker.getFloatYOffset();
+ }
+
+ public int getCurrentColumnWidth() {
+ int flowIPD = getCurrentPV().getCurrentSpan().getColumnWidth();
+ flowIPD -= startIntrusionAdjustment + endIntrusionAdjustment;
+ return flowIPD;
+ }
+
+ public void holdFootnotes(List fl, List ll, int tfl, int ifl, boolean fp, boolean nf, int fnfi, int fli,
+ int fei, MinOptMax fsl, int pfli, int pfei) {
+ if (fl != null && fl.size() > 0) {
+ pageBreaker.holdFootnotes(fl, ll, tfl, ifl, fp, nf, fnfi, fli, fei, fsl, pfli, pfei);
+ }
+ }
+
+ public void retrieveFootnotes(PageBreakingAlgorithm alg) {
+ pageBreaker.retrieveFootones(alg);
+ }
}
diff --git a/src/java/org/apache/fop/layoutmgr/SpaceResolver.java b/src/java/org/apache/fop/layoutmgr/SpaceResolver.java
index 31bdaebbf..551e7d3f2 100644
--- a/src/java/org/apache/fop/layoutmgr/SpaceResolver.java
+++ b/src/java/org/apache/fop/layoutmgr/SpaceResolver.java
@@ -696,7 +696,7 @@ public final class SpaceResolver {
beforeBreak.notifyBreakSituation(true, RelSide.BEFORE);
}
}
- el = (KnuthElement)effectiveList.get(endElementIndex);
+ el = endElementIndex > -1 ? (KnuthElement) effectiveList.get(endElementIndex) : null;
if (el != null && el.isPenalty()) {
Position pos = el.getPosition();
if (pos instanceof SpaceResolver.SpaceHandlingBreakPosition) {
diff --git a/src/java/org/apache/fop/layoutmgr/inline/FloatLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/FloatLayoutManager.java
new file mode 100644
index 000000000..4bb481dcd
--- /dev/null
+++ b/src/java/org/apache/fop/layoutmgr/inline/FloatLayoutManager.java
@@ -0,0 +1,98 @@
+/*
+ * 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$ */
+
+package org.apache.fop.layoutmgr.inline;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.fop.fo.flow.Float;
+import org.apache.fop.layoutmgr.FloatContentLayoutManager;
+import org.apache.fop.layoutmgr.InlineKnuthSequence;
+import org.apache.fop.layoutmgr.KnuthElement;
+import org.apache.fop.layoutmgr.KnuthPossPosIter;
+import org.apache.fop.layoutmgr.KnuthSequence;
+import org.apache.fop.layoutmgr.LayoutContext;
+import org.apache.fop.layoutmgr.LayoutManager;
+import org.apache.fop.layoutmgr.Position;
+import org.apache.fop.layoutmgr.PositionIterator;
+import org.apache.fop.layoutmgr.SpaceResolver;
+
+public class FloatLayoutManager extends InlineStackingLayoutManager {
+
+ private FloatContentLayoutManager floatContentLM;
+ private KnuthInlineBox anchor;
+ private List<KnuthElement> floatContentKnuthElements;
+ private Float floatContent;
+ private boolean floatContentAreaAdded;
+
+ public FloatLayoutManager(Float node) {
+ super(node);
+ floatContent = node;
+ }
+
+ protected LayoutManager getChildLM() {
+ return null;
+ }
+
+ public LinkedList getNextKnuthElements(LayoutContext context, int alignment) {
+
+ if (!floatContentAreaAdded && !floatContent.isDisabled()) {
+ floatContentLM = new FloatContentLayoutManager(floatContent);
+ floatContentLM.setParent(this);
+ floatContentLM.initialize();
+ floatContentKnuthElements = floatContentLM.getNextKnuthElements(context, alignment);
+ SpaceResolver.resolveElementList(floatContentKnuthElements);
+ }
+
+ // the only knuth element is a zero width and height knuth box
+ LinkedList knuthElements = new LinkedList();
+ KnuthSequence seq = new InlineKnuthSequence();
+ anchor = new KnuthInlineBox(0, null, null, true);
+ if (!floatContentAreaAdded) {
+ anchor.setFloatContentLM(floatContentLM);
+ }
+ anchor.setPosition(notifyPos(new Position(this)));
+ seq.add(anchor);
+ knuthElements.add(seq);
+ setFinished(true);
+
+ return knuthElements;
+ }
+
+ public void addAreas(PositionIterator posIter, LayoutContext context) {
+ // "Unwrap" the NonLeafPositions stored in posIter
+ LinkedList positionList = new LinkedList();
+ Position pos = null;
+ while (posIter.hasNext()) {
+ pos = posIter.next();
+ if (pos != null && pos.getPosition() != null) {
+ positionList.add(pos.getPosition());
+ }
+ }
+ }
+
+ public void processAreas(LayoutContext context) {
+ PositionIterator contentPosIter = new KnuthPossPosIter(floatContentKnuthElements, 0,
+ floatContentKnuthElements.size());
+ floatContentLM.addAreas(contentPosIter, context);
+ floatContentAreaAdded = true;
+ anchor.setFloatContentLM(null);
+ }
+}
diff --git a/src/java/org/apache/fop/layoutmgr/inline/KnuthInlineBox.java b/src/java/org/apache/fop/layoutmgr/inline/KnuthInlineBox.java
index e8bec8f4d..dad6d283c 100644
--- a/src/java/org/apache/fop/layoutmgr/inline/KnuthInlineBox.java
+++ b/src/java/org/apache/fop/layoutmgr/inline/KnuthInlineBox.java
@@ -19,6 +19,7 @@
package org.apache.fop.layoutmgr.inline;
+import org.apache.fop.layoutmgr.FloatContentLayoutManager;
import org.apache.fop.layoutmgr.FootnoteBodyLayoutManager;
import org.apache.fop.layoutmgr.KnuthBox;
import org.apache.fop.layoutmgr.Position;
@@ -30,6 +31,8 @@ public class KnuthInlineBox extends KnuthBox {
private FootnoteBodyLayoutManager footnoteBodyLM;
private AlignmentContext alignmentContext;
+ private FloatContentLayoutManager floatContentLM;
+
/**
* Create a new KnuthBox.
@@ -72,4 +75,17 @@ public class KnuthInlineBox extends KnuthBox {
public boolean isAnchor() {
return (footnoteBodyLM != null);
}
+
+ public void setFloatContentLM(FloatContentLayoutManager fclm) {
+ floatContentLM = fclm;
+ }
+
+ public FloatContentLayoutManager getFloatContentLM() {
+ return floatContentLM;
+ }
+
+ public boolean isFloatAnchor() {
+ return (floatContentLM != null);
+ }
+
}
diff --git a/src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java b/src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java
index d8ebc6dbf..6f31f038a 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.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
@@ -50,6 +51,7 @@ import org.apache.fop.layoutmgr.BlockLevelLayoutManager;
import org.apache.fop.layoutmgr.BreakElement;
import org.apache.fop.layoutmgr.BreakingAlgorithm;
import org.apache.fop.layoutmgr.ElementListObserver;
+import org.apache.fop.layoutmgr.FloatContentLayoutManager;
import org.apache.fop.layoutmgr.FootenoteUtil;
import org.apache.fop.layoutmgr.FootnoteBodyLayoutManager;
import org.apache.fop.layoutmgr.InlineKnuthSequence;
@@ -963,13 +965,19 @@ public class LineLayoutManager extends InlineStackingLayoutManager
/* "normal" vertical alignment: create a sequence whose boxes
represent effective lines, and contain LineBreakPositions */
int startIndex = 0;
+ int previousEndIndex = 0;
for (int i = 0;
i < llPoss.getChosenLineCount();
i++) {
+ int orphans = fobj.getOrphans();
+ int widows = fobj.getWidows();
+ if (handlingFloat()) {
+ orphans = 1;
+ widows = 1;
+ }
if (returnList.size() > 0
&& i > 0 //if i==0 break generated above already
- && i >= fobj.getOrphans()
- && i <= llPoss.getChosenLineCount() - fobj.getWidows()) {
+ && i >= orphans && i <= llPoss.getChosenLineCount() - widows) {
// penalty allowing a page break between lines
Keep keep = getKeepTogether();
returnList.add(new BreakElement(
@@ -983,14 +991,28 @@ public class LineLayoutManager extends InlineStackingLayoutManager
// whose citations are in this line
List<FootnoteBodyLayoutManager> footnoteList = FootenoteUtil.getFootnotes(
seq, startIndex, endIndex);
+ List<FloatContentLayoutManager> floats = FloatContentLayoutManager.checkForFloats(seq,
+ startIndex, endIndex);
startIndex = endIndex + 1;
LineBreakPosition lbp = (LineBreakPosition) llPoss.getChosenPosition(i);
if (baselineOffset < 0) {
baselineOffset = lbp.spaceBefore + lbp.baseline;
}
- returnList.add(new KnuthBlockBox(
- lbp.lineHeight + lbp.spaceBefore + lbp.spaceAfter,
- footnoteList, lbp, false));
+ if (floats.isEmpty()) {
+ returnList.add(new KnuthBlockBox(lbp.lineHeight + lbp.spaceBefore + lbp.spaceAfter,
+ footnoteList, lbp, false));
+ } else {
+ // add a line with height zero and no content and attach float to it
+ returnList.add(new KnuthBlockBox(0, Collections.emptyList(), null, false, floats));
+ // add a break element to signal that we should restart LB at this break
+ Keep keep = getKeepTogether();
+ returnList.add(new BreakElement(new LeafPosition(this, p, previousEndIndex), keep
+ .getPenalty(), keep.getContext(), context));
+ // add the original line where the float was but without the float now
+ returnList.add(new KnuthBlockBox(lbp.lineHeight + lbp.spaceBefore + lbp.spaceAfter,
+ footnoteList, lbp, false));
+ }
+ previousEndIndex = endIndex;
}
}
}
@@ -1196,10 +1218,15 @@ public class LineLayoutManager extends InlineStackingLayoutManager
for (int p = 0; p < knuthParagraphs.size(); p++) {
LineLayoutPossibilities llPoss = lineLayoutsList[p];
//log.debug("demerits of the chosen layout: " + llPoss.getChosenDemerits());
+ int orphans = fobj.getOrphans();
+ int widows = fobj.getWidows();
+ if (handlingFloat()) {
+ orphans = 1;
+ widows = 1;
+ }
for (int i = 0; i < llPoss.getChosenLineCount(); i++) {
- if (!((BlockLevelLayoutManager) parentLayoutManager).mustKeepTogether()
- && i >= fobj.getOrphans()
- && i <= llPoss.getChosenLineCount() - fobj.getWidows()) {
+ if (!((BlockLevelLayoutManager) parentLayoutManager).mustKeepTogether() && i >= orphans
+ && i <= llPoss.getChosenLineCount() - widows) {
// null penalty allowing a page break between lines
returnList.add(new KnuthPenalty(0, 0, false, new Position(this), false));
}
diff --git a/src/java/org/apache/fop/layoutmgr/list/ListBlockLayoutManager.java b/src/java/org/apache/fop/layoutmgr/list/ListBlockLayoutManager.java
index 062a67b38..d39b63477 100644
--- a/src/java/org/apache/fop/layoutmgr/list/ListBlockLayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/list/ListBlockLayoutManager.java
@@ -21,6 +21,7 @@ package org.apache.fop.layoutmgr.list;
import java.util.LinkedList;
import java.util.List;
+import java.util.Stack;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -95,10 +96,11 @@ public class ListBlockLayoutManager extends SpacedBorderedPaddedBlockLayoutManag
}
/** {@inheritDoc} */
- @Override
- public List getNextKnuthElements(LayoutContext context, int alignment) {
+ public List getNextKnuthElements(LayoutContext context, int alignment, Stack lmStack,
+ Position restartPosition, LayoutManager restartAtLM) {
resetSpaces();
- List returnList = super.getNextKnuthElements(context, alignment);
+ List returnList;
+ returnList = super.getNextKnuthElements(context, alignment, lmStack, restartPosition, restartAtLM);
//fox:widow-content-limit
int widowRowLimit = getListBlockFO().getWidowContentLimit().getValue();
@@ -275,5 +277,9 @@ public class ListBlockLayoutManager extends SpacedBorderedPaddedBlockLayoutManag
return getListBlockFO().getKeepWithNext();
}
+ /** {@inheritDoc} */
+ public boolean isRestartable() {
+ return true;
+ }
}
diff --git a/src/java/org/apache/fop/layoutmgr/list/ListItemContentLayoutManager.java b/src/java/org/apache/fop/layoutmgr/list/ListItemContentLayoutManager.java
index 108402cfa..214ba6269 100644
--- a/src/java/org/apache/fop/layoutmgr/list/ListItemContentLayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/list/ListItemContentLayoutManager.java
@@ -21,6 +21,7 @@ package org.apache.fop.layoutmgr.list;
import java.util.LinkedList;
import java.util.List;
+import java.util.Stack;
import org.apache.fop.area.Area;
import org.apache.fop.area.Block;
@@ -225,15 +226,15 @@ public class ListItemContentLayoutManager extends BlockStackingLayoutManager imp
return Keep.KEEP_AUTO;
}
- @SuppressWarnings("unchecked")
- @Override
- public List<ListElement> getNextKnuthElements(LayoutContext context, int alignment) {
+ /** {@inheritDoc} */
+ public List getNextKnuthElements(LayoutContext context, int alignment, Stack lmStack,
+ Position restartPosition, LayoutManager restartAtLM) {
List<ListElement> elements = new LinkedList<ListElement>();
do {
- elements.addAll(super.getNextKnuthElements(context, alignment));
+ elements.addAll(super.getNextKnuthElements(context, alignment, lmStack, restartPosition,
+ restartAtLM));
} while (!isFinished());
return elements;
}
-
}
diff --git a/src/java/org/apache/fop/layoutmgr/list/ListItemLayoutManager.java b/src/java/org/apache/fop/layoutmgr/list/ListItemLayoutManager.java
index 6404e9feb..ba49b7dc0 100644
--- a/src/java/org/apache/fop/layoutmgr/list/ListItemLayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/list/ListItemLayoutManager.java
@@ -20,9 +20,11 @@
package org.apache.fop.layoutmgr.list;
import java.util.ArrayList;
+import java.util.Collections;
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;
@@ -39,15 +41,16 @@ import org.apache.fop.layoutmgr.BreakOpportunity;
import org.apache.fop.layoutmgr.BreakOpportunityHelper;
import org.apache.fop.layoutmgr.ElementListObserver;
import org.apache.fop.layoutmgr.ElementListUtils;
+import org.apache.fop.layoutmgr.FloatContentLayoutManager;
import org.apache.fop.layoutmgr.FootenoteUtil;
import org.apache.fop.layoutmgr.Keep;
import org.apache.fop.layoutmgr.KnuthBlockBox;
-import org.apache.fop.layoutmgr.KnuthBox;
import org.apache.fop.layoutmgr.KnuthElement;
import org.apache.fop.layoutmgr.KnuthPenalty;
import org.apache.fop.layoutmgr.KnuthPossPosIter;
import org.apache.fop.layoutmgr.LayoutContext;
import org.apache.fop.layoutmgr.LayoutManager;
+import org.apache.fop.layoutmgr.LeafPosition;
import org.apache.fop.layoutmgr.ListElement;
import org.apache.fop.layoutmgr.NonLeafPosition;
import org.apache.fop.layoutmgr.Position;
@@ -79,11 +82,13 @@ public class ListItemLayoutManager extends SpacedBorderedPaddedBlockLayoutManage
private Keep keepWithNextPendingOnLabel;
private Keep keepWithNextPendingOnBody;
- private class ListItemPosition extends Position {
+ public class ListItemPosition extends Position {
private int labelFirstIndex;
private int labelLastIndex;
private int bodyFirstIndex;
private int bodyLastIndex;
+ private Position originalLabelPosition;
+ private Position originalBodyPosition;
public ListItemPosition(LayoutManager lm, int labelFirst, int labelLast,
int bodyFirst, int bodyLast) {
@@ -124,6 +129,22 @@ public class ListItemLayoutManager extends SpacedBorderedPaddedBlockLayoutManage
sb.append(")");
return sb.toString();
}
+
+ public Position getOriginalLabelPosition() {
+ return originalLabelPosition;
+ }
+
+ public void setOriginalLabelPosition(Position originalLabelPosition) {
+ this.originalLabelPosition = originalLabelPosition;
+ }
+
+ public Position getOriginalBodyPosition() {
+ return originalBodyPosition;
+ }
+
+ public void setOriginalBodyPosition(Position originalBodyPosition) {
+ this.originalBodyPosition = originalBodyPosition;
+ }
}
/**
@@ -188,8 +209,8 @@ public class ListItemLayoutManager extends SpacedBorderedPaddedBlockLayoutManage
}
/** {@inheritDoc} */
- @Override
- public List getNextKnuthElements(LayoutContext context, int alignment) {
+ public List getNextKnuthElements(LayoutContext context, int alignment, Stack lmStack,
+ Position restartPosition, LayoutManager restartAtLM) {
referenceIPD = context.getRefIPD();
LayoutContext childLC;
@@ -205,7 +226,30 @@ public class ListItemLayoutManager extends SpacedBorderedPaddedBlockLayoutManage
childLC = makeChildLayoutContext(context);
childLC.setFlags(LayoutContext.SUPPRESS_BREAK_BEFORE);
label.initialize();
- labelList = label.getNextKnuthElements(childLC, alignment);
+ boolean labelDone = false;
+ Stack labelLMStack = null;
+ Position labelRestartPosition = null;
+ LayoutManager labelRestartLM = null;
+ if (restartPosition != null && restartPosition instanceof ListItemPosition) {
+ ListItemPosition lip = (ListItemPosition) restartPosition;
+ if (lip.labelLastIndex <= lip.labelFirstIndex) {
+ labelDone = true;
+ } else {
+ labelRestartPosition = lip.getOriginalLabelPosition();
+ labelRestartLM = labelRestartPosition.getLM();
+ LayoutManager lm = labelRestartLM;
+ labelLMStack = new Stack();
+ while (lm != this) {
+ labelLMStack.push(lm);
+ lm = lm.getParent();
+ if (lm instanceof ListItemContentLayoutManager) {
+ lm = lm.getParent();
+ }
+ }
+ }
+ }
+ labelList = !labelDone ? label.getNextKnuthElements(childLC, alignment, labelLMStack,
+ labelRestartPosition, labelRestartLM) : new LinkedList<KnuthElement>();
//Space resolution as if the contents were placed in a new reference area
//(see 6.8.3, XSL 1.0, section on Constraints, last paragraph)
@@ -219,7 +263,30 @@ public class ListItemLayoutManager extends SpacedBorderedPaddedBlockLayoutManage
childLC = makeChildLayoutContext(context);
childLC.setFlags(LayoutContext.SUPPRESS_BREAK_BEFORE);
body.initialize();
- bodyList = body.getNextKnuthElements(childLC, alignment);
+ boolean bodyDone = false;
+ Stack bodyLMStack = null;
+ Position bodyRestartPosition = null;
+ LayoutManager bodyRestartLM = null;
+ if (restartPosition != null && restartPosition instanceof ListItemPosition) {
+ ListItemPosition lip = (ListItemPosition) restartPosition;
+ if (lip.bodyLastIndex <= lip.bodyFirstIndex) {
+ bodyDone = true;
+ } else {
+ bodyRestartPosition = lip.getOriginalBodyPosition();
+ bodyRestartLM = bodyRestartPosition.getLM();
+ LayoutManager lm = bodyRestartLM;
+ bodyLMStack = new Stack();
+ while (lm != this) {
+ bodyLMStack.push(lm);
+ lm = lm.getParent();
+ if (lm instanceof ListItemContentLayoutManager) {
+ lm = lm.getParent();
+ }
+ }
+ }
+ }
+ bodyList = !bodyDone ? body.getNextKnuthElements(childLC, alignment, bodyLMStack,
+ bodyRestartPosition, bodyRestartLM) : new LinkedList<KnuthElement>();
//Space resolution as if the contents were placed in a new reference area
//(see 6.8.3, XSL 1.0, section on Constraints, last paragraph)
@@ -229,8 +296,34 @@ public class ListItemLayoutManager extends SpacedBorderedPaddedBlockLayoutManage
context.updateKeepWithPreviousPending(childLC.getKeepWithPreviousPending());
this.keepWithNextPendingOnBody = childLC.getKeepWithNextPending();
+ List<ListElement> returnedList = new LinkedList<ListElement>();
+ if (!labelList.isEmpty() && labelList.get(0) instanceof KnuthBlockBox) {
+ KnuthBlockBox kbb = (KnuthBlockBox) labelList.get(0);
+ if (kbb.getWidth() == 0 && kbb.hasFloatAnchors()) {
+ List<FloatContentLayoutManager> floats = kbb.getFloatContentLMs();
+ returnedList.add(new KnuthBlockBox(0, Collections.emptyList(), null, false, floats));
+ Keep keep = getKeepTogether();
+ returnedList.add(new BreakElement(new LeafPosition(this, 0), keep.getPenalty(), keep
+ .getContext(), context));
+ labelList.remove(0);
+ labelList.remove(0);
+ }
+ }
+ if (!bodyList.isEmpty() && bodyList.get(0) instanceof KnuthBlockBox) {
+ KnuthBlockBox kbb = (KnuthBlockBox) bodyList.get(0);
+ if (kbb.getWidth() == 0 && kbb.hasFloatAnchors()) {
+ List<FloatContentLayoutManager> floats = kbb.getFloatContentLMs();
+ returnedList.add(new KnuthBlockBox(0, Collections.emptyList(), null, false, floats));
+ Keep keep = getKeepTogether();
+ returnedList.add(new BreakElement(new LeafPosition(this, 0), keep.getPenalty(), keep
+ .getContext(), context));
+ bodyList.remove(0);
+ bodyList.remove(0);
+ }
+ }
+
// create a combined list
- List returnedList = getCombinedKnuthElementsForListItem(labelList, bodyList, context);
+ returnedList.addAll(getCombinedKnuthElementsForListItem(labelList, bodyList, context));
// "wrap" the Position inside each element
wrapPositionElements(returnedList, returnList, true);
@@ -298,7 +391,9 @@ public class ListItemLayoutManager extends SpacedBorderedPaddedBlockLayoutManage
int additionalPenaltyHeight = 0;
int stepPenalty = 0;
int breakClass = EN_AUTO;
- KnuthElement endEl = (KnuthElement)elementLists[0].get(end[0]);
+ KnuthElement endEl = elementLists[0].size() > 0 ? (KnuthElement) elementLists[0].get(end[0])
+ : null;
+ Position originalLabelPosition = endEl != null ? endEl.getPosition().getPosition() : null;
if (endEl instanceof KnuthPenalty) {
additionalPenaltyHeight = endEl.getWidth();
stepPenalty = endEl.getPenalty() == -KnuthElement.INFINITE ? -KnuthElement.INFINITE : Math
@@ -306,7 +401,8 @@ public class ListItemLayoutManager extends SpacedBorderedPaddedBlockLayoutManage
breakClass = BreakUtil.compareBreakClasses(breakClass,
((KnuthPenalty) endEl).getBreakClass());
}
- endEl = (KnuthElement)elementLists[1].get(end[1]);
+ endEl = elementLists[1].size() > 0 ? (KnuthElement) elementLists[1].get(end[1]) : null;
+ Position originalBodyPosition = endEl != null ? endEl.getPosition().getPosition() : null;
if (endEl instanceof KnuthPenalty) {
additionalPenaltyHeight = Math.max(
additionalPenaltyHeight, endEl.getWidth());
@@ -327,13 +423,26 @@ public class ListItemLayoutManager extends SpacedBorderedPaddedBlockLayoutManage
footnoteList.addAll(FootenoteUtil.getFootnotes(elementLists[i], start[i], end[i]));
}
+ LinkedList<FloatContentLayoutManager> floats = new LinkedList<FloatContentLayoutManager>();
+ for (int i = 0; i < elementLists.length; i++) {
+ floats.addAll(FloatContentLayoutManager.checkForFloats(elementLists[i], start[i], end[i]));
+ }
+
// add the new elements
addedBoxHeight += boxHeight;
- ListItemPosition stepPosition = new ListItemPosition(this,
- start[0], end[0], start[1], end[1]);
- if (footnoteList.isEmpty()) {
- returnList.add(new KnuthBox(boxHeight, stepPosition, false));
+ ListItemPosition stepPosition = new ListItemPosition(this, start[0], end[0], start[1], end[1]);
+ stepPosition.setOriginalLabelPosition(originalLabelPosition);
+ stepPosition.setOriginalBodyPosition(originalBodyPosition);
+
+ if (floats.isEmpty()) {
+ returnList.add(new KnuthBlockBox(boxHeight, footnoteList, stepPosition, false));
} else {
+ // add a line with height zero and no content and attach float to it
+ returnList.add(new KnuthBlockBox(0, Collections.emptyList(), stepPosition, false, floats));
+ // add a break element to signal that we should restart LB at this break
+ Keep keep = getKeepTogether();
+ returnList.add(new BreakElement(stepPosition, keep.getPenalty(), keep.getContext(), context));
+ // add the original line where the float was but without the float now
returnList.add(new KnuthBlockBox(boxHeight, footnoteList, stepPosition, false));
}
@@ -512,6 +621,10 @@ public class ListItemLayoutManager extends SpacedBorderedPaddedBlockLayoutManage
positionList.add(pos.getPosition());
}
}
+ if (positionList.isEmpty()) {
+ reset();
+ return;
+ }
registerMarkers(true, isFirst(firstPos), isLast(lastPos));
@@ -674,5 +787,9 @@ public class ListItemLayoutManager extends SpacedBorderedPaddedBlockLayoutManage
return breakBefore;
}
+ /** {@inheritDoc} */
+ public boolean isRestartable() {
+ return true;
+ }
}