diff options
24 files changed, 1061 insertions, 73 deletions
diff --git a/src/java/org/apache/fop/fo/Constants.java b/src/java/org/apache/fop/fo/Constants.java index 086cbca40..2d53d1d46 100644 --- a/src/java/org/apache/fop/fo/Constants.java +++ b/src/java/org/apache/fop/fo/Constants.java @@ -819,8 +819,11 @@ public interface Constants { /** For specifying PDF optional content group (layer) binding. */ int PR_X_LAYER = 291; + /** Property constant */ + int PR_X_AUTO_TOGGLE = 292; + /** Number of property constants defined */ - int PROPERTY_COUNT = 291; + int PROPERTY_COUNT = 292; // compound property constants @@ -1260,6 +1263,8 @@ public interface Constants { int EN_TB_LR = 205; // for top-to-bottom, left-to-right writing mode /** Enumeration constant -- for fo:retrieve-table-marker */ int EN_FIRST_INCLUDING_CARRYOVER = 206; + /** Enumeration constant -- for auto-toggle */ + int EN_SELECT_FIRST_FITTING = 207; /** Number of enumeration constants defined */ - int ENUM_COUNT = 206; + int ENUM_COUNT = 207; } diff --git a/src/java/org/apache/fop/fo/FOPropertyMapping.java b/src/java/org/apache/fop/fo/FOPropertyMapping.java index cc4fe9e2c..16f7ab457 100644 --- a/src/java/org/apache/fop/fo/FOPropertyMapping.java +++ b/src/java/org/apache/fop/fo/FOPropertyMapping.java @@ -581,6 +581,7 @@ public final class FOPropertyMapping implements Constants { // background-color m = new ColorProperty.Maker(PR_BACKGROUND_COLOR) { + @Override protected Property convertPropertyDatatype( Property p, PropertyList propertyList, FObj fo) throws PropertyException { String nameval = p.getNCname(); @@ -1620,6 +1621,7 @@ public final class FOPropertyMapping implements Constants { // text-align TODO: make it a StringProperty with enums. m = new EnumProperty.Maker(PR_TEXT_ALIGN) { + @Override public Property get(int subpropId, PropertyList propertyList, boolean bTryInherit, boolean bTryDefault) throws PropertyException { Property p = super.get(subpropId, propertyList, bTryInherit, bTryDefault); @@ -1649,6 +1651,7 @@ public final class FOPropertyMapping implements Constants { // text-align-last m = new EnumProperty.Maker(PR_TEXT_ALIGN_LAST) { + @Override public Property get(int subpropId, PropertyList propertyList, boolean bTryInherit, boolean bTryDefault) throws PropertyException { Property p = super.get(subpropId, propertyList, bTryInherit, bTryDefault); @@ -2125,7 +2128,7 @@ public final class FOPropertyMapping implements Constants { addPropertyMaker("starting-state", m); // switch-to - m = new ToBeImplementedProperty.Maker(PR_SWITCH_TO); + m = new StringProperty.Maker(PR_SWITCH_TO); m.setInherited(false); m.setDefault("xsl-any"); addPropertyMaker("switch-to", m); @@ -2614,6 +2617,12 @@ public final class FOPropertyMapping implements Constants { m.setDefault(""); addPropertyMaker("fox:alt-text", m); + // fox:auto-toggle, used only in fo:multi-switch + m = new EnumProperty.Maker(PR_X_AUTO_TOGGLE); + m.setInherited(false); + m.addEnum("select-first-fitting", getEnumProperty(EN_SELECT_FIRST_FITTING, "SELECT_FIRST_FITTING")); + m.setDefault("select-first-fitting"); + addPropertyMaker("fox:auto-toggle", m); // fox:border-*-radius-* m = new CondLengthProperty.Maker(PR_X_BORDER_BEFORE_RADIUS_START); diff --git a/src/java/org/apache/fop/fo/extensions/ExtensionElementMapping.java b/src/java/org/apache/fop/fo/extensions/ExtensionElementMapping.java index 82db43e59..eb02540bc 100644 --- a/src/java/org/apache/fop/fo/extensions/ExtensionElementMapping.java +++ b/src/java/org/apache/fop/fo/extensions/ExtensionElementMapping.java @@ -49,6 +49,7 @@ public class ExtensionElementMapping extends ElementMapping { PROPERTY_ATTRIBUTES.add("orphan-content-limit"); PROPERTY_ATTRIBUTES.add("internal-destination"); PROPERTY_ATTRIBUTES.add("disable-column-balancing"); + PROPERTY_ATTRIBUTES.add("auto-toggle"); //These are FOP's extension properties for accessibility PROPERTY_ATTRIBUTES.add("alt-text"); PROPERTY_ATTRIBUTES.add("header"); @@ -80,6 +81,7 @@ public class ExtensionElementMapping extends ElementMapping { /** * Initialize the data structures. */ + @Override protected void initialize() { if (foObjs == null) { foObjs = new HashMap<String, Maker>(); @@ -91,23 +93,27 @@ public class ExtensionElementMapping extends ElementMapping { } static class DestinationMaker extends ElementMapping.Maker { + @Override public FONode make(FONode parent) { return new Destination(parent); } } static class ExternalDocumentMaker extends ElementMapping.Maker { + @Override public FONode make(FONode parent) { return new ExternalDocument(parent); } } /** {@inheritDoc} */ + @Override public String getStandardPrefix() { return STANDARD_PREFIX; } /** {@inheritDoc} */ + @Override public boolean isAttributeProperty(QName attributeName) { if (!URI.equals(attributeName.getNamespaceURI())) { throw new IllegalArgumentException("The namespace URIs don't match"); diff --git a/src/java/org/apache/fop/fo/flow/MultiCase.java b/src/java/org/apache/fop/fo/flow/MultiCase.java index ac965dffb..ef6e444e1 100644 --- a/src/java/org/apache/fop/fo/flow/MultiCase.java +++ b/src/java/org/apache/fop/fo/flow/MultiCase.java @@ -19,10 +19,13 @@ package org.apache.fop.fo.flow; +import org.xml.sax.Locator; + import org.apache.fop.apps.FOPException; import org.apache.fop.fo.FONode; import org.apache.fop.fo.FObj; import org.apache.fop.fo.PropertyList; +import org.apache.fop.fo.ValidationException; /** * Class modelling the <a href="http://www.w3.org/TR/xsl/#fo_multi-case"> @@ -30,16 +33,15 @@ import org.apache.fop.fo.PropertyList; * TODO implement validateChildNode() */ public class MultiCase extends FObj { - // The value of properties relevant for fo:multi-case. + + // FO multi-case properties private int startingState; - // private ToBeImplementedProperty caseName; - // private ToBeImplementedProperty caseTitle; + private String caseName; + private String caseTitle; // Unused but valid items, commented out for performance: // private CommonAccessibility commonAccessibility; // End of property values - private static boolean notImplementedWarningGiven = false; - /** * Base constructor * @@ -47,20 +49,38 @@ public class MultiCase extends FObj { */ public MultiCase(FONode parent) { super(parent); - - if (!notImplementedWarningGiven) { - getFOValidationEventProducer().unimplementedFeature(this, getName(), - getName(), getLocator()); - notImplementedWarningGiven = true; - } } - /** {@inheritDoc} */ + @Override public void bind(PropertyList pList) throws FOPException { super.bind(pList); startingState = pList.get(PR_STARTING_STATE).getEnum(); - // caseName = pList.get(PR_CASE_NAME); - // caseTitle = pList.get(PR_CASE_TITLE); + caseName = pList.get(PR_CASE_NAME).getString(); + caseTitle = pList.get(PR_CASE_TITLE).getString(); + } + + /** + * Content Model: (#PCDATA|%inline;|%block)* + */ + @Override + protected void validateChildNode(Locator loc, String nsURI, String localName) + throws ValidationException { + if (FO_URI.equals(nsURI)) { + if (!isBlockOrInlineItem(nsURI, localName) || "marker".equals(localName)) { + invalidChildError(loc, nsURI, localName); + } + if (!"multi-toggle".equals(localName)) { + // Validate against parent of fo:multi-switch + FONode.validateChildNode(getParent().getParent(), loc, nsURI, localName); + } + } + } + + @Override + public void endOfNode() throws FOPException { + if (firstChild == null) { + missingChildElementError("(#PCDATA|%inline;|%block)*"); + } } /** @return the "starting-state" property */ @@ -68,7 +88,7 @@ public class MultiCase extends FObj { return startingState; } - /** {@inheritDoc} */ + @Override public String getLocalName() { return "multi-case"; } @@ -77,7 +97,17 @@ public class MultiCase extends FObj { * {@inheritDoc} * @return {@link org.apache.fop.fo.Constants#FO_MULTI_CASE} */ + @Override public int getNameId() { return FO_MULTI_CASE; } + + public String getCaseName() { + return caseName; + } + + public String getCaseTitle() { + return caseTitle; + } + } diff --git a/src/java/org/apache/fop/fo/flow/MultiSwitch.java b/src/java/org/apache/fop/fo/flow/MultiSwitch.java index d8ebee4cb..1248d1ca4 100644 --- a/src/java/org/apache/fop/fo/flow/MultiSwitch.java +++ b/src/java/org/apache/fop/fo/flow/MultiSwitch.java @@ -19,7 +19,6 @@ package org.apache.fop.fo.flow; -// XML import org.xml.sax.Locator; import org.apache.fop.apps.FOPException; @@ -39,7 +38,7 @@ public class MultiSwitch extends FObj { // private CommonAccessibility commonAccessibility; // End of property values - private static boolean notImplementedWarningGiven = false; + private int autoToggle; /** * Base constructor @@ -48,32 +47,30 @@ public class MultiSwitch extends FObj { */ public MultiSwitch(FONode parent) { super(parent); - - if (!notImplementedWarningGiven) { - getFOValidationEventProducer().unimplementedFeature(this, getName(), - getName(), getLocator()); - notImplementedWarningGiven = true; - } } /** {@inheritDoc} */ + @Override public void bind(PropertyList pList) throws FOPException { super.bind(pList); + autoToggle = pList.get(PR_X_AUTO_TOGGLE).getEnum(); // autoRestore = pList.get(PR_AUTO_RESTORE); } - /** {@inheritDoc} */ + @Override public void endOfNode() throws FOPException { if (firstChild == null) { missingChildElementError("(multi-case+)"); } + super.endOfNode(); } /** * {@inheritDoc} * <br>XSL Content Model: (multi-case+) */ + @Override protected void validateChildNode(Locator loc, String nsURI, String localName) throws ValidationException { if (FO_URI.equals(nsURI)) { @@ -84,6 +81,7 @@ public class MultiSwitch extends FObj { } /** {@inheritDoc} */ + @Override public String getLocalName() { return "multi-switch"; } @@ -92,7 +90,13 @@ public class MultiSwitch extends FObj { * {@inheritDoc} * @return {@link org.apache.fop.fo.Constants#FO_MULTI_SWITCH} */ + @Override public int getNameId() { return FO_MULTI_SWITCH; } + + public int getAutoToggle() { + return autoToggle; + } + } diff --git a/src/java/org/apache/fop/fo/flow/MultiToggle.java b/src/java/org/apache/fop/fo/flow/MultiToggle.java index 10766680e..05a634ada 100644 --- a/src/java/org/apache/fop/fo/flow/MultiToggle.java +++ b/src/java/org/apache/fop/fo/flow/MultiToggle.java @@ -19,7 +19,6 @@ package org.apache.fop.fo.flow; -// FOP import org.xml.sax.Locator; import org.apache.fop.apps.FOPException; @@ -27,6 +26,7 @@ import org.apache.fop.fo.FONode; import org.apache.fop.fo.FObj; import org.apache.fop.fo.PropertyList; import org.apache.fop.fo.ValidationException; +import org.apache.fop.fo.properties.StringProperty; /** @@ -36,7 +36,7 @@ import org.apache.fop.fo.ValidationException; public class MultiToggle extends FObj { // The value of properties relevant for fo:multi-toggle (commented out for performance). // private CommonAccessibility commonAccessibility; - // public ToBeImplementedProperty prSwitchTo; + public StringProperty prSwitchTo; // End of property values private static boolean notImplementedWarningGiven = false; @@ -57,15 +57,17 @@ public class MultiToggle extends FObj { } /** {@inheritDoc} */ + @Override public void bind(PropertyList pList) throws FOPException { - // prSwitchTo = pList.get(PR_SWITCH_TO); - + super.bind(pList); + prSwitchTo = (StringProperty) pList.get(PR_SWITCH_TO); } /** * {@inheritDoc} * <br>XSL Content Model: (#PCDATA|%inline;|%block;)* */ + @Override protected void validateChildNode(Locator loc, String nsURI, String localName) throws ValidationException { if (FO_URI.equals(nsURI)) { @@ -76,6 +78,7 @@ public class MultiToggle extends FObj { } /** {@inheritDoc} */ + @Override public String getLocalName() { return "multi-toggle"; } @@ -84,7 +87,9 @@ public class MultiToggle extends FObj { * {@inheritDoc} * @return {@link org.apache.fop.fo.Constants#FO_MULTI_TOGGLE} */ + @Override public int getNameId() { return FO_MULTI_TOGGLE; } + } diff --git a/src/java/org/apache/fop/layoutmgr/AbstractBreaker.java b/src/java/org/apache/fop/layoutmgr/AbstractBreaker.java index 51e80e8d4..408a02b04 100644 --- a/src/java/org/apache/fop/layoutmgr/AbstractBreaker.java +++ b/src/java/org/apache/fop/layoutmgr/AbstractBreaker.java @@ -107,9 +107,9 @@ public abstract class AbstractBreaker { * of previous BlockSequence?), EN_COLUMN, EN_ODD_PAGE, * EN_EVEN_PAGE. */ - private int startOn; + private final int startOn; - private int displayAlign; + private final int displayAlign; /** * Creates a new BlockSequence. @@ -142,6 +142,7 @@ public abstract class AbstractBreaker { * Finalizes a Knuth sequence. * @return a finalized sequence. */ + @Override public KnuthSequence endSequence() { return endSequence(null); } @@ -611,7 +612,6 @@ public abstract class AbstractBreaker { // Handle SpaceHandling(Break)Positions, see SpaceResolver! SpaceResolver.performConditionalsNotification(effectiveList, startElementIndex, notificationEndElementIndex, lastBreak); - // Add areas now! addAreas(new KnuthPossPosIter(effectiveList, startElementIndex, endElementIndex + 1), childLC); diff --git a/src/java/org/apache/fop/layoutmgr/BreakingAlgorithm.java b/src/java/org/apache/fop/layoutmgr/BreakingAlgorithm.java index c7048295f..4cf15f3a0 100644 --- a/src/java/org/apache/fop/layoutmgr/BreakingAlgorithm.java +++ b/src/java/org/apache/fop/layoutmgr/BreakingAlgorithm.java @@ -319,12 +319,12 @@ public abstract class BreakingAlgorithm { protected class BestRecords { private static final double INFINITE_DEMERITS = Double.POSITIVE_INFINITY; - private double[] bestDemerits = new double[4]; - private KnuthNode[] bestNode = new KnuthNode[4]; - private double[] bestAdjust = new double[4]; - private int[] bestDifference = new int[4]; - private int[] bestAvailableShrink = new int[4]; - private int[] bestAvailableStretch = new int[4]; + private final double[] bestDemerits = new double[4]; + private final KnuthNode[] bestNode = new KnuthNode[4]; + private final double[] bestAdjust = new double[4]; + private final int[] bestDifference = new int[4]; + private final int[] bestAvailableShrink = new int[4]; + private final int[] bestAvailableStretch = new int[4]; /** Points to the fitness class which currently leads to the best demerits. */ private int bestIndex = -1; @@ -988,7 +988,7 @@ public abstract class BreakingAlgorithm { * @param node the node * @param line the line number * @param elementIdx the position index of the element - * @param difference the difference between content-length and avaialable width + * @param difference the difference between content-length and available width * @param r the adjustment ratio * @param demerits demerits produced by the node * @param fitnessClass the fitness class diff --git a/src/java/org/apache/fop/layoutmgr/ElementListUtils.java b/src/java/org/apache/fop/layoutmgr/ElementListUtils.java index 2bd6f429a..e6be4ca63 100644 --- a/src/java/org/apache/fop/layoutmgr/ElementListUtils.java +++ b/src/java/org/apache/fop/layoutmgr/ElementListUtils.java @@ -201,7 +201,7 @@ public final class ElementListUtils { if (last.isPenalty() && ((KnuthPenalty)last).getPenalty() < KnuthElement.INFINITE) { return true; } else if (last instanceof BreakElement - && ((BreakElement)last).getPenaltyValue() < KnuthElement.INFINITE) { + && ((BreakElement)last).getPenaltyValue() < KnuthElement.INFINITE) { return true; } return false; diff --git a/src/java/org/apache/fop/layoutmgr/FlowLayoutManager.java b/src/java/org/apache/fop/layoutmgr/FlowLayoutManager.java index 4c7afa8d6..75c61b94f 100644 --- a/src/java/org/apache/fop/layoutmgr/FlowLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/FlowLayoutManager.java @@ -48,7 +48,7 @@ public class FlowLayoutManager extends BlockStackingLayoutManager private static Log log = LogFactory.getLog(FlowLayoutManager.class); /** Array of areas currently being filled stored by area class */ - private BlockParent[] currentAreas = new BlockParent[Area.CLASS_MAX]; + private final BlockParent[] currentAreas = new BlockParent[Area.CLASS_MAX]; /** * This is the top level layout manager. diff --git a/src/java/org/apache/fop/layoutmgr/LayoutContext.java b/src/java/org/apache/fop/layoutmgr/LayoutContext.java index 21983c20f..763407132 100644 --- a/src/java/org/apache/fop/layoutmgr/LayoutContext.java +++ b/src/java/org/apache/fop/layoutmgr/LayoutContext.java @@ -644,26 +644,27 @@ public final class LayoutContext { } /** {@inheritDoc} */ + @Override public String toString() { return "Layout Context:" - + "\nStack Limit BPD: \t" - + (getStackLimitBP() == null ? "null" : getStackLimitBP().toString()) - + "\nTrailing Space: \t" - + (getTrailingSpace() == null ? "null" : getTrailingSpace().toString()) - + "\nLeading Space: \t" - + (getLeadingSpace() == null ? "null" : getLeadingSpace().toString()) - + "\nReference IPD: \t" + getRefIPD() - + "\nSpace Adjust: \t" + getSpaceAdjust() - + "\nIPD Adjust: \t" + getIPDAdjust() - + "\nResolve Leading Space: \t" + resolveLeadingSpace() - + "\nSuppress Break Before: \t" + suppressBreakBefore() - + "\nIs First Area: \t" + isFirstArea() - + "\nStarts New Area: \t" + startsNewArea() - + "\nIs Last Area: \t" + isLastArea() - + "\nKeeps: \t[keep-with-next=" + getKeepWithNextPending() + + "\nStack Limit BPD: \t" + + (getStackLimitBP() == null ? "null" : getStackLimitBP().toString()) + + "\nTrailing Space: \t" + + (getTrailingSpace() == null ? "null" : getTrailingSpace().toString()) + + "\nLeading Space: \t" + + (getLeadingSpace() == null ? "null" : getLeadingSpace().toString()) + + "\nReference IPD: \t" + getRefIPD() + + "\nSpace Adjust: \t" + getSpaceAdjust() + + "\nIPD Adjust: \t" + getIPDAdjust() + + "\nResolve Leading Space: \t" + resolveLeadingSpace() + + "\nSuppress Break Before: \t" + suppressBreakBefore() + + "\nIs First Area: \t" + isFirstArea() + + "\nStarts New Area: \t" + startsNewArea() + + "\nIs Last Area: \t" + isLastArea() + + "\nKeeps: \t[keep-with-next=" + getKeepWithNextPending() + "][keep-with-previous=" + getKeepWithPreviousPending() + "] pending" - + "\nBreaks: \tforced [" + (breakBefore != Constants.EN_AUTO ? "break-before" : "") + "][" - + (breakAfter != Constants.EN_AUTO ? "break-after" : "") + "]"; + + "\nBreaks: \tforced [" + (breakBefore != Constants.EN_AUTO ? "break-before" : "") + "][" + + (breakAfter != Constants.EN_AUTO ? "break-after" : "") + "]"; } /** diff --git a/src/java/org/apache/fop/layoutmgr/LayoutManagerMapping.java b/src/java/org/apache/fop/layoutmgr/LayoutManagerMapping.java index 0e333d219..88c52b383 100644 --- a/src/java/org/apache/fop/layoutmgr/LayoutManagerMapping.java +++ b/src/java/org/apache/fop/layoutmgr/LayoutManagerMapping.java @@ -49,6 +49,8 @@ import org.apache.fop.fo.flow.InstreamForeignObject; import org.apache.fop.fo.flow.Leader; import org.apache.fop.fo.flow.ListBlock; import org.apache.fop.fo.flow.ListItem; +import org.apache.fop.fo.flow.MultiCase; +import org.apache.fop.fo.flow.MultiSwitch; import org.apache.fop.fo.flow.PageNumber; import org.apache.fop.fo.flow.PageNumberCitation; import org.apache.fop.fo.flow.PageNumberCitationLast; @@ -96,7 +98,7 @@ public class LayoutManagerMapping implements LayoutManagerMaker { private static final Log LOG = LogFactory.getLog(LayoutManagerMapping.class); /** The map of LayoutManagerMakers */ - private Map makers = new HashMap(); + private final Map makers = new HashMap(); /** default constructor */ public LayoutManagerMapping() { @@ -142,6 +144,8 @@ public class LayoutManagerMapping implements LayoutManagerMaker { registerMaker(TableHeader.class, new Maker()); registerMaker(Wrapper.class, new WrapperLayoutManagerMaker()); registerMaker(Title.class, new InlineLayoutManagerMaker()); + registerMaker(MultiCase.class, new MultiCaseLayoutManagerMaker()); + registerMaker(MultiSwitch.class, new MultiSwitchLayoutManagerMaker()); } /** @@ -443,4 +447,20 @@ public class LayoutManagerMapping implements LayoutManagerMaker { } } + public class MultiSwitchLayoutManagerMaker extends Maker { + + @Override + public void make(FONode node, List lms) { + lms.add(new MultiSwitchLayoutManager((MultiSwitch) node)); + } + } + + public class MultiCaseLayoutManagerMaker extends Maker { + + @Override + public void make(FONode node, List lms) { + lms.add(new MultiCaseLayoutManager((MultiCase) node)); + } + } + } diff --git a/src/java/org/apache/fop/layoutmgr/MultiCaseLayoutManager.java b/src/java/org/apache/fop/layoutmgr/MultiCaseLayoutManager.java new file mode 100644 index 000000000..9469a2fb8 --- /dev/null +++ b/src/java/org/apache/fop/layoutmgr/MultiCaseLayoutManager.java @@ -0,0 +1,61 @@ +/* + * 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 org.apache.fop.area.Area; +import org.apache.fop.fo.FObj; + +public class MultiCaseLayoutManager extends BlockStackingLayoutManager { + + public MultiCaseLayoutManager(FObj node) { + super(node); + } + + @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 Area getParentArea(Area childArea) { + return parentLayoutManager.getParentArea(childArea); + } + + @Override + public void addChildArea(Area childArea) { + parentLayoutManager.addChildArea(childArea); + } + + /** {@inheritDoc} */ + @Override + public void addAreas(PositionIterator posIter, LayoutContext context) { + AreaAdditionUtil.addAreas(this, posIter, context); + flush(); + } + +} diff --git a/src/java/org/apache/fop/layoutmgr/MultiSwitchLayoutManager.java b/src/java/org/apache/fop/layoutmgr/MultiSwitchLayoutManager.java new file mode 100644 index 000000000..2bef1a815 --- /dev/null +++ b/src/java/org/apache/fop/layoutmgr/MultiSwitchLayoutManager.java @@ -0,0 +1,163 @@ +/* + * 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.area.Area; +import org.apache.fop.fo.Constants; +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> getKnuthElements(LayoutContext context, int alignment); + } + + private class DefaultKnuthListGenerator implements KnuthElementsGenerator { + + public List<ListElement> getKnuthElements(LayoutContext context, int alignment) { + List<ListElement> knuthList = new LinkedList<ListElement>(); + LayoutManager childLM = getChildLM(); + while (!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 { + + @SuppressWarnings("unchecked") + public List<ListElement> getKnuthElements(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) { + LayoutContext childLC = makeChildLayoutContext(context); + List<ListElement> childElements = new LinkedList<ListElement>(); + while (!childLM.isFinished()) { + childElements.addAll(childLM.getNextKnuthElements(childLC, alignment)); + } + List<ListElement> wrappedElements = new LinkedList<ListElement>(); + wrapPositionElements(childElements, wrappedElements); + // TODO Doing space resolution here is wrong. + SpaceResolver.resolveElementList(wrappedElements); + int contentLength = ElementListUtils.calcContentLength(wrappedElements); + penalty.addVariant(penalty.new Variant(wrappedElements, 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() == Constants.EN_SELECT_FIRST_FITTING) { + knuthGen = new WhitespaceManagement(); + } else { + knuthGen = new DefaultKnuthListGenerator(); + } + } + + @Override + public List<ListElement> getNextKnuthElements(LayoutContext context, int alignment) { + referenceIPD = context.getRefIPD(); + List<ListElement> knuthList = knuthGen.getKnuthElements(context, alignment); + setFinished(true); + return knuthList; + } + + @Override + public Area getParentArea(Area childArea) { + return parentLayoutManager.getParentArea(childArea); + } + + @Override + public void addChildArea(Area childArea) { + parentLayoutManager.addChildArea(childArea); + } + + @Override + public void addAreas(PositionIterator posIter, LayoutContext context) { + 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(); + } + +} diff --git a/src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java b/src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java index a5084bac5..db849a40f 100644 --- a/src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java +++ b/src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java @@ -30,6 +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.WhitespaceManagementPenalty.Variant; import org.apache.fop.traits.MinOptMax; import org.apache.fop.util.ListUtil; @@ -38,9 +39,9 @@ class PageBreakingAlgorithm extends BreakingAlgorithm { /** the logger for the class */ private static Log log = LogFactory.getLog(PageBreakingAlgorithm.class); - private LayoutManager topLevelLM; - private PageProvider pageProvider; - private PageBreakingLayoutListener layoutListener; + private final LayoutManager topLevelLM; + private final PageProvider pageProvider; + private final PageBreakingLayoutListener layoutListener; /** List of PageBreakPosition elements. */ private LinkedList<PageBreakPosition> pageBreaks = null; @@ -73,9 +74,9 @@ class PageBreakingAlgorithm extends BreakingAlgorithm { private int footnoteElementIndex = -1; // demerits for a page break that splits a footnote - private int splitFootnoteDemerits = 5000; + private final int splitFootnoteDemerits = 5000; // demerits for a page break that defers a whole footnote to the following page - private int deferredFootnoteDemerits = 10000; + private final int deferredFootnoteDemerits = 10000; private MinOptMax footnoteSeparatorLength = null; // the method noBreakBetween(int, int) uses these variables @@ -152,6 +153,14 @@ class PageBreakingAlgorithm extends BreakingAlgorithm { /** Index of the last inserted element of the last inserted footnote. */ public int footnoteElementIndex; + /** + * 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, int totalWidth, int totalStretch, int totalShrink, @@ -169,6 +178,11 @@ class PageBreakingAlgorithm extends BreakingAlgorithm { this.footnoteElementIndex = footnoteElementIndex; } + public void addVariant(Variant variant) { + pendingVariants.add(variant); + totalVariantsWidth += variant.width; + } + } /** @@ -177,11 +191,12 @@ class PageBreakingAlgorithm extends BreakingAlgorithm { */ protected class BestPageRecords extends BestRecords { - private int[] bestInsertedFootnotesLength = new int[4]; - private int[] bestTotalFootnotesLength = new int[4]; - private int[] bestFootnoteListIndex = new int[4]; - private int[] bestFootnoteElementIndex = new int[4]; + private final int[] bestInsertedFootnotesLength = new int[4]; + private final int[] bestTotalFootnotesLength = new int[4]; + private final int[] bestFootnoteListIndex = new int[4]; + private final int[] bestFootnoteElementIndex = new int[4]; + @Override public void addRecord(double demerits, KnuthNode node, double adjust, int availableShrink, int availableStretch, int difference, int fitness) { @@ -209,6 +224,8 @@ class PageBreakingAlgorithm extends BreakingAlgorithm { public int getFootnoteElementIndex(int fitness) { return bestFootnoteElementIndex[fitness]; } + + } /** {@inheritDoc} */ @@ -406,6 +423,7 @@ class PageBreakingAlgorithm extends BreakingAlgorithm { /** {@inheritDoc} */ @Override protected int restartFrom(KnuthNode restartingNode, int currentIndex) { + int returnValue = super.restartFrom(restartingNode, currentIndex); newFootnotes = false; if (footnotesPending) { @@ -509,7 +527,11 @@ class PageBreakingAlgorithm extends BreakingAlgorithm { int actualWidth = totalWidth - pageNode.totalWidth; int footnoteSplit; boolean canDeferOldFN; - if (element.isPenalty()) { + actualWidth += pageNode.totalVariantsWidth; + if (element instanceof WhitespaceManagementPenalty) { + actualWidth += handleWhitespaceManagementPenalty(pageNode, + (WhitespaceManagementPenalty) element, elementIndex); + } else if (element.isPenalty()) { actualWidth += element.getWidth(); } if (footnotesPending) { @@ -571,6 +593,24 @@ class PageBreakingAlgorithm extends BreakingAlgorithm { } /** + * 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.getPenalty(), elementIndex); + double r = computeAdjustmentRatio(activeNode, difference); + if (r >= -1.0) { + activeNode.addVariant(var); + return var.width; + } + } + return 0; + } + + /** * Checks whether footnotes from preceding pages may be deferred to the page after * the given element. * @param node active node for the preceding page break @@ -982,6 +1022,17 @@ class PageBreakingAlgorithm extends BreakingAlgorithm { int total) { //int difference = (bestActiveNode.line < total) // ? bestActiveNode.difference : bestActiveNode.difference + fillerMinWidth; + // Check if the given node has an attached variant of a dynamic content + KnuthPageNode pageNode = (KnuthPageNode) bestActiveNode; + KnuthPageNode previousPageNode = ((KnuthPageNode) pageNode.previous); + for (Variant var : previousPageNode.pendingVariants) { + WhitespaceManagementPenalty penalty = var.getWhitespaceManagementPenalty(); + // A WMPenalty should not be activated more than once. The reason is simply + // because a dynamic content cannot occupy multiple pages at the same time. + if (!penalty.hasActiveVariant()) { + penalty.setActiveVariant(var); + } + } int difference = bestActiveNode.difference; if (difference + bestActiveNode.availableShrink < 0) { if (!autoHeight) { diff --git a/src/java/org/apache/fop/layoutmgr/WhitespaceManagementPenalty.java b/src/java/org/apache/fop/layoutmgr/WhitespaceManagementPenalty.java new file mode 100644 index 000000000..e34d24b9a --- /dev/null +++ b/src/java/org/apache/fop/layoutmgr/WhitespaceManagementPenalty.java @@ -0,0 +1,90 @@ +/* + * 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.List; + +import org.apache.fop.layoutmgr.MultiSwitchLayoutManager.WhitespaceManagementPosition; + +/** + * 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 WhitespaceManagementPenalty extends KnuthPenalty { + + public class Variant { + + public final List<ListElement> knuthList; + public final int width; + private final KnuthPenalty penalty; + + public Variant(List<ListElement> knuthList, int width) { + this.knuthList = knuthList; + this.width = width; + this.penalty = new KnuthPenalty(width, 0, false, null, false); + } + + public KnuthElement getPenalty() { + return penalty; + } + + public WhitespaceManagementPenalty getWhitespaceManagementPenalty() { + return WhitespaceManagementPenalty.this; + } + + } + + private final WhitespaceManagementPosition whitespaceManagementPosition; + private final List<Variant> variantList; + + public WhitespaceManagementPenalty(WhitespaceManagementPosition pos) { + super(0, 0, false, pos, false); + this.whitespaceManagementPosition = pos; + variantList = new ArrayList<Variant>(); + } + + public void addVariant(Variant variant) { + variantList.add(variant); + } + + public void setActiveVariant(Variant bestVariant) { + whitespaceManagementPosition.setKnuthList(bestVariant.knuthList); + } + + public boolean hasActiveVariant() { + return whitespaceManagementPosition.getKnuthList() != null; + } + + public List<Variant> getVariants() { + return variantList; + } + + @Override + public String toString() { + String str = super.toString(); + StringBuffer buffer = new StringBuffer(64); + buffer.append(" number of variants = " + variantList.size()); + return str + buffer.toString(); + } + +} diff --git a/test/java/org/apache/fop/KnuthAlgorithmTestCase.java b/test/java/org/apache/fop/KnuthAlgorithmTestCase.java index 8f44864e0..aa92191de 100644 --- a/test/java/org/apache/fop/KnuthAlgorithmTestCase.java +++ b/test/java/org/apache/fop/KnuthAlgorithmTestCase.java @@ -89,7 +89,7 @@ public class KnuthAlgorithmTestCase { private class MyBreakingAlgorithm extends BreakingAlgorithm { - private List parts = new java.util.ArrayList(); + private final List<Part> parts = new java.util.ArrayList<Part>(); public MyBreakingAlgorithm(int align, int alignLast, boolean first, boolean partOverflowRecovery, int maxFlagCount) { @@ -97,13 +97,15 @@ public class KnuthAlgorithmTestCase { } public Part[] getParts() { - return (Part[])parts.toArray(new Part[parts.size()]); + return parts.toArray(new Part[parts.size()]); } + @Override public void updateData1(int total, double demerits) { //nop } + @Override public void updateData2(KnuthNode bestActiveNode, KnuthSequence sequence, int total) { int difference = bestActiveNode.difference; // it is always allowed to adjust space, so the ratio must be set regardless of @@ -137,6 +139,7 @@ public class KnuthAlgorithmTestCase { parts.add(0, part); } + @Override protected int filterActiveNodes() { //nop return 0; diff --git a/test/layoutengine/standard-testcases/multi-switch_basic.xml b/test/layoutengine/standard-testcases/multi-switch_basic.xml new file mode 100644 index 000000000..8f00d4179 --- /dev/null +++ b/test/layoutengine/standard-testcases/multi-switch_basic.xml @@ -0,0 +1,61 @@ +<?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 standard fo:multi-switch. + </p> + </info> + <fo> + <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:fox="http://xmlgraphics.apache.org/fop/extensions"> + <fo:layout-master-set> + <fo:simple-page-master master-name="page" page-width="300pt" page-height="200pt" margin="10pt"> + <fo:region-body/> + </fo:simple-page-master> + </fo:layout-master-set> + <fo:page-sequence master-reference="page"> + <fo:flow flow-name="xsl-region-body"> + <fo:block>Block 1</fo:block> + <fo:multi-switch> + <fo:multi-case> + <fo:block>MS1 multi-case</fo:block> + </fo:multi-case> + </fo:multi-switch> + <fo:block>Block 2</fo:block> + <fo:multi-switch> + <fo:multi-case> + <fo:block>MS2 multi-case 1</fo:block> + </fo:multi-case> + <fo:multi-case> + <fo:block>MS2 multi-case 2</fo:block> + </fo:multi-case> + </fo:multi-switch> + </fo:flow> + </fo:page-sequence> + </fo:root> + </fo> + <checks> + <eval expected="1" xpath="count(//pageSequence[1]/pageViewport)"/> + <eval expected="4" xpath="count(//pageSequence[1]/pageViewport[1]//flow/block)"/> + <eval expected="Block 1" xpath="//pageSequence[1]/pageViewport[1]//flow/block[1]"/> + <eval expected="MS1 multi-case" xpath="//pageSequence[1]/pageViewport[1]//flow/block[2]"/> + <eval expected="Block 2" xpath="//pageSequence[1]/pageViewport[1]//flow/block[3]"/> + <eval expected="MS2 multi-case 1" xpath="//pageSequence[1]/pageViewport[1]//flow/block[4]"/> + </checks> +</testcase> diff --git a/test/layoutengine/standard-testcases/multi-switch_select-first-fitting.xml b/test/layoutengine/standard-testcases/multi-switch_select-first-fitting.xml new file mode 100644 index 000000000..2c8aa44ca --- /dev/null +++ b/test/layoutengine/standard-testcases/multi-switch_select-first-fitting.xml @@ -0,0 +1,51 @@ +<?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> + Basic test for fo:multi-switch using the whitespace management extension. + </p> + </info> + <fo> + <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:fox="http://xmlgraphics.apache.org/fop/extensions"> + <fo:layout-master-set> + <fo:simple-page-master master-name="page" page-height="70pt" page-width="120pt" + margin="10pt"> + <fo:region-body/> + </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="select-first-fitting"> + <fo:multi-case> + <fo:block>First variant</fo:block> + </fo:multi-case> + <fo:multi-case> + <fo:block>Second variant</fo:block> + </fo:multi-case> + </fo:multi-switch> + </fo:flow> + </fo:page-sequence> + </fo:root> + </fo> + <checks> + <eval expected="1" xpath="count(//flow/block)"/> + <eval expected="First variant" xpath="//flow/block"/> + <eval expected="14400" xpath="//flow/block/@bpd"/> + </checks> +</testcase> diff --git a/test/layoutengine/standard-testcases/multi-switch_select-first-fitting_forced-page-break.xml b/test/layoutengine/standard-testcases/multi-switch_select-first-fitting_forced-page-break.xml new file mode 100644 index 000000000..dd9ed615c --- /dev/null +++ b/test/layoutengine/standard-testcases/multi-switch_select-first-fitting_forced-page-break.xml @@ -0,0 +1,67 @@ +<?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 forced page breaks. + </p> + </info> + <fo> + <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:fox="http://xmlgraphics.apache.org/fop/extensions"> + <fo:layout-master-set> + <fo:simple-page-master master-name="page" page-width="300pt" page-height="200pt" margin="10pt"> + <fo:region-body/> + </fo:simple-page-master> + </fo:layout-master-set> + <fo:page-sequence master-reference="page"> + <fo:flow flow-name="xsl-region-body"> + <fo:block break-after="page"> + Block 1 page 1 + <fo:multi-switch fox:auto-toggle="select-first-fitting"> + <fo:multi-case> + <fo:block>MS1 Variant 1</fo:block> + </fo:multi-case> + </fo:multi-switch> + </fo:block> + <fo:multi-switch fox:auto-toggle="select-first-fitting"> + <fo:multi-case> + <fo:block>MS2 Variant 1</fo:block> + </fo:multi-case> + </fo:multi-switch> + <fo:block break-before="page"> + Block 2 page 3 + <fo:multi-switch fox:auto-toggle="select-first-fitting"> + <fo:multi-case> + <fo:block>MS3 Variant 1</fo:block> + </fo:multi-case> + </fo:multi-switch> + </fo:block> + </fo:flow> + </fo:page-sequence> + </fo:root> + </fo> + <checks> + <eval expected="3" xpath="count(//pageSequence[1]/pageViewport)"/> + <eval expected="Block 1 page 1" xpath="//pageSequence[1]/pageViewport[1]//flow/block[1]/lineArea[1]"/> + <eval expected="MS1 Variant 1" xpath="//pageSequence[1]/pageViewport[1]//flow/block[1]/block[1]"/> + <eval expected="MS2 Variant 1" xpath="//pageSequence[1]/pageViewport[2]//flow/block[1]"/> + <eval expected="Block 2 page 3" xpath="//pageSequence[1]/pageViewport[3]//flow/block[1]/lineArea[1]"/> + <eval expected="MS3 Variant 1" xpath="//pageSequence[1]/pageViewport[3]//flow/block[1]/block[1]"/> + </checks> +</testcase> diff --git a/test/layoutengine/standard-testcases/multi-switch_select-first-fitting_middle-page.xml b/test/layoutengine/standard-testcases/multi-switch_select-first-fitting_middle-page.xml new file mode 100644 index 000000000..dabc10e52 --- /dev/null +++ b/test/layoutengine/standard-testcases/multi-switch_select-first-fitting_middle-page.xml @@ -0,0 +1,63 @@ +<?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> + Dynamic content in the middle of a page: the first variant is selected. + </p> + </info> + <fo> + <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:fox="http://xmlgraphics.apache.org/fop/extensions"> + <fo:layout-master-set> + <fo:simple-page-master master-name="page" page-height="70pt" page-width="120pt" + margin="10pt"> + <fo:region-body/> + </fo:simple-page-master> + </fo:layout-master-set> + <fo:page-sequence master-reference="page"> + <fo:flow flow-name="xsl-region-body" font-size="8pt" line-height="10pt"> + <fo:block>Before the multi-switch</fo:block> + <fo:multi-switch fox:auto-toggle="select-first-fitting"> + <fo:multi-case> + <fo:block>First variant</fo:block> + </fo:multi-case> + <fo:multi-case> + <fo:block>Second variant</fo:block> + <fo:block>Second variant</fo:block> + </fo:multi-case> + </fo:multi-switch> + <fo:block>After the multi-switch</fo:block> + <fo:block>Filler 1</fo:block> + <fo:block>Filler 2</fo:block> + <fo:block>This should be on page 2.</fo:block> + </fo:flow> + </fo:page-sequence> + </fo:root> + </fo> + <checks> + <eval expected="2" xpath="count(//pageViewport)"/> + <eval expected="5" xpath="count(//pageViewport[1]//flow/block)"/> + <eval expected="Before the multi-switch" xpath="//pageViewport[1]//flow/block[1]"/> + <eval expected="First variant" xpath="//pageViewport[1]//flow/block[2]"/> + <eval expected="After the multi-switch" xpath="//pageViewport[1]//flow/block[3]"/> + <eval expected="Filler 1" xpath="//pageViewport[1]//flow/block[4]"/> + <eval expected="Filler 2" xpath="//pageViewport[1]//flow/block[5]"/> + <eval expected="1" xpath="count(//pageViewport[2]//flow/block)"/> + <eval expected="This should be on page 2." xpath="//pageViewport[2]//flow/block[1]"/> + </checks> +</testcase> diff --git a/test/layoutengine/standard-testcases/multi-switch_select-first-fitting_multiple-variants.xml b/test/layoutengine/standard-testcases/multi-switch_select-first-fitting_multiple-variants.xml new file mode 100644 index 000000000..8ab004151 --- /dev/null +++ b/test/layoutengine/standard-testcases/multi-switch_select-first-fitting_multiple-variants.xml @@ -0,0 +1,130 @@ +<?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> + Check that the right variant is being selected (if any), depending on the space left on the + page. + </p> + </info> + <fo> + <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" + xmlns:fox="http://xmlgraphics.apache.org/fop/extensions"> + <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" font-size="8pt" line-height="10pt"> + <fo:flow flow-name="xsl-region-body"> + <fo:block>Page 1 line 1</fo:block> + <fo:block + space-before.minimum="15pt" + space-before.optimum="25pt" + space-before.maximum="30pt">Page 1 line 2</fo:block> + <fo:block>Page 1 line 3</fo:block> + <fo:block font-size="16pt" line-height="20pt">Filler</fo:block> + <fo:block>Before the multi-switch</fo:block> + <fo:multi-switch fox:auto-toggle="select-first-fitting"> + <fo:multi-case> + <fo:block>Variant 1 line 1</fo:block> + <fo:block>Variant 1 line 2</fo:block> + </fo:multi-case> + <fo:multi-case> + <fo:block>Variant 2 line 1</fo:block> + </fo:multi-case> + </fo:multi-switch> + <fo:block>This text should be on page 3.</fo:block> + </fo:flow> + </fo:page-sequence> + + <fo:page-sequence master-reference="page" font-size="8pt" line-height="10pt"> + <fo:flow flow-name="xsl-region-body"> + <fo:block>Page 1 line 1</fo:block> + <fo:block + space-before.minimum="20pt" + space-before.optimum="25pt" + space-before.maximum="35pt">Page 1 line 2</fo:block> + <fo:block>Page 2 line 1</fo:block> + <fo:block font-size="16pt" line-height="20pt">Filler</fo:block> + <fo:block>Before the multi-switch</fo:block> + <fo:multi-switch fox:auto-toggle="select-first-fitting"> + <fo:multi-case> + <fo:block>Variant 1 line 1</fo:block> + <fo:block>Variant 1 line 2</fo:block> + </fo:multi-case> + <fo:multi-case> + <fo:block>Variant 2 line 1</fo:block> + </fo:multi-case> + </fo:multi-switch> + <fo:block>This text should be on page 3.</fo:block> + </fo:flow> + </fo:page-sequence> + + <fo:page-sequence master-reference="page" font-size="8pt" line-height="10pt"> + <fo:flow flow-name="xsl-region-body"> + <fo:block>Page 1 line 1</fo:block> + <fo:block + space-before.minimum="20pt" + space-before.optimum="25pt" + space-before.maximum="35pt">Page 1 line 2</fo:block> + <fo:block>Page 2 line 1</fo:block> + <fo:block>Page 2 line 2</fo:block> + <fo:block font-size="16pt" line-height="20pt">Filler</fo:block> + <fo:block>Before the multi-switch</fo:block> + <fo:multi-switch fox:auto-toggle="select-first-fitting"> + <fo:multi-case> + <fo:block>Variant 1 line 1</fo:block> + <fo:block>Variant 1 line 2</fo:block> + </fo:multi-case> + <fo:multi-case> + <fo:block>Variant 2 line 1</fo:block> + </fo:multi-case> + </fo:multi-switch> + <fo:block>This text should be on page 3.</fo:block> + </fo:flow> + </fo:page-sequence> + </fo:root> + </fo> + <checks> + <!-- 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]"/> + <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]"/> + <eval expected="This text should be on page 3." xpath="//pageSequence[2]/pageViewport[3]//flow/block[1]"/> + + <!-- 3. No variant --> + <eval expected="3" xpath="count(//pageSequence[3]/pageViewport)"/> + <eval expected="4" xpath="count(//pageSequence[3]/pageViewport[2]//flow/block)"/> + <eval expected="Page 2 line 1" xpath="//pageSequence[3]/pageViewport[2]//flow/block[1]"/> + <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="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> diff --git a/test/layoutengine/standard-testcases/multi-switch_select-first-fitting_padding.xml b/test/layoutengine/standard-testcases/multi-switch_select-first-fitting_padding.xml new file mode 100644 index 000000000..1ec9e2975 --- /dev/null +++ b/test/layoutengine/standard-testcases/multi-switch_select-first-fitting_padding.xml @@ -0,0 +1,70 @@ +<?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 padding properties. + </p> + </info> + <fo> + <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:fox="http://xmlgraphics.apache.org/fop/extensions"> + <fo:layout-master-set> + <fo:simple-page-master master-name="page" page-width="300pt" page-height="200pt" margin="10pt"> + <fo:region-body/> + </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="select-first-fitting"> + <fo:multi-case> + <fo:block padding="10pt">MS1 Variant 1</fo:block> + </fo:multi-case> + </fo:multi-switch> + <fo:multi-switch fox:auto-toggle="select-first-fitting"> + <fo:multi-case> + <fo:block padding-before="10pt" padding-after="10pt">MS2 Variant 1</fo:block> + </fo:multi-case> + </fo:multi-switch> + <fo:multi-switch fox:auto-toggle="select-first-fitting"> + <fo:multi-case> + <fo:block> + <fo:inline padding-start="10pt" padding-end="10pt">MS3 Variant 1</fo:inline> + </fo:block> + </fo:multi-case> + </fo:multi-switch> + </fo:flow> + </fo:page-sequence> + </fo:root> + </fo> + <checks> + <eval expected="MS1 Variant 1" xpath="//block[1]"/> + <eval expected="10000" xpath="//block[1]/@padding-start"/> + <eval expected="10000" xpath="//block[1]/@padding-end"/> + <eval expected="10000" xpath="//block[1]/@padding-before"/> + <eval expected="10000" xpath="//block[1]/@padding-after"/> + + <eval expected="MS2 Variant 1" xpath="//block[2]"/> + <eval expected="10000" xpath="//block[2]/@padding-before"/> + <eval expected="10000" xpath="//block[2]/@padding-after"/> + + <eval expected="MS3 Variant 1" xpath="//block[3]/lineArea[1]"/> + <eval expected="10000" xpath="//block[3]/lineArea[1]/inlineparent/@padding-start"/> + <eval expected="10000" xpath="//block[3]/lineArea[1]/inlineparent/@padding-end"/> + </checks> +</testcase> diff --git a/test/layoutengine/standard-testcases/multi-switch_select-first-fitting_several-multi-switch.xml b/test/layoutengine/standard-testcases/multi-switch_select-first-fitting_several-multi-switch.xml new file mode 100644 index 000000000..969a4786b --- /dev/null +++ b/test/layoutengine/standard-testcases/multi-switch_select-first-fitting_several-multi-switch.xml @@ -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="select-first-fitting"> + <fo:multi-case> + <fo:block>MS 1 Variant 1</fo:block> + </fo:multi-case> + </fo:multi-switch> + <fo:multi-switch fox:auto-toggle="select-first-fitting"> + <fo:multi-case> + <fo:block>MS 2 Variant 1</fo:block> + </fo:multi-case> + </fo:multi-switch> + <fo:multi-switch fox:auto-toggle="select-first-fitting"> + <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="select-first-fitting"> + <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="select-first-fitting"> + <fo:multi-case> + <fo:block>MS 2 Variant 1</fo:block> + </fo:multi-case> + </fo:multi-switch> + <fo:multi-switch fox:auto-toggle="select-first-fitting"> + <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="select-first-fitting"> + <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> |