diff options
Diffstat (limited to 'src/java')
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; + } } |