diff options
Diffstat (limited to 'src/java')
16 files changed, 516 insertions, 71 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(); + } + +} |