Modified MultiSwitchLM to have its standard behaviour by default. Moved BestFitLayoutUtils into MultiSwitchLM. Code clean-up and javadoc. Patch by Seifeddine Dridi, applied with some modifications. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_WhitespaceManagement@1585822 13f79535-47bb-0310-9956-ffa450edef68tags/fop-2_0
@@ -38,9 +38,7 @@ public class MultiSwitch extends FObj { | |||
// private CommonAccessibility commonAccessibility; | |||
// End of property values | |||
private FONode currentlyVisibleMultiCase; | |||
private String autoToggle; | |||
private String fittingStrategy; | |||
/** | |||
* Base constructor | |||
@@ -97,18 +95,6 @@ public class MultiSwitch extends FObj { | |||
return FO_MULTI_SWITCH; | |||
} | |||
public void setCurrentlyVisibleNode(FONode node) { | |||
currentlyVisibleMultiCase = node; | |||
} | |||
public FONode getCurrentlyVisibleNode() { | |||
return currentlyVisibleMultiCase; | |||
} | |||
public String getFittingStrategy() { | |||
return fittingStrategy; | |||
} | |||
public String getAutoToggle() { | |||
return autoToggle; | |||
} |
@@ -1,100 +0,0 @@ | |||
/* | |||
* 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. | |||
*/ | |||
package org.apache.fop.layoutmgr; | |||
import java.util.LinkedList; | |||
import java.util.List; | |||
import org.apache.fop.layoutmgr.BestFitPenalty.Variant; | |||
/** | |||
* Utility class used in {@link MultiSwitchLayoutManager} | |||
* to handle the <i>best-fit</i> property value if specified in {@link org.apache.fop.fo.flow.MultiSwitch} | |||
*/ | |||
public final class BestFitLayoutUtils { | |||
private BestFitLayoutUtils() { } | |||
static class BestFitPosition extends Position { | |||
private List<ListElement> knuthList; | |||
public BestFitPosition(LayoutManager lm) { | |||
super(lm); | |||
} | |||
public List<Position> getPositionList() { | |||
List<Position> positions = new LinkedList<Position>(); | |||
if (knuthList != null && !knuthList.isEmpty()) { | |||
SpaceResolver.performConditionalsNotification(knuthList, 0, knuthList.size() - 1, -1); | |||
for (ListElement el : knuthList) { | |||
if (el.getPosition() != null) { | |||
positions.add(el.getPosition()); | |||
} | |||
} | |||
} | |||
return positions; | |||
} | |||
public void setKnuthList(List<ListElement> knuthList) { | |||
this.knuthList = knuthList; | |||
} | |||
} | |||
public static List<ListElement> getKnuthList(LayoutManager lm, | |||
List<List<ListElement>> childrenLists) { | |||
List<ListElement> knuthList = new LinkedList<ListElement>(); | |||
BestFitPenalty bestFitPenalty = new BestFitPenalty(new BestFitPosition(lm)); | |||
for (List<ListElement> childList : childrenLists) { | |||
// TODO Doing space resolution here is not correct. | |||
// Space elements will simply be nulled. | |||
SpaceResolver.resolveElementList(childList); | |||
int contentLength = ElementListUtils.calcContentLength(childList); | |||
bestFitPenalty.addVariant(new Variant(childList, contentLength)); | |||
} | |||
// TODO Adding two enclosing boxes is definitely a dirty hack. | |||
// The first box forces the breaking algorithm to consider the penalty | |||
// in case there are no elements preceding it | |||
// and the last box prevents the glue and penalty from getting deleted | |||
// when they are at the end of the Knuth list. | |||
knuthList.add(new KnuthBox(0, new Position(lm), false)); | |||
knuthList.add(bestFitPenalty); | |||
knuthList.add(new KnuthBox(0, new Position(lm), false)); | |||
return knuthList; | |||
} | |||
public static List<Position> getPositionList(LayoutManager lm, PositionIterator posIter) { | |||
// "unwrap" the NonLeafPositions stored in parentIter | |||
// and put them in a new list; | |||
LinkedList<Position> positionList = new LinkedList<Position>(); | |||
while (posIter.hasNext()) { | |||
Position pos = posIter.next(); | |||
if (pos instanceof BestFitPosition) { | |||
positionList.addAll(((BestFitPosition) pos).getPositionList()); | |||
} else { | |||
positionList.add(pos); | |||
} | |||
} | |||
return positionList; | |||
} | |||
} |
@@ -451,18 +451,8 @@ public class LayoutManagerMapping implements LayoutManagerMaker { | |||
@Override | |||
public void make(FONode node, List lms) { | |||
MultiSwitch multiSwitch = (MultiSwitch) node; | |||
MultiSwitchLayoutManager mslm = new MultiSwitchLayoutManager(multiSwitch); | |||
FONode multiCase = multiSwitch.getCurrentlyVisibleNode(); | |||
if (multiCase != null) { | |||
FONodeIterator childIter = multiCase.getChildNodes(); | |||
while (childIter.hasNext()) { | |||
FONode child = (FONode) childIter.next(); | |||
makeLayoutManagers(child, lms); | |||
} | |||
} else { | |||
lms.add(mslm); | |||
} | |||
MultiSwitchLayoutManager mslm = new MultiSwitchLayoutManager((MultiSwitch) node); | |||
lms.add(mslm); | |||
} | |||
} | |||
@@ -17,38 +17,123 @@ | |||
package org.apache.fop.layoutmgr; | |||
import java.util.ArrayList; | |||
import java.util.LinkedList; | |||
import java.util.List; | |||
import org.apache.fop.area.Area; | |||
import org.apache.fop.fo.FObj; | |||
import org.apache.fop.fo.flow.MultiSwitch; | |||
public class MultiSwitchLayoutManager extends BlockStackingLayoutManager { | |||
static class WhitespaceManagementPosition extends Position { | |||
private List<ListElement> knuthList; | |||
public WhitespaceManagementPosition(LayoutManager lm) { | |||
super(lm); | |||
} | |||
public List<Position> getPositionList() { | |||
List<Position> positions = new LinkedList<Position>(); | |||
if (knuthList != null && !knuthList.isEmpty()) { | |||
SpaceResolver.performConditionalsNotification(knuthList, 0, knuthList.size() - 1, -1); | |||
for (ListElement el : knuthList) { | |||
if (el.getPosition() != null) { | |||
positions.add(el.getPosition()); | |||
} | |||
} | |||
} | |||
return positions; | |||
} | |||
public void setKnuthList(List<ListElement> knuthList) { | |||
this.knuthList = knuthList; | |||
} | |||
public List<ListElement> getKnuthList() { | |||
return knuthList; | |||
} | |||
} | |||
private interface KnuthElementsGenerator { | |||
List<ListElement> getKnuthElement(LayoutContext context, int alignment); | |||
} | |||
private class DefaultKnuthListGenerator implements KnuthElementsGenerator { | |||
public List<ListElement> getKnuthElement(LayoutContext context, int alignment) { | |||
List<ListElement> knuthList = new LinkedList<ListElement>(); | |||
LayoutManager childLM; | |||
while ((childLM = getChildLM()) != null) { | |||
if (!childLM.isFinished()) { | |||
LayoutContext childLC = makeChildLayoutContext(context); | |||
List childElements = childLM.getNextKnuthElements(childLC, alignment); | |||
if (childElements != null) { | |||
List<ListElement> newList = new LinkedList<ListElement>(); | |||
wrapPositionElements(childElements, newList); | |||
knuthList.addAll(newList); | |||
} | |||
} | |||
} | |||
return knuthList; | |||
} | |||
} | |||
private class WhitespaceManagement implements KnuthElementsGenerator { | |||
public List<ListElement> getKnuthElement(LayoutContext context, int alignment) { | |||
MultiSwitchLayoutManager mslm = MultiSwitchLayoutManager.this; | |||
List<ListElement> knuthList = new LinkedList<ListElement>(); | |||
WhitespaceManagementPenalty penalty = new WhitespaceManagementPenalty( | |||
new WhitespaceManagementPosition(mslm)); | |||
LayoutManager childLM; | |||
while ((childLM = getChildLM()) != null) { | |||
if (!childLM.isFinished()) { | |||
LayoutContext childLC = makeChildLayoutContext(context); | |||
List childElements = childLM.getNextKnuthElements(childLC, alignment); | |||
if (childElements != null) { | |||
List<ListElement> newList = new LinkedList<ListElement>(); | |||
wrapPositionElements(childElements, newList); | |||
// TODO Doing space resolution here is wrong. | |||
SpaceResolver.resolveElementList(newList); | |||
int contentLength = ElementListUtils.calcContentLength(newList); | |||
penalty.addVariant(penalty.new Variant(newList, contentLength)); | |||
} | |||
} | |||
} | |||
// Prevent the penalty from being ignored if it is at the beginning of the content | |||
knuthList.add(new KnuthBox(0, new Position(mslm), false)); | |||
knuthList.add(penalty); | |||
// Prevent the penalty from being ignored if it is at the end of the content | |||
knuthList.add(new KnuthBox(0, new Position(mslm), false)); | |||
return knuthList; | |||
} | |||
} | |||
private KnuthElementsGenerator knuthGen; | |||
public MultiSwitchLayoutManager(FObj node) { | |||
super(node); | |||
MultiSwitch multiSwitchNode = (MultiSwitch) node; | |||
if (multiSwitchNode.getAutoToggle().equals("best-fit")) { | |||
knuthGen = new WhitespaceManagement(); | |||
} else { | |||
knuthGen = new DefaultKnuthListGenerator(); | |||
} | |||
} | |||
@Override | |||
public List<ListElement> getNextKnuthElements(LayoutContext context, int alignment) { | |||
referenceIPD = context.getRefIPD(); | |||
List<List<ListElement>> childrenLists = new ArrayList<List<ListElement>>(); | |||
LayoutManager childLM; | |||
while ((childLM = getChildLM()) != null) { | |||
if (!childLM.isFinished()) { | |||
LayoutContext childLC = makeChildLayoutContext(context); | |||
List childElements = childLM.getNextKnuthElements(childLC, alignment); | |||
if (childElements != null) { | |||
List<ListElement> newList = new LinkedList<ListElement>(); | |||
wrapPositionElements(childElements, newList); | |||
childrenLists.add(newList); | |||
} | |||
} | |||
} | |||
List<ListElement> knuthList = knuthGen.getKnuthElement(context, alignment); | |||
setFinished(true); | |||
return BestFitLayoutUtils.getKnuthList(this, childrenLists); | |||
return knuthList; | |||
} | |||
@Override | |||
@@ -63,11 +148,16 @@ public class MultiSwitchLayoutManager extends BlockStackingLayoutManager { | |||
@Override | |||
public void addAreas(PositionIterator posIter, LayoutContext context) { | |||
List<Position> positionList = BestFitLayoutUtils.getPositionList(this, posIter); | |||
PositionIterator newPosIter = new PositionIterator( | |||
positionList.listIterator()); | |||
LinkedList<Position> positionList = new LinkedList<Position>(); | |||
while (posIter.hasNext()) { | |||
Position pos = posIter.next(); | |||
if (pos instanceof WhitespaceManagementPosition) { | |||
positionList.addAll(((WhitespaceManagementPosition) pos).getPositionList()); | |||
} else { | |||
positionList.add(pos); | |||
} | |||
} | |||
PositionIterator newPosIter = new PositionIterator(positionList.listIterator()); | |||
AreaAdditionUtil.addAreas(this, newPosIter, context); | |||
flush(); | |||
} |
@@ -30,7 +30,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.PageBreakPosition; | |||
import org.apache.fop.layoutmgr.BestFitPenalty.Variant; | |||
import org.apache.fop.layoutmgr.WhitespaceManagementPenalty.Variant; | |||
import org.apache.fop.traits.MinOptMax; | |||
import org.apache.fop.util.ListUtil; | |||
@@ -153,10 +153,13 @@ 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; | |||
/** | |||
* Pending variants of dynamic contents that were evaluated WRT this node. | |||
* When computing page difference for a break element, the total width of these variants | |||
* will be added to 'actualWidth'. | |||
*/ | |||
private final List<Variant> pendingVariants = new ArrayList<Variant>(); | |||
private int totalVariantsWidth; | |||
public KnuthPageNode(int position, | |||
int line, int fitness, | |||
@@ -164,7 +167,7 @@ class PageBreakingAlgorithm extends BreakingAlgorithm { | |||
int insertedFootnotes, int totalFootnotes, | |||
int footnoteListIndex, int footnoteElementIndex, | |||
double adjustRatio, int availableShrink, int availableStretch, | |||
int difference, double totalDemerits, KnuthNode previous, Variant variant) { | |||
int difference, double totalDemerits, KnuthNode previous) { | |||
super(position, line, fitness, | |||
totalWidth, totalStretch, totalShrink, | |||
adjustRatio, availableShrink, availableStretch, | |||
@@ -173,7 +176,11 @@ class PageBreakingAlgorithm extends BreakingAlgorithm { | |||
this.insertedFootnotes = insertedFootnotes; | |||
this.footnoteListIndex = footnoteListIndex; | |||
this.footnoteElementIndex = footnoteElementIndex; | |||
this.variant = variant; | |||
} | |||
public void addVariant(Variant variant) { | |||
pendingVariants.add(variant); | |||
totalVariantsWidth += variant.width; | |||
} | |||
} | |||
@@ -188,7 +195,6 @@ class PageBreakingAlgorithm extends BreakingAlgorithm { | |||
private final int[] bestTotalFootnotesLength = new int[4]; | |||
private final int[] bestFootnoteListIndex = new int[4]; | |||
private final int[] bestFootnoteElementIndex = new int[4]; | |||
private final Variant[] bestVariant = new Variant[4]; | |||
@Override | |||
public void addRecord(double demerits, KnuthNode node, double adjust, | |||
@@ -201,7 +207,6 @@ class PageBreakingAlgorithm extends BreakingAlgorithm { | |||
bestTotalFootnotesLength[fitness] = totalFootnotesLength; | |||
bestFootnoteListIndex[fitness] = footnoteListIndex; | |||
bestFootnoteElementIndex[fitness] = footnoteElementIndex; | |||
bestVariant[fitness] = ((KnuthPageNode) node).pendingVariant; | |||
} | |||
public int getInsertedFootnotesLength(int fitness) { | |||
@@ -220,9 +225,6 @@ class PageBreakingAlgorithm extends BreakingAlgorithm { | |||
return bestFootnoteElementIndex[fitness]; | |||
} | |||
public Variant getVariant(int fitness) { | |||
return bestVariant[fitness]; | |||
} | |||
} | |||
@@ -316,8 +318,7 @@ class PageBreakingAlgorithm extends BreakingAlgorithm { | |||
insertedFootnotesLength, totalFootnotesLength, | |||
footnoteListIndex, footnoteElementIndex, | |||
adjustRatio, availableShrink, availableStretch, | |||
difference, totalDemerits, previous, | |||
(previous != null) ? ((KnuthPageNode)previous).pendingVariant : null); | |||
difference, totalDemerits, previous); | |||
} | |||
/** {@inheritDoc} */ | |||
@@ -332,8 +333,7 @@ class PageBreakingAlgorithm extends BreakingAlgorithm { | |||
((BestPageRecords) best).getFootnoteElementIndex(fitness), | |||
best.getAdjust(fitness), best.getAvailableShrink(fitness), | |||
best.getAvailableStretch(fitness), best.getDifference(fitness), | |||
best.getDemerits(fitness), best.getNode(fitness), | |||
((BestPageRecords) best).getVariant(fitness)); | |||
best.getDemerits(fitness), best.getNode(fitness)); | |||
} | |||
/** | |||
@@ -527,15 +527,12 @@ class PageBreakingAlgorithm extends BreakingAlgorithm { | |||
int actualWidth = totalWidth - pageNode.totalWidth; | |||
int footnoteSplit; | |||
boolean canDeferOldFN; | |||
if (element.isPenalty()) { | |||
if (element instanceof BestFitPenalty) { | |||
actualWidth += handleBestFitPenalty(pageNode, (BestFitPenalty) element, elementIndex); | |||
} else { | |||
actualWidth += element.getWidth(); | |||
if (pageNode.pendingVariant != null) { | |||
actualWidth += ((KnuthPageNode) activeNode).pendingVariant.width; | |||
} | |||
} | |||
actualWidth += pageNode.totalVariantsWidth; | |||
if (element instanceof WhitespaceManagementPenalty) { | |||
actualWidth += handleWhitespaceManagementPenalty(pageNode, | |||
(WhitespaceManagementPenalty) element, elementIndex); | |||
} else if (element.isPenalty()) { | |||
actualWidth += element.getWidth(); | |||
} | |||
if (footnotesPending) { | |||
// compute the total length of the footnotes not yet inserted | |||
@@ -595,13 +592,18 @@ class PageBreakingAlgorithm extends BreakingAlgorithm { | |||
} | |||
} | |||
private int handleBestFitPenalty(KnuthPageNode activeNode, BestFitPenalty penalty, int elementIndex) { | |||
/** | |||
* Evaluates the variants corresponding to the given penalty until one that | |||
* leads to an acceptable adjustment ratio is found. That variant will | |||
* be added to the list of pending variants in the given active node. | |||
*/ | |||
private int handleWhitespaceManagementPenalty(KnuthPageNode activeNode, | |||
WhitespaceManagementPenalty penalty, int elementIndex) { | |||
for (Variant var : penalty.getVariants()) { | |||
int difference = computeDifference(activeNode, var.toPenalty(), elementIndex); | |||
double r = computeAdjustmentRatio(activeNode, difference); | |||
if (r >= -1.0) { | |||
var.penaltyIndex = elementIndex; | |||
activeNode.pendingVariant = var; | |||
activeNode.addVariant(var); | |||
return var.width; | |||
} | |||
} | |||
@@ -1022,9 +1024,14 @@ class PageBreakingAlgorithm extends BreakingAlgorithm { | |||
// ? bestActiveNode.difference : bestActiveNode.difference + fillerMinWidth; | |||
// 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.variant.penaltyIndex); | |||
penalty.setActiveVariant(pageNode.variant); | |||
KnuthPageNode previousPageNode = ((KnuthPageNode) pageNode.previous); | |||
for (Variant var : previousPageNode.pendingVariants) { | |||
WhitespaceManagementPenalty penalty = var.getBestFitPenalty(); | |||
int penaltyIndex = this.par.indexOf(penalty); | |||
// Make sure penalty is inside the range of the current page node | |||
if (penaltyIndex <= pageNode.position) { | |||
penalty.setActiveVariant(var); | |||
} | |||
} | |||
int difference = bestActiveNode.difference; | |||
if (difference + bestActiveNode.availableShrink < 0) { |
@@ -22,39 +22,42 @@ package org.apache.fop.layoutmgr; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import org.apache.fop.layoutmgr.BestFitLayoutUtils.BestFitPosition; | |||
import org.apache.fop.layoutmgr.MultiSwitchLayoutManager.WhitespaceManagementPosition; | |||
/** | |||
* A type of penalty used to specify a set of alternatives for the layout engine | |||
* to choose from. The chosen alternative must have an occupied size | |||
* less than the remaining BPD on the active page. | |||
* A special penalty used to specify content having multiple variants. At most | |||
* only one variant will be inserted into the final document. If none of the | |||
* variants fit into the remaining space on the current page, the dynamic | |||
* content will be completely ignored. | |||
*/ | |||
public class BestFitPenalty extends KnuthPenalty { | |||
public class WhitespaceManagementPenalty extends KnuthPenalty { | |||
public static class Variant { | |||
public class Variant { | |||
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() { | |||
return new KnuthPenalty(width, 0, false, null, false); | |||
} | |||
public WhitespaceManagementPenalty getBestFitPenalty() { | |||
return WhitespaceManagementPenalty.this; | |||
} | |||
} | |||
private final BestFitPosition bestFitPosition; | |||
private final WhitespaceManagementPosition whitespaceManagementPosition; | |||
private final List<Variant> variantList; | |||
public BestFitPenalty(BestFitPosition pos) { | |||
public WhitespaceManagementPenalty(WhitespaceManagementPosition pos) { | |||
super(0, 0, false, pos, false); | |||
this.bestFitPosition = pos; | |||
this.whitespaceManagementPosition = pos; | |||
variantList = new ArrayList<Variant>(); | |||
} | |||
@@ -63,7 +66,11 @@ public class BestFitPenalty extends KnuthPenalty { | |||
} | |||
public void setActiveVariant(Variant bestVariant) { | |||
bestFitPosition.setKnuthList(bestVariant.knuthList); | |||
whitespaceManagementPosition.setKnuthList(bestVariant.knuthList); | |||
} | |||
public boolean isActivated() { | |||
return whitespaceManagementPosition.getKnuthList() != null; | |||
} | |||
public List<Variant> getVariants() { |
@@ -0,0 +1,98 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> | |||
<!-- | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
--> | |||
<testcase> | |||
<info> | |||
<p> | |||
Test that multiple whitespace managment elements on the same page are handled nicely. | |||
</p> | |||
</info> | |||
<fo> | |||
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" | |||
xmlns:fox="http://xmlgraphics.apache.org/fop/extensions" font-size="8pt" line-height="10pt"> | |||
<fo:layout-master-set> | |||
<fo:simple-page-master master-name="page" | |||
page-height="70pt" page-width="220pt" margin="10pt"> | |||
<fo:region-body background-color="#F0F0F0"/> | |||
</fo:simple-page-master> | |||
</fo:layout-master-set> | |||
<fo:page-sequence master-reference="page"> | |||
<fo:flow flow-name="xsl-region-body"> | |||
<fo:multi-switch fox:auto-toggle="best-fit"> | |||
<fo:multi-case> | |||
<fo:block>MS 1 Variant 1</fo:block> | |||
</fo:multi-case> | |||
</fo:multi-switch> | |||
<fo:multi-switch fox:auto-toggle="best-fit"> | |||
<fo:multi-case> | |||
<fo:block>MS 2 Variant 1</fo:block> | |||
</fo:multi-case> | |||
</fo:multi-switch> | |||
<fo:multi-switch fox:auto-toggle="best-fit"> | |||
<fo:multi-case> | |||
<fo:block>MS 3 Variant 1</fo:block> | |||
</fo:multi-case> | |||
</fo:multi-switch> | |||
</fo:flow> | |||
</fo:page-sequence> | |||
<fo:page-sequence master-reference="page"> | |||
<fo:flow flow-name="xsl-region-body"> | |||
<fo:multi-switch fox:auto-toggle="best-fit"> | |||
<fo:multi-case> | |||
<fo:block line-height="70pt">MS 1 Variant 1</fo:block> | |||
</fo:multi-case> | |||
</fo:multi-switch> | |||
<fo:multi-switch fox:auto-toggle="best-fit"> | |||
<fo:multi-case> | |||
<fo:block>MS 2 Variant 1</fo:block> | |||
</fo:multi-case> | |||
</fo:multi-switch> | |||
<fo:multi-switch fox:auto-toggle="best-fit"> | |||
<fo:multi-case> | |||
<fo:block line-height="50pt">MS 3 Variant 1</fo:block> | |||
</fo:multi-case> | |||
<fo:multi-case> | |||
<fo:block>MS 3 Variant 2</fo:block> | |||
</fo:multi-case> | |||
</fo:multi-switch> | |||
<fo:multi-switch fox:auto-toggle="best-fit"> | |||
<fo:multi-case> | |||
<fo:block>MS 4 Variant 1</fo:block> | |||
</fo:multi-case> | |||
</fo:multi-switch> | |||
</fo:flow> | |||
</fo:page-sequence> | |||
</fo:root> | |||
</fo> | |||
<checks> | |||
<!-- 1. 3 multi-switch on the same page --> | |||
<eval expected="1" xpath="count(//pageSequence[1]/pageViewport)"/> | |||
<eval expected="3" xpath="count(//pageSequence[1]/pageViewport[1]//flow/block)"/> | |||
<eval expected="MS 1 Variant 1" xpath="//pageSequence[1]/pageViewport[1]//flow/block[1]"/> | |||
<eval expected="MS 2 Variant 1" xpath="//pageSequence[1]/pageViewport[1]//flow/block[2]"/> | |||
<eval expected="MS 3 Variant 1" xpath="//pageSequence[1]/pageViewport[1]//flow/block[3]"/> | |||
<!-- 2. 4 multi-switch, one cannot fit, one uses the 2nd variant --> | |||
<eval expected="1" xpath="count(//pageSequence[2]/pageViewport)"/> | |||
<eval expected="3" xpath="count(//pageSequence[2]/pageViewport[1]//flow/block)"/> | |||
<eval expected="MS 2 Variant 1" xpath="//pageSequence[2]/pageViewport[1]//flow/block[1]"/> | |||
<eval expected="MS 3 Variant 2" xpath="//pageSequence[2]/pageViewport[1]//flow/block[2]"/> | |||
<eval expected="MS 4 Variant 1" xpath="//pageSequence[2]/pageViewport[1]//flow/block[3]"/> | |||
</checks> | |||
</testcase> |