Browse Source

Handle middle-of-the-page case without using a glue.

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-ffa450edef68
tags/fop-2_0
Vincent Hennebert 10 years ago
parent
commit
f5e524b0b2

+ 5
- 7
src/java/org/apache/fop/layoutmgr/BestFitLayoutUtils.java View File

@@ -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;
}

+ 2
- 0
src/java/org/apache/fop/layoutmgr/BestFitPenalty.java View File

@@ -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() {

+ 2
- 30
src/java/org/apache/fop/layoutmgr/MultiCaseLayoutManager.java View File

@@ -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} */

+ 2
- 56
src/java/org/apache/fop/layoutmgr/MultiSwitchLayoutManager.java View File

@@ -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;
}

}

+ 16
- 11
src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java View File

@@ -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;

+ 6
- 5
test/layoutengine/standard-testcases/multi-switch_best-fit_multiple-variants.xml View File

@@ -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>

Loading…
Cancel
Save