Using a glue may cause a spurious empty page if the multi-switch is at the end of the flow, with no satisfying way of fixing that. Patch by Seifeddine Dridi git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_WhitespaceManagement@1582469 13f79535-47bb-0310-9956-ffa450edef68tags/fop-2_0
@@ -40,10 +40,12 @@ public final class BestFitLayoutUtils { | |||
public List<Position> getPositionList() { | |||
List<Position> positions = new LinkedList<Position>(); | |||
if (knuthList != null) { | |||
if (knuthList != null && !knuthList.isEmpty()) { | |||
SpaceResolver.performConditionalsNotification(knuthList, 0, knuthList.size() - 1, -1); | |||
for (ListElement elem : knuthList) { | |||
positions.add(elem.getPosition()); | |||
for (ListElement el : knuthList) { | |||
if (el.getPosition() != null) { | |||
positions.add(el.getPosition()); | |||
} | |||
} | |||
} | |||
return positions; | |||
@@ -75,10 +77,6 @@ public final class BestFitLayoutUtils { | |||
// when they are at the end of the Knuth list. | |||
knuthList.add(new KnuthBox(0, new Position(lm), false)); | |||
knuthList.add(bestFitPenalty); | |||
Variant firstVariant = bestFitPenalty.getVariants().get(0); | |||
BestFitPosition pos = new BestFitPosition(lm); | |||
pos.setKnuthList(firstVariant.knuthList); | |||
knuthList.add(new KnuthGlue(firstVariant.width, 0, 0, pos, false)); | |||
knuthList.add(new KnuthBox(0, new Position(lm), false)); | |||
return knuthList; | |||
} |
@@ -35,10 +35,12 @@ public class BestFitPenalty extends KnuthPenalty { | |||
public final List<ListElement> knuthList; | |||
public final int width; | |||
public int penaltyIndex; | |||
public Variant(List<ListElement> knuthList, int width) { | |||
this.knuthList = knuthList; | |||
this.width = width; | |||
this.penaltyIndex = -1; | |||
} | |||
public KnuthElement toPenalty() { |
@@ -18,14 +18,10 @@ | |||
package org.apache.fop.layoutmgr; | |||
import org.apache.fop.area.Area; | |||
import org.apache.fop.area.Block; | |||
import org.apache.fop.area.LineArea; | |||
import org.apache.fop.fo.FObj; | |||
public class MultiCaseLayoutManager extends BlockStackingLayoutManager { | |||
private Block curBlockArea; | |||
public MultiCaseLayoutManager(FObj node) { | |||
super(node); | |||
} | |||
@@ -47,36 +43,12 @@ public class MultiCaseLayoutManager extends BlockStackingLayoutManager { | |||
@Override | |||
public Area getParentArea(Area childArea) { | |||
if (curBlockArea == null) { | |||
curBlockArea = new Block(); | |||
curBlockArea.setIPD(super.getContentAreaIPD()); | |||
// Set up dimensions | |||
// Must get dimensions from parent area | |||
/*Area parentArea = */parentLayoutManager.getParentArea(curBlockArea); | |||
setCurrentArea(curBlockArea); | |||
} | |||
return curBlockArea; | |||
return parentLayoutManager.getParentArea(childArea); | |||
} | |||
@Override | |||
public void addChildArea(Area childArea) { | |||
if (curBlockArea != null) { | |||
if (childArea instanceof LineArea) { | |||
curBlockArea.addLineArea((LineArea) childArea); | |||
} else { | |||
curBlockArea.addBlock((Block) childArea); | |||
} | |||
} | |||
} | |||
/** | |||
* Force current area to be added to parent area. | |||
*/ | |||
@Override | |||
protected void flush() { | |||
if (getCurrentArea() != null) { | |||
super.flush(); | |||
} | |||
parentLayoutManager.addChildArea(childArea); | |||
} | |||
/** {@inheritDoc} */ |
@@ -22,14 +22,10 @@ import java.util.LinkedList; | |||
import java.util.List; | |||
import org.apache.fop.area.Area; | |||
import org.apache.fop.area.Block; | |||
import org.apache.fop.area.LineArea; | |||
import org.apache.fop.fo.FObj; | |||
public class MultiSwitchLayoutManager extends BlockStackingLayoutManager { | |||
private Block curBlockArea; | |||
public MultiSwitchLayoutManager(FObj node) { | |||
super(node); | |||
} | |||
@@ -55,61 +51,14 @@ public class MultiSwitchLayoutManager extends BlockStackingLayoutManager { | |||
return BestFitLayoutUtils.getKnuthList(this, childrenLists); | |||
} | |||
@Override | |||
public Keep getKeepTogether() { | |||
return Keep.KEEP_AUTO; | |||
} | |||
@Override | |||
public Keep getKeepWithNext() { | |||
return Keep.KEEP_AUTO; | |||
} | |||
@Override | |||
public Keep getKeepWithPrevious() { | |||
return Keep.KEEP_AUTO; | |||
} | |||
@Override | |||
public int getContentAreaIPD() { | |||
if (curBlockArea != null) { | |||
return curBlockArea.getIPD(); | |||
} | |||
return super.getContentAreaIPD(); | |||
} | |||
@Override | |||
public Area getParentArea(Area childArea) { | |||
if (curBlockArea == null) { | |||
curBlockArea = new Block(); | |||
curBlockArea.setIPD(super.getContentAreaIPD()); | |||
setCurrentArea(curBlockArea); | |||
// Set up dimensions | |||
// Must get dimensions from parent area | |||
/*Area parentArea = */parentLayoutManager.getParentArea(curBlockArea); | |||
} | |||
return curBlockArea; | |||
return parentLayoutManager.getParentArea(childArea); | |||
} | |||
@Override | |||
public void addChildArea(Area childArea) { | |||
if (curBlockArea != null) { | |||
if (childArea instanceof LineArea) { | |||
curBlockArea.addLineArea((LineArea) childArea); | |||
} else { | |||
curBlockArea.addBlock((Block) childArea); | |||
} | |||
} | |||
} | |||
/** | |||
* Force current area to be added to parent area. | |||
*/ | |||
@Override | |||
protected void flush() { | |||
if (curBlockArea != null) { | |||
parentLayoutManager.addChildArea(getCurrentArea()); | |||
} | |||
parentLayoutManager.addChildArea(childArea); | |||
} | |||
@Override | |||
@@ -121,9 +70,6 @@ public class MultiSwitchLayoutManager extends BlockStackingLayoutManager { | |||
AreaAdditionUtil.addAreas(this, newPosIter, context); | |||
flush(); | |||
// TODO removing the following line forces the generated area | |||
// to be rendered twice in some cases... | |||
curBlockArea = null; | |||
} | |||
} |
@@ -99,9 +99,6 @@ class PageBreakingAlgorithm extends BreakingAlgorithm { | |||
private int currentKeepContext = Constants.EN_AUTO; | |||
private KnuthNode lastBeforeKeepContextSwitch; | |||
/** Holds the variant of a dynamic content that must be attached to the next page node */ | |||
private Variant variant; | |||
/** | |||
* Construct a page breaking algorithm. | |||
* @param topLevelLM the top level layout manager | |||
@@ -156,7 +153,10 @@ class PageBreakingAlgorithm extends BreakingAlgorithm { | |||
/** Index of the last inserted element of the last inserted footnote. */ | |||
public int footnoteElementIndex; | |||
/** Current active variant attached to this node */ | |||
public final Variant variant; | |||
/** Pending variant to be assigned to all descending nodes */ | |||
public Variant pendingVariant; | |||
public KnuthPageNode(int position, | |||
int line, int fitness, | |||
@@ -201,7 +201,7 @@ class PageBreakingAlgorithm extends BreakingAlgorithm { | |||
bestTotalFootnotesLength[fitness] = totalFootnotesLength; | |||
bestFootnoteListIndex[fitness] = footnoteListIndex; | |||
bestFootnoteElementIndex[fitness] = footnoteElementIndex; | |||
bestVariant[fitness] = variant; | |||
bestVariant[fitness] = ((KnuthPageNode) node).pendingVariant; | |||
} | |||
public int getInsertedFootnotesLength(int fitness) { | |||
@@ -223,6 +223,7 @@ class PageBreakingAlgorithm extends BreakingAlgorithm { | |||
public Variant getVariant(int fitness) { | |||
return bestVariant[fitness]; | |||
} | |||
} | |||
/** {@inheritDoc} */ | |||
@@ -315,7 +316,8 @@ class PageBreakingAlgorithm extends BreakingAlgorithm { | |||
insertedFootnotesLength, totalFootnotesLength, | |||
footnoteListIndex, footnoteElementIndex, | |||
adjustRatio, availableShrink, availableStretch, | |||
difference, totalDemerits, previous, variant); | |||
difference, totalDemerits, previous, | |||
(previous != null) ? ((KnuthPageNode)previous).pendingVariant : null); | |||
} | |||
/** {@inheritDoc} */ | |||
@@ -525,12 +527,14 @@ class PageBreakingAlgorithm extends BreakingAlgorithm { | |||
int actualWidth = totalWidth - pageNode.totalWidth; | |||
int footnoteSplit; | |||
boolean canDeferOldFN; | |||
variant = null; | |||
if (element.isPenalty()) { | |||
if (element instanceof BestFitPenalty) { | |||
actualWidth += handleBestFitPenalty(activeNode, (BestFitPenalty) element, elementIndex); | |||
actualWidth += handleBestFitPenalty(pageNode, (BestFitPenalty) element, elementIndex); | |||
} else { | |||
actualWidth += element.getWidth(); | |||
if (pageNode.pendingVariant != null) { | |||
actualWidth += ((KnuthPageNode) activeNode).pendingVariant.width; | |||
} | |||
} | |||
} | |||
if (footnotesPending) { | |||
@@ -591,13 +595,14 @@ class PageBreakingAlgorithm extends BreakingAlgorithm { | |||
} | |||
} | |||
private int handleBestFitPenalty(KnuthNode activeNode, BestFitPenalty penalty, int elementIndex) { | |||
private int handleBestFitPenalty(KnuthPageNode activeNode, BestFitPenalty penalty, int elementIndex) { | |||
for (Variant var : penalty.getVariants()) { | |||
int difference = computeDifference(activeNode, var.toPenalty(), elementIndex); | |||
double r = computeAdjustmentRatio(activeNode, difference); | |||
if (r >= -1.0) { | |||
variant = var; | |||
return variant.width; | |||
var.penaltyIndex = elementIndex; | |||
activeNode.pendingVariant = var; | |||
return var.width; | |||
} | |||
} | |||
return 0; | |||
@@ -1018,7 +1023,7 @@ class PageBreakingAlgorithm extends BreakingAlgorithm { | |||
// Check if the given node has an attached variant of a dynamic content | |||
KnuthPageNode pageNode = (KnuthPageNode) bestActiveNode; | |||
if (pageNode.variant != null) { | |||
BestFitPenalty penalty = (BestFitPenalty) par.get(pageNode.position); | |||
BestFitPenalty penalty = (BestFitPenalty) par.get(pageNode.variant.penaltyIndex); | |||
penalty.setActiveVariant(pageNode.variant); | |||
} | |||
int difference = bestActiveNode.difference; |
@@ -106,13 +106,13 @@ | |||
<!-- 1. First variant --> | |||
<eval expected="3" xpath="count(//pageSequence[1]/pageViewport)"/> | |||
<eval expected="Filler" xpath="//pageSequence[1]/pageViewport[2]//flow/block[1]"/> | |||
<eval expected="Variant 1 line 1" xpath="//pageSequence[1]/pageViewport[2]//flow/block[3]/block/block[1]"/> | |||
<eval expected="Variant 1 line 1" xpath="//pageSequence[1]/pageViewport[2]//flow/block[3]"/> | |||
<eval expected="This text should be on page 3." xpath="//pageSequence[1]/pageViewport[3]//flow/block[1]"/> | |||
<!-- 2. Second variant --> | |||
<eval expected="3" xpath="count(//pageSequence[2]/pageViewport)"/> | |||
<eval expected="Page 2 line 1" xpath="//pageSequence[2]/pageViewport[2]//flow/block[1]"/> | |||
<eval expected="Variant 2 line 1" xpath="//pageSequence[2]/pageViewport[2]//flow/block[4]/block/block[1]"/> | |||
<eval expected="Variant 2 line 1" xpath="//pageSequence[2]/pageViewport[2]//flow/block[4]"/> | |||
<eval expected="This text should be on page 3." xpath="//pageSequence[2]/pageViewport[3]//flow/block[1]"/> | |||
<!-- 3. No variant --> | |||
@@ -122,8 +122,9 @@ | |||
<eval expected="Page 2 line 2" xpath="//pageSequence[3]/pageViewport[2]//flow/block[2]"/> | |||
<eval expected="Filler" xpath="//pageSequence[3]/pageViewport[2]//flow/block[3]"/> | |||
<eval expected="Before the multi-switch" xpath="//pageSequence[3]/pageViewport[2]//flow/block[4]"/> | |||
<eval expected="2" xpath="count(//pageSequence[3]/pageViewport[3]//flow/block)"/> | |||
<eval expected="Variant 1 line 1" xpath="//pageSequence[3]/pageViewport[3]//flow/block[1]/block/block[1]"/> | |||
<eval expected="This text should be on page 3." xpath="//pageSequence[3]/pageViewport[3]//flow/block[2]"/> | |||
<eval expected="3" xpath="count(//pageSequence[3]/pageViewport[3]//flow/block)"/> | |||
<eval expected="Variant 1 line 1" xpath="//pageSequence[3]/pageViewport[3]//flow/block[1]"/> | |||
<eval expected="Variant 1 line 2" xpath="//pageSequence[3]/pageViewport[3]//flow/block[2]"/> | |||
<eval expected="This text should be on page 3." xpath="//pageSequence[3]/pageViewport[3]//flow/block[3]"/> | |||
</checks> | |||
</testcase> |