aboutsummaryrefslogtreecommitdiffstats
path: root/src/java
diff options
context:
space:
mode:
authorVincent Hennebert <vhennebert@apache.org>2013-11-07 20:49:18 +0000
committerVincent Hennebert <vhennebert@apache.org>2013-11-07 20:49:18 +0000
commit7c9187955e5ae1c8181a52715791e4b61fc977bb (patch)
tree272804e274ce56b5374c6c31b7ade6fc2693ec59 /src/java
parentfb7bda27d7c52920c6234d0f73dd2e423dce735a (diff)
downloadxmlgraphics-fop-7c9187955e5ae1c8181a52715791e4b61fc977bb.tar.gz
xmlgraphics-fop-7c9187955e5ae1c8181a52715791e4b61fc977bb.zip
Implement whitespace management extension using fo:multi-switch
Patch from 13/10/28 by Seifeddine Dridi, applied with some modifications. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_WhitespaceManagement@1539809 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src/java')
-rw-r--r--src/java/org/apache/fop/fo/Constants.java7
-rw-r--r--src/java/org/apache/fop/fo/FOPropertyMapping.java10
-rw-r--r--src/java/org/apache/fop/fo/extensions/AlternativeBlock.java98
-rw-r--r--src/java/org/apache/fop/fo/extensions/BestFit.java69
-rw-r--r--src/java/org/apache/fop/fo/extensions/ExtensionElementMapping.java17
-rw-r--r--src/java/org/apache/fop/fo/flow/MultiCase.java70
-rw-r--r--src/java/org/apache/fop/fo/flow/MultiCaseHandler.java38
-rw-r--r--src/java/org/apache/fop/fo/flow/MultiSwitch.java48
-rw-r--r--src/java/org/apache/fop/fo/flow/MultiToggle.java50
-rw-r--r--src/java/org/apache/fop/layoutmgr/Alternative.java73
-rw-r--r--src/java/org/apache/fop/layoutmgr/AlternativeBlockLayoutManager.java241
-rw-r--r--src/java/org/apache/fop/layoutmgr/BestFitLayoutManager.java280
-rw-r--r--src/java/org/apache/fop/layoutmgr/BestFitLayoutUtils.java117
-rw-r--r--src/java/org/apache/fop/layoutmgr/BestFitPenalty.java62
-rw-r--r--src/java/org/apache/fop/layoutmgr/BreakingAlgorithm.java36
-rw-r--r--src/java/org/apache/fop/layoutmgr/ElementListUtils.java31
-rw-r--r--src/java/org/apache/fop/layoutmgr/LayoutManagerMapping.java37
-rw-r--r--src/java/org/apache/fop/layoutmgr/MultiCaseLayoutManager.java89
-rw-r--r--src/java/org/apache/fop/layoutmgr/MultiSwitchLayoutManager.java157
-rw-r--r--src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java44
20 files changed, 762 insertions, 812 deletions
diff --git a/src/java/org/apache/fop/fo/Constants.java b/src/java/org/apache/fop/fo/Constants.java
index 9cec6e566..d285744e4 100644
--- a/src/java/org/apache/fop/fo/Constants.java
+++ b/src/java/org/apache/fop/fo/Constants.java
@@ -816,11 +816,14 @@ public interface Constants {
/** Scope for table header */
int PR_X_HEADER_COLUMN = 290;
- /** Property constant - FOP proprietary*/
+ /** Property constant */
int PR_X_FITTING_STRATEGY = 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
diff --git a/src/java/org/apache/fop/fo/FOPropertyMapping.java b/src/java/org/apache/fop/fo/FOPropertyMapping.java
index 656d5c06c..31166abd7 100644
--- a/src/java/org/apache/fop/fo/FOPropertyMapping.java
+++ b/src/java/org/apache/fop/fo/FOPropertyMapping.java
@@ -2128,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);
@@ -2617,12 +2617,18 @@ public final class FOPropertyMapping implements Constants {
m.setDefault("");
addPropertyMaker("fox:alt-text", m);
- //fox:fitting-strategy, used only in fox:best-fit
+ // fox:fitting-strategy, used only in fox:best-fit
m = new StringProperty.Maker(PR_X_FITTING_STRATEGY);
m.setInherited(false);
m.setDefault("first-fit");
addPropertyMaker("fox:fitting-strategy", m);
+ // fox:auto-toggle, used only in fo:multi-switch
+ m = new StringProperty.Maker(PR_X_AUTO_TOGGLE);
+ m.setInherited(false);
+ m.setDefault("");
+ addPropertyMaker("fox:auto-toggle", m);
+
// fox:border-*-radius-*
m = new CondLengthProperty.Maker(PR_X_BORDER_BEFORE_RADIUS_START);
m.useGeneric(genericCondCornerRadius);
diff --git a/src/java/org/apache/fop/fo/extensions/AlternativeBlock.java b/src/java/org/apache/fop/fo/extensions/AlternativeBlock.java
deleted file mode 100644
index 3e10e73cf..000000000
--- a/src/java/org/apache/fop/fo/extensions/AlternativeBlock.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* $Id$ */
-
-package org.apache.fop.fo.extensions;
-
-import org.xml.sax.Attributes;
-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;
-
-/**
- * A class modeling fox:alternative-block
- */
-
-public class AlternativeBlock extends FObj {
-
- public static final String OBJECT_NAME = "alternative-block";
-
- public AlternativeBlock(FONode parent) {
- super(parent);
- }
-
- @Override
- public void processNode(String elementName, Locator locator,
- Attributes attlist, PropertyList pList) throws FOPException {
- if (log.isDebugEnabled()) {
- log.debug("org.apache.fop.fo.extensions.AlternativeBlock: " + elementName
- + (locator != null ? " at " + getLocatorString(locator) : ""));
- }
- }
-
- @Override
- public void startOfNode() throws FOPException {
- if (log.isDebugEnabled()) {
- log.debug("AlternativeBlock.startOfNode()");
- }
- }
-
- @Override
- public void endOfNode() throws FOPException {
- if (log.isDebugEnabled()) {
- log.debug("AlternativeBlock.endOfNode()");
- }
- }
-
- /**
- * Content model: see {@link Block}
- */
- @Override
- protected void validateChildNode(Locator loc, String nsURI, String localName)
- throws ValidationException {
- if (FOX_URI.equals(nsURI)) {
- if ("best-fit".equals(localName) || "alternative-block".equals(localName)) {
- invalidChildError(loc, FOX_URI, localName);
- }
- } else if (FO_URI.equals(nsURI)) {
- if (!isBlockOrInlineItem(nsURI, localName)) {
- invalidChildError(loc, nsURI, localName);
- }
- }
- }
-
- @Override
- public String getLocalName() {
- return OBJECT_NAME;
- }
-
- @Override
- public String getNormalNamespacePrefix() {
- return ExtensionElementMapping.STANDARD_PREFIX;
- }
-
- @Override
- public String getNamespaceURI() {
- return ExtensionElementMapping.URI;
- }
-
-}
diff --git a/src/java/org/apache/fop/fo/extensions/BestFit.java b/src/java/org/apache/fop/fo/extensions/BestFit.java
index 4b5275f2a..461dd7a26 100644
--- a/src/java/org/apache/fop/fo/extensions/BestFit.java
+++ b/src/java/org/apache/fop/fo/extensions/BestFit.java
@@ -15,8 +15,6 @@
* limitations under the License.
*/
-/* $Id$ */
-
package org.apache.fop.fo.extensions;
import org.xml.sax.Locator;
@@ -24,72 +22,36 @@ 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;
+import org.apache.fop.fo.flow.MultiCaseHandler;
+import org.apache.fop.fo.flow.MultiSwitch;
import org.apache.fop.layoutmgr.Alternative.FittingStrategy;
-/**
- * A class that holds a set of <fox:alternative-block> blocks where each one is examined,
- * and the one that best matches the fitting strategy is selected.
- * The selected alternative should have an occupied BPD that is less than
- * the remaining BPD of the current page.
- */
-public class BestFit extends FObj {
+public class BestFit extends FObj implements MultiCaseHandler {
public static final String OBJECT_NAME = "best-fit";
- private FittingStrategy strategy = FittingStrategy.FIRST_FIT;
+ private FittingStrategy strategy;
public BestFit(FONode parent) {
super(parent);
-
}
- /** {@inheritDoc} */
- @Override
- public void bind(PropertyList pList) throws FOPException {
- super.bind(pList);
- String strategyName = pList.get(PR_X_FITTING_STRATEGY).getString();
- for (FittingStrategy fs : FittingStrategy.values()) {
- if (fs.getStrategyName().equals(strategyName)) {
- strategy = fs;
- return;
+ public void setFittingStrategy(String strategyName) {
+ strategy = FittingStrategy.make(strategyName);
+ if (strategy == null) {
+ strategy = FittingStrategy.FIRST_FIT;
+ if (log.isWarnEnabled()) {
+ log.warn("Unrecognized strategy name => " + strategyName + ". Using default strategy (first-fit");
}
}
- if (log.isWarnEnabled()) {
- log.warn("Unrecognized strategy name => " + strategyName + ". Using default strategy (first-fit");
- }
- }
-
- @Override
- public void startOfNode() throws FOPException {
- super.startOfNode();
- if (log.isDebugEnabled()) {
- log.debug("BestFit.startOfNode()");
- }
- }
-
- @Override
- public void endOfNode() throws FOPException {
- super.endOfNode();
- if (log.isDebugEnabled()) {
- log.debug("BestFit.endOfNode()");
- }
}
/**
* {@inheritDoc}
- * Content model: (fox:alternative-block)+
*/
@Override
protected void validateChildNode(Locator loc, String nsURI, String localName)
throws ValidationException {
- if (FOX_URI.equals(nsURI)) {
- if (!"alternative-block".equals(localName)) {
- invalidChildError(loc, FOX_URI, localName);
- }
- } else {
- invalidChildError(loc, nsURI, localName);
- }
}
@Override
@@ -107,8 +69,19 @@ public class BestFit extends FObj {
return ExtensionElementMapping.URI;
}
+ public void filter(MultiSwitch multiSwitch) throws FOPException {
+ // Modifying the FO tree is not advised...
+// FONodeIterator nodeIter = multiSwitch.getChildNodes();
+// while (nodeIter.hasNext()) {
+// FONode childNode = (FONode) nodeIter.next();
+// this.addChildNode(childNode);
+// }
+// multiSwitch.clearChildNodes();
+ }
+
public FittingStrategy getStrategy() {
return strategy;
}
}
+
diff --git a/src/java/org/apache/fop/fo/extensions/ExtensionElementMapping.java b/src/java/org/apache/fop/fo/extensions/ExtensionElementMapping.java
index f6f681acc..6bd90784f 100644
--- a/src/java/org/apache/fop/fo/extensions/ExtensionElementMapping.java
+++ b/src/java/org/apache/fop/fo/extensions/ExtensionElementMapping.java
@@ -50,6 +50,7 @@ public class ExtensionElementMapping extends ElementMapping {
PROPERTY_ATTRIBUTES.add("internal-destination");
PROPERTY_ATTRIBUTES.add("disable-column-balancing");
PROPERTY_ATTRIBUTES.add("fitting-strategy");
+ PROPERTY_ATTRIBUTES.add("auto-toggle");
//These are FOP's extension properties for accessibility
PROPERTY_ATTRIBUTES.add("alt-text");
PROPERTY_ATTRIBUTES.add("header");
@@ -87,8 +88,6 @@ public class ExtensionElementMapping extends ElementMapping {
foObjs.put("label", new UnknownXMLObj.Maker(URI));
foObjs.put("destination", new DestinationMaker());
foObjs.put("external-document", new ExternalDocumentMaker());
- foObjs.put("best-fit", new BestFitMaker());
- foObjs.put("alternative-block", new AlternativeBlockMaker());
}
}
@@ -106,20 +105,6 @@ public class ExtensionElementMapping extends ElementMapping {
}
}
- static class BestFitMaker extends ElementMapping.Maker {
- @Override
- public FONode make(FONode parent) {
- return new BestFit(parent);
- }
- }
-
- static class AlternativeBlockMaker extends ElementMapping.Maker {
- @Override
- public FONode make(FONode parent) {
- return new AlternativeBlock(parent);
- }
- }
-
/** {@inheritDoc} */
@Override
public String getStandardPrefix() {
diff --git a/src/java/org/apache/fop/fo/flow/MultiCase.java b/src/java/org/apache/fop/fo/flow/MultiCase.java
index ac965dffb..053e0d6f2 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">
@@ -32,6 +35,9 @@ import org.apache.fop.fo.PropertyList;
public class MultiCase extends FObj {
// The value of properties relevant for fo:multi-case.
private int startingState;
+ private String caseName;
+ private String caseTitle;
+ private MultiCaseHandler multiCaseHandler;
// private ToBeImplementedProperty caseName;
// private ToBeImplementedProperty caseTitle;
// Unused but valid items, commented out for performance:
@@ -55,12 +61,50 @@ public class MultiCase extends FObj {
}
}
- /** {@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();
+ if (startingState == EN_SHOW) {
+ MultiSwitch multiSwitch = (MultiSwitch) parent;
+ if (multiSwitch.getCurrentlyVisibleNode() == null) {
+ multiSwitch.setCurrentlyVisibleNode(this);
+ }
+ }
+ }
+
+ /**
+ * 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)*");
+ }
+ }
+
+ @Override
+ protected void addChildNode(FONode child) throws FOPException {
+ if (child instanceof MultiCaseHandler) {
+ multiCaseHandler = (MultiCaseHandler) child;
+ }
+ super.addChildNode(child);
}
/** @return the "starting-state" property */
@@ -68,7 +112,7 @@ public class MultiCase extends FObj {
return startingState;
}
- /** {@inheritDoc} */
+ @Override
public String getLocalName() {
return "multi-case";
}
@@ -77,7 +121,25 @@ 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;
+ }
+
+ public boolean isActuated() {
+ return multiCaseHandler != null;
+ }
+
+ MultiCaseHandler getHandler() {
+ return multiCaseHandler;
+ }
+
}
diff --git a/src/java/org/apache/fop/fo/flow/MultiCaseHandler.java b/src/java/org/apache/fop/fo/flow/MultiCaseHandler.java
new file mode 100644
index 000000000..25a11bd68
--- /dev/null
+++ b/src/java/org/apache/fop/fo/flow/MultiCaseHandler.java
@@ -0,0 +1,38 @@
+/*
+ * 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.fo.flow;
+
+import org.apache.fop.apps.FOPException;
+
+/**
+ * This interface is used in conjunction with {@link MultiSwitch}
+ * to implement a callback system for handling fo:multi-case elements.
+ */
+
+public interface MultiCaseHandler {
+
+ /**
+ * A filtering function used to select one or more fo:multi-case
+ * elements, children of {@link MultiSwitch}.
+ *
+ * @param multiSwitch parent of the fo:multi-case elements to filter
+ * @throws FOPException
+ */
+ void filter(MultiSwitch multiSwitch) throws FOPException;
+
+}
diff --git a/src/java/org/apache/fop/fo/flow/MultiSwitch.java b/src/java/org/apache/fop/fo/flow/MultiSwitch.java
index d8ebee4cb..0c1bb2cde 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,10 @@ public class MultiSwitch extends FObj {
// private CommonAccessibility commonAccessibility;
// End of property values
- private static boolean notImplementedWarningGiven = false;
+ private static boolean notImplementedWarningGiven;
+ private FONode currentlyVisibleMultiCase;
+ private String autoToggle;
+ private String fittingStrategy;
/**
* Base constructor
@@ -57,23 +59,44 @@ public class MultiSwitch extends FObj {
}
/** {@inheritDoc} */
+ @Override
public void bind(PropertyList pList) throws FOPException {
super.bind(pList);
+ autoToggle = pList.get(PR_X_AUTO_TOGGLE).getString();
+ fittingStrategy = pList.get(PR_X_FITTING_STRATEGY).getString();
// autoRestore = pList.get(PR_AUTO_RESTORE);
}
-
/** {@inheritDoc} */
+ @Override
public void endOfNode() throws FOPException {
if (firstChild == null) {
missingChildElementError("(multi-case+)");
}
+ super.endOfNode();
+ }
+
+ @Override
+ public void finalizeNode() throws FOPException {
+ if (autoToggle.equals("best-fit")) {
+ // Nothing to do in this case
+ setCurrentlyVisibleNode(null);
+ } else {
+ FONodeIterator nodeIter = getChildNodes();
+ while (nodeIter.hasNext()) {
+ MultiCase multiCase = (MultiCase) nodeIter.next();
+ if (multiCase.isActuated()) {
+ multiCase.getHandler().filter(this);
+ }
+ }
+ }
}
/**
* {@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 +107,7 @@ public class MultiSwitch extends FObj {
}
/** {@inheritDoc} */
+ @Override
public String getLocalName() {
return "multi-switch";
}
@@ -92,7 +116,25 @@ 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 void setCurrentlyVisibleNode(FONode node) {
+ currentlyVisibleMultiCase = node;
+ }
+
+ public FONode getCurrentlyVisibleNode() {
+ return currentlyVisibleMultiCase;
+ }
+
+ public String getFittingStrategy() {
+ return fittingStrategy;
+ }
+
+ public String 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..04da3083a 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,16 +26,17 @@ 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;
/**
* Class modelling the <a href="http://www.w3.org/TR/xsl/#fo_multi-toggle">
* <code>fo:multi-toggle<code></a> property.
*/
-public class MultiToggle extends FObj {
+public class MultiToggle extends FObj implements MultiCaseHandler {
// 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,44 @@ public class MultiToggle extends FObj {
* {@inheritDoc}
* @return {@link org.apache.fop.fo.Constants#FO_MULTI_TOGGLE}
*/
+ @Override
public int getNameId() {
return FO_MULTI_TOGGLE;
}
+
+ public void filter(MultiSwitch multiSwitch) throws FOPException {
+ if (multiSwitch.getCurrentlyVisibleNode() == null) {
+ multiSwitch.setCurrentlyVisibleNode(parent);
+ }
+
+ FONode currentlyVisibleMultiCase = multiSwitch.getCurrentlyVisibleNode();
+
+ if (prSwitchTo.getString().equals("xsl-any")) {
+// NoOp
+ } else if (prSwitchTo.getString().equals("xsl-preceding")) {
+ FONodeIterator nodeIter = multiSwitch.getChildNodes(currentlyVisibleMultiCase);
+ if (nodeIter != null) {
+ if (!nodeIter.hasPrevious()) {
+ currentlyVisibleMultiCase = nodeIter.lastNode();
+ } else {
+ currentlyVisibleMultiCase = nodeIter.previousNode();
+ }
+ }
+ } else if (prSwitchTo.getString().equals("xsl-following")) {
+ FONodeIterator nodeIter = multiSwitch.getChildNodes(currentlyVisibleMultiCase);
+ if (nodeIter != null) {
+ //Ignore the first node
+ nodeIter.next();
+ if (!nodeIter.hasNext()) {
+ currentlyVisibleMultiCase = nodeIter.firstNode();
+ } else {
+ currentlyVisibleMultiCase = nodeIter.nextNode();
+ }
+ }
+ } else {
+ // Pick an fo:multi-case that matches a case-name...
+ }
+
+ multiSwitch.setCurrentlyVisibleNode(currentlyVisibleMultiCase);
+ }
}
diff --git a/src/java/org/apache/fop/layoutmgr/Alternative.java b/src/java/org/apache/fop/layoutmgr/Alternative.java
index 9162a63b5..9487b7462 100644
--- a/src/java/org/apache/fop/layoutmgr/Alternative.java
+++ b/src/java/org/apache/fop/layoutmgr/Alternative.java
@@ -19,24 +19,27 @@
package org.apache.fop.layoutmgr;
+import java.util.LinkedList;
import java.util.List;
+/**
+ * An alternative has a set of fitness traits (e.g. occupied bpd and ipd,
+ * adjustment ratio, remaining size, etc.) that determine how good its
+ * eligibility is when evaluated by a fitting strategy.
+ */
public class Alternative {
- /** remaining BPD after inserting the alternative */
+ /** Remaining BPD after inserting the alternative. */
private int remainingBPD;
- /** width of the alternative in block-progressing-dimension */
- private final int width;
- /** Knuth element list */
+ /** Size of the alternative in block-progression-direction. */
+ private final int length;
private final List<ListElement> knuthList;
- /** Indicates whether we should consider the alternative or not */
- private boolean enabled;
+ private boolean enabled = true;
- public Alternative(List<ListElement> knuthList, int width) {
+ public Alternative(List<ListElement> knuthList, int length) {
this.knuthList = knuthList;
- this.width = width;
+ this.length = length;
this.remainingBPD = 0;
- this.enabled = false;
}
public List<ListElement> getKnuthList() {
@@ -47,8 +50,8 @@ public class Alternative {
return remainingBPD;
}
- public int getWidth() {
- return width;
+ public int getLength() {
+ return length;
}
public void setRemainingBPD(int remainingBPD) {
@@ -68,20 +71,22 @@ public class Alternative {
FIRST_FIT("first-fit") {
@Override
- public Alternative filter(List<Alternative> alternatives) {
+ public List<Alternative> filter(List<Alternative> alternatives) {
+ List<Alternative> alts = new LinkedList<Alternative>();
for (Alternative alt : alternatives) {
if (alt.isEnabled()) {
- return alt;
+ alts.add(alt);
+ break;
}
}
- return null;
+ return alts;
}
},
SMALLEST_FIT("smallest-fit") {
@Override
- public Alternative filter(List<Alternative> alternatives) {
+ public List<Alternative> filter(List<Alternative> alternatives) {
int biggestDiff = -Integer.MAX_VALUE;
Alternative bestAlt = null;
@@ -91,14 +96,16 @@ public class Alternative {
bestAlt = alt;
}
}
- return bestAlt;
+ List<Alternative> alts = new LinkedList<Alternative>();
+ alts.add(bestAlt);
+ return alts;
}
},
BIGGEST_FIT("biggest-fit") {
@Override
- public Alternative filter(List<Alternative> alternatives) {
+ public List<Alternative> filter(List<Alternative> alternatives) {
int smallestDiff = Integer.MAX_VALUE;
Alternative bestAlt = null;
@@ -108,7 +115,26 @@ public class Alternative {
bestAlt = alt;
}
}
- return bestAlt;
+ List<Alternative> alts = new LinkedList<Alternative>();
+ alts.add(bestAlt);
+ return alts;
+ }
+ },
+
+ ANY("any") {
+
+ @Override
+ public List<Alternative> filter(List<Alternative> alternatives) {
+ List<Alternative> alts = new LinkedList<Alternative>();
+
+ int remainingSpace = Integer.MAX_VALUE;
+ for (Alternative alt : alternatives) {
+ if (alt.isEnabled() && alt.getLength() <= remainingSpace) {
+ alts.add(alt);
+ remainingSpace = alt.getRemainingBPD();
+ }
+ }
+ return alts;
}
};
@@ -122,11 +148,20 @@ public class Alternative {
return strategyName;
}
+ public static FittingStrategy make(String strategyName) {
+ for (FittingStrategy fs : FittingStrategy.values()) {
+ if (fs.getStrategyName().equals(strategyName)) {
+ return fs;
+ }
+ }
+ return null;
+ }
+
/**
* @param alternatives the list of potential candidate {@link Alternative}
* @return the best alternative according to the strategy being employed
*/
- public abstract Alternative filter(List<Alternative> alternatives);
+ public abstract List<Alternative> filter(List<Alternative> alternatives);
}
}
diff --git a/src/java/org/apache/fop/layoutmgr/AlternativeBlockLayoutManager.java b/src/java/org/apache/fop/layoutmgr/AlternativeBlockLayoutManager.java
deleted file mode 100644
index e82575a4b..000000000
--- a/src/java/org/apache/fop/layoutmgr/AlternativeBlockLayoutManager.java
+++ /dev/null
@@ -1,241 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* $Id$ */
-
-package org.apache.fop.layoutmgr;
-
-import java.util.LinkedList;
-import java.util.List;
-import java.util.ListIterator;
-import java.util.Stack;
-
-import org.apache.fop.area.Area;
-import org.apache.fop.area.Block;
-import org.apache.fop.area.LineArea;
-import org.apache.fop.fo.extensions.AlternativeBlock;
-
-/**
- * Layout manager for {@link AlternativeBlock}
- */
-
-public class AlternativeBlockLayoutManager extends AbstractLayoutManager {
-
- private Block curBlockArea;
-
- public AlternativeBlockLayoutManager(AlternativeBlock node) {
- super(node);
- setGeneratesBlockArea(true);
- }
-
- /**
- * Creates and initializes a {@link LayoutContext} to pass to the child LM
- *
- * @param context the parent {@link LayoutContext}
- * @return a new child layout context
- */
- protected LayoutContext makeChildLayoutContext(LayoutContext context) {
- LayoutContext childLC = LayoutContext.newInstance();
- childLC.copyPendingMarksFrom(context);
- childLC.setStackLimitBP(context.getStackLimitBP());
- childLC.setRefIPD(context.getRefIPD());
- childLC.setWritingMode(context.getWritingMode());
- return childLC;
- }
-
- /** {@inheritDoc} */
- @Override
- public List getNextKnuthElements(LayoutContext context, int alignment) {
- return getNextKnuthElements(context, alignment, null, null, null);
- }
-
- /** {@inheritDoc} */
- @Override
- public List getNextKnuthElements(LayoutContext context, int alignment,
- Stack lmStack, Position positionAtIPDChange,
- LayoutManager restartAtLM) {
- LayoutManager curLM;
- List<ListElement> knuthList = new LinkedList<ListElement>();
- while ((curLM = getChildLM()) != null) {
- LayoutContext childLC = makeChildLayoutContext(context);
-
- List childKnuthList = null;
- if (!curLM.isFinished()) {
- childKnuthList = curLM.getNextKnuthElements(childLC, alignment);
- }
- if (childKnuthList != null) {
- wrapPositionElements(childKnuthList, knuthList);
- }
- }
- setFinished(true);
- return knuthList;
- }
-
- /**
- * "wrap" the Position inside each element moving the elements from SourceList to targetList
- *
- * @param sourceList source list
- * @param targetList target list receiving the wrapped position elements
- */
- protected void wrapPositionElements(List sourceList, List targetList) {
- wrapPositionElements(sourceList, targetList, false);
- }
-
- /**
- * "wrap" the Position inside each element moving the elements from
- * SourceList to targetList
- *
- * @param sourceList source list
- * @param targetList target list receiving the wrapped position elements
- * @param force if true, every Position is wrapped regardless of its LM of origin
- */
- protected void wrapPositionElements(List sourceList, List targetList,
- boolean force) {
-
- ListIterator listIter = sourceList.listIterator();
- Object tempElement;
- while (listIter.hasNext()) {
- tempElement = listIter.next();
- if (tempElement instanceof ListElement) {
- wrapPositionElement((ListElement) tempElement, targetList,
- force);
- } else if (tempElement instanceof List) {
- wrapPositionElements((List) tempElement, targetList, force);
- }
- }
- }
-
- /**
- * "wrap" the Position inside the given element and add it to the target list.
- *
- * @param el the list element
- * @param targetList target list receiving the wrapped position elements
- * @param force if true, every Position is wrapped regardless of its LM of origin
- */
- protected void wrapPositionElement(ListElement el, List targetList,
- boolean force) {
- if (force || el.getLayoutManager() != this) {
- el.setPosition(notifyPos(new NonLeafPosition(this, el.getPosition())));
- }
- targetList.add(el);
- }
-
- @Override
- public Area getParentArea(Area childArea) {
- if (curBlockArea == null) {
- curBlockArea = new Block();
- // Set up dimensions
- // Must get dimensions from parent area
- /*Area parentArea = */parentLayoutManager.getParentArea(curBlockArea);
- }
- return curBlockArea;
- }
-
- /** {@inheritDoc} */
- @Override
- public void addChildArea(Area childArea) {
- if (curBlockArea != null) {
- if (childArea instanceof LineArea) {
- curBlockArea.addLineArea((LineArea) childArea);
- } else {
- curBlockArea.addBlock((Block) childArea);
- }
- }
- }
-
- /**
- * Force current area to be added to parent area.
- */
- protected void flush() {
- if (getCurrentArea() != null) {
- parentLayoutManager.addChildArea(getCurrentArea());
- }
- }
-
- private Area getCurrentArea() {
- return curBlockArea;
- }
-
- /** {@inheritDoc} */
- @Override
- public void addAreas(PositionIterator parentIter,
- LayoutContext layoutContext) {
-
- getParentArea(null);
-
- addId();
-
- LayoutManager childLM;
- LayoutContext lc = LayoutContext.offspringOf(layoutContext);
- LayoutManager firstLM = null;
- LayoutManager lastLM = null;
- Position firstPos = null;
- Position lastPos = null;
-
- // "unwrap" the NonLeafPositions stored in parentIter
- // and put them in a new list;
- LinkedList<Position> positionList = new LinkedList<Position>();
- Position pos;
- while (parentIter.hasNext()) {
- pos = parentIter.next();
- if (pos.getIndex() >= 0) {
- if (firstPos == null) {
- firstPos = pos;
- }
- lastPos = pos;
- }
- if (pos instanceof NonLeafPosition && (pos.getPosition() != null)
- && pos.getPosition().getLM() != this) {
- // pos was created by a child of this BestFitBlockLM
- positionList.add(pos.getPosition());
- lastLM = pos.getPosition().getLM();
- if (firstLM == null) {
- firstLM = lastLM;
- }
- }
- }
-
- registerMarkers(true, isFirst(firstPos), isLast(lastPos));
-
- PositionIterator childPosIter = new PositionIterator(
- positionList.listIterator());
- while ((childLM = childPosIter.getNextChildLM()) != null) {
- // Add the block areas to Area
- // set the space adjustment ratio
- lc.setSpaceAdjust(layoutContext.getSpaceAdjust());
- lc.setFlags(LayoutContext.FIRST_AREA, childLM == firstLM);
- lc.setFlags(LayoutContext.LAST_AREA, childLM == lastLM);
- lc.setStackLimitBP(layoutContext.getStackLimitBP());
- childLM.addAreas(childPosIter, lc);
- }
-
- registerMarkers(false, isFirst(firstPos), isLast(lastPos));
-
- flush();
-
- curBlockArea = null;
-
- checkEndOfLayout(lastPos);
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean isRestartable() {
- return true;
- }
-
-}
diff --git a/src/java/org/apache/fop/layoutmgr/BestFitLayoutManager.java b/src/java/org/apache/fop/layoutmgr/BestFitLayoutManager.java
deleted file mode 100644
index 9108663f9..000000000
--- a/src/java/org/apache/fop/layoutmgr/BestFitLayoutManager.java
+++ /dev/null
@@ -1,280 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* $Id$ */
-
-package org.apache.fop.layoutmgr;
-
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.ListIterator;
-import java.util.Stack;
-
-import org.apache.fop.area.Area;
-import org.apache.fop.area.Block;
-import org.apache.fop.area.LineArea;
-import org.apache.fop.fo.extensions.BestFit;
-import org.apache.fop.layoutmgr.Alternative.FittingStrategy;
-
-/**
- * LayoutManager for a fox:best-fit. It selects the "best" alternative
- * to render based on the chosen fitting strategy.
- */
-public class BestFitLayoutManager extends AbstractLayoutManager {
-
- private Block curBlockArea;
- private BestFitPenalty bestFitPenalty;
-
- private static class BestFitPosition extends Position {
-
- public BestFitPosition(LayoutManager lm) {
- super(lm);
- }
-
- }
-
- private final FittingStrategy fittingStrategy;
-
- public BestFitLayoutManager(BestFit node) {
- super(node);
- fittingStrategy = node.getStrategy();
- setGeneratesBlockArea(true);
- }
-
- /**
- * Creates and initializes a {@link LayoutContext} to pass to the child LM
- *
- * @param context the parent {@link LayoutContext}
- * @return a new child layout context
- */
- protected LayoutContext makeChildLayoutContext(LayoutContext context) {
- LayoutContext childLC = LayoutContext.newInstance();
- childLC.copyPendingMarksFrom(context);
- childLC.setStackLimitBP(context.getStackLimitBP());
- childLC.setRefIPD(context.getRefIPD());
- childLC.setWritingMode(context.getWritingMode());
- return childLC;
- }
-
- /** {@inheritDoc} */
- @Override
- public List getNextKnuthElements(LayoutContext context, int alignment) {
- return getNextKnuthElements(context, alignment, null, null, null);
- }
-
- /** {@inheritDoc} */
- @Override
- public List getNextKnuthElements(LayoutContext context, int alignment,
- Stack lmStack, Position positionAtIPDChange,
- LayoutManager restartAtLM) {
- LayoutManager curLM; // currently active LM
- bestFitPenalty = new BestFitPenalty(fittingStrategy, new BestFitPosition(this));
- while ((curLM = getChildLM()) != null) {
- LayoutContext childLC = makeChildLayoutContext(context);
-
- List childKnuthList = null;
- if (!curLM.isFinished()) {
- childKnuthList = curLM.getNextKnuthElements(childLC, alignment);
- }
- if (childKnuthList != null) {
- List<ListElement> newKnuthList = new LinkedList<ListElement>();
- this.wrapPositionElements(childKnuthList, newKnuthList);
- int contentLength = ElementListUtils.calcFullContentLength(newKnuthList);
- // Add a new variant
- bestFitPenalty.addAlternative(new Alternative(newKnuthList, contentLength));
- }
- }
- setFinished(true);
- List<ListElement> finalList = new LinkedList<ListElement>();
- // Enclose the penalty with two empty Knuth boxes
- // to prevent the layout engine from ignoring it.
- // I know this seems like a hack, but I'll address
- // this issue properly when more tests are done
- finalList.add(new KnuthBox(0, new Position(this), false));
- finalList.add(bestFitPenalty);
- finalList.add(new KnuthBox(0, new Position(this), false));
- return finalList;
- }
-
- /**
- * "wrap" the Position inside each element moving the elements from
- * SourceList to targetList
- *
- * @param sourceList source list
- * @param targetList target list receiving the wrapped position elements
- */
- protected void wrapPositionElements(List sourceList, List targetList) {
- wrapPositionElements(sourceList, targetList, false);
- }
-
- /**
- * "wrap" the Position inside each element moving the elements from
- * SourceList to targetList
- *
- * @param sourceList source list
- * @param targetList target list receiving the wrapped position elements
- * @param force if true, every Position is wrapped regardless of its LM of origin
- */
- protected void wrapPositionElements(List sourceList, List targetList,
- boolean force) {
-
- ListIterator listIter = sourceList.listIterator();
- Object tempElement;
- while (listIter.hasNext()) {
- tempElement = listIter.next();
- if (tempElement instanceof ListElement) {
- wrapPositionElement((ListElement) tempElement, targetList,
- force);
- } else if (tempElement instanceof List) {
- wrapPositionElements((List) tempElement, targetList, force);
- }
- }
- }
-
- /**
- * "wrap" the Position inside the given element and add it to the target list.
- *
- * @param el the list element
- * @param targetList target list receiving the wrapped position elements
- * @param force if true, every Position is wrapped regardless of its LM of origin
- */
- protected void wrapPositionElement(ListElement el, List targetList,
- boolean force) {
- if (force || el.getLayoutManager() != this) {
- el.setPosition(notifyPos(new NonLeafPosition(this, el.getPosition())));
- }
- targetList.add(el);
- }
-
- @Override
- public Area getParentArea(Area childArea) {
- if (curBlockArea == null) {
- curBlockArea = new Block();
- // Set up dimensions
- // Must get dimensions from parent area
- /*Area parentArea = */parentLayoutManager.getParentArea(curBlockArea);
- }
- return curBlockArea;
- }
-
- /** {@inheritDoc} */
- @Override
- public void addChildArea(Area childArea) {
- if (curBlockArea != null) {
- if (childArea instanceof LineArea) {
- curBlockArea.addLineArea((LineArea) childArea);
- } else {
- curBlockArea.addBlock((Block) childArea);
- }
- }
- }
-
- /**
- * Force current area to be added to parent area.
- */
- protected void flush() {
- if (getCurrentArea() != null) {
- parentLayoutManager.addChildArea(getCurrentArea());
- }
- }
-
- private Area getCurrentArea() {
- return curBlockArea;
- }
-
- /** {@inheritDoc} */
- @Override
- public void addAreas(PositionIterator parentIter,
- LayoutContext layoutContext) {
-
- getParentArea(null);
-
- addId();
-
- LayoutManager childLM;
- LayoutContext lc = LayoutContext.offspringOf(layoutContext);
- LayoutManager firstLM = null;
- LayoutManager lastLM = null;
- Position firstPos = null;
- Position lastPos = null;
-
- // "unwrap" the NonLeafPositions stored in parentIter
- // and put them in a new list;
- LinkedList<Position> positionList = new LinkedList<Position>();
- Position pos;
- while (parentIter.hasNext()) {
- pos = parentIter.next();
- if (pos.getIndex() >= 0) {
- if (firstPos == null) {
- firstPos = pos;
- }
- lastPos = pos;
- }
- if (pos instanceof NonLeafPosition && (pos.getPosition() != null)
- && pos.getPosition().getLM() != this) {
- // pos was created by a child of this BestFitBlockLM
- positionList.add(pos.getPosition());
- lastLM = pos.getPosition().getLM();
- if (firstLM == null) {
- firstLM = lastLM;
- }
- } else if (pos instanceof BestFitPosition) {
- if (bestFitPenalty.getBestAlternative() != null) {
- Alternative bestAlt = bestFitPenalty.getBestAlternative();
- Iterator<ListElement> it = bestAlt.getKnuthList().iterator();
- while (it.hasNext()) {
- positionList.add(it.next().getPosition());
- }
- }
- lastLM = pos.getLM();
- if (firstLM == null) {
- firstLM = lastLM;
- }
- }
- }
-
- //registerMarkers(true, isFirst(firstPos), isLast(lastPos));
-
- PositionIterator childPosIter = new PositionIterator(
- positionList.listIterator());
- while ((childLM = childPosIter.getNextChildLM()) != null) {
- // Add the block areas to Area
- // set the space adjustment ratio
- lc.setSpaceAdjust(layoutContext.getSpaceAdjust());
- lc.setFlags(LayoutContext.FIRST_AREA, childLM == firstLM);
- lc.setFlags(LayoutContext.LAST_AREA, childLM == lastLM);
- lc.setStackLimitBP(layoutContext.getStackLimitBP());
- childLM.addAreas(childPosIter, lc);
- }
-
- //registerMarkers(false, isFirst(firstPos), isLast(lastPos));
-
- flush();
-
- curBlockArea = null;
-
- checkEndOfLayout(lastPos);
- }
-
- /** {@inheritDoc} */
- @Override
- public boolean isRestartable() {
- return true;
- }
-
-}
diff --git a/src/java/org/apache/fop/layoutmgr/BestFitLayoutUtils.java b/src/java/org/apache/fop/layoutmgr/BestFitLayoutUtils.java
new file mode 100644
index 000000000..af82df386
--- /dev/null
+++ b/src/java/org/apache/fop/layoutmgr/BestFitLayoutUtils.java
@@ -0,0 +1,117 @@
+/*
+ * 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.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.fop.layoutmgr.Alternative.FittingStrategy;
+
+/*
+ * Utility class used in {@link MultiSwitchLayoutManager}
+ * to handle the <i>best-fit</i> property value if specified in {@link MultiSwitch}
+ */
+public final class BestFitLayoutUtils {
+
+ private BestFitLayoutUtils() { }
+
+ static class BestFitPosition extends Position {
+
+ public List<ListElement> knuthList;
+
+ public BestFitPosition(LayoutManager lm) {
+ super(lm);
+ }
+
+ public List<Position> getPositionList() {
+ List<Position> positions = new LinkedList<Position>();
+ if (knuthList != null) {
+
+ SpaceResolver.performConditionalsNotification(knuthList, 0, knuthList.size() - 1, -1);
+
+ for (ListElement elem : knuthList) {
+ if (elem.getPosition() != null && elem.getLayoutManager() != null) {
+ positions.add(elem.getPosition());
+ }
+ }
+ }
+ return positions;
+ }
+
+ public void setKnuthList(List<ListElement> knuthList) {
+ this.knuthList = knuthList;
+ }
+
+ public List<ListElement> getKnuthList() {
+ return knuthList;
+ }
+
+ }
+
+ public static Alternative makeAlternative(List<ListElement> childList) {
+ // Add a zero penalty to make the SpaceResolver
+ // transform Space elements into Knuth glues.
+ childList.add(KnuthPenalty.DUMMY_ZERO_PENALTY);
+ SpaceResolver.resolveElementList(childList);
+ int contentLength = ElementListUtils.calcContentLength(childList);
+ return new Alternative(childList, contentLength);
+ }
+
+ public static List<ListElement> getKnuthList(LayoutManager lm,
+ List<List<ListElement>> childrenLists,
+ FittingStrategy strategy) {
+ List<ListElement> knuthList = new LinkedList<ListElement>();
+ Iterator<List<ListElement>> iter = childrenLists.iterator();
+ BestFitPenalty bestFitPenalty = new BestFitPenalty(strategy, new BestFitPosition(lm));
+ while (iter.hasNext()) {
+ List<ListElement> childList = iter.next();
+ bestFitPenalty.addAlternative(makeAlternative(childList));
+ }
+ // A penalty must always be preceded by a box
+ // to be considered as a valid breakpoint.
+ addKnuthPenalty(lm, knuthList, bestFitPenalty);
+ return knuthList;
+ }
+
+ public static void addKnuthPenalty(LayoutManager lm, List<ListElement> list,
+ KnuthPenalty bestFitPenalty) {
+
+ list.add(0, new KnuthBox(0, new Position(lm), false));
+ list.add(bestFitPenalty);
+ list.add(new KnuthBox(0, new Position(lm), false));
+ }
+
+ public static List<Position> getPositionList(LayoutManager lm, PositionIterator posIter) {
+
+ // "unwrap" the NonLeafPositions stored in parentIter
+ // and put them in a new list;
+ LinkedList<Position> positionList = new LinkedList<Position>();
+ Position pos;
+ while (posIter.hasNext()) {
+ pos = posIter.next();
+ if (pos instanceof BestFitPosition) {
+ positionList.addAll(((BestFitPosition) pos).getPositionList());
+ } else {
+ positionList.add(pos);
+ }
+ }
+ return positionList;
+ }
+
+}
diff --git a/src/java/org/apache/fop/layoutmgr/BestFitPenalty.java b/src/java/org/apache/fop/layoutmgr/BestFitPenalty.java
index badd3dbf0..d3ee6f722 100644
--- a/src/java/org/apache/fop/layoutmgr/BestFitPenalty.java
+++ b/src/java/org/apache/fop/layoutmgr/BestFitPenalty.java
@@ -23,17 +23,20 @@ import java.util.LinkedList;
import java.util.List;
import org.apache.fop.layoutmgr.Alternative.FittingStrategy;
+import org.apache.fop.layoutmgr.BestFitLayoutUtils.BestFitPosition;
/**
- * A dummy penalty used in {@link BestFitLayoutManager} to store
- * the different alternatives in {@link fox:best-fit}
+ * A penalty class used to specify a set of alternatives for the layout engine
+ * to choose from. The chosen alternative must have an occupied size
+ * that is less than the available BPD of the current page
+ * and it must also be the best match when it is evaluated by {@link FittingStrategy}.
*/
-
public class BestFitPenalty extends KnuthPenalty {
private final LinkedList<Alternative> alternatives;
private final FittingStrategy strategy;
- private Alternative bestAlternative = null;
+ public boolean canFit = true;
+ private int currentAltIndex;
public BestFitPenalty(FittingStrategy strategy, Position pos) {
super(0, 0, false, pos, false);
@@ -49,30 +52,59 @@ public class BestFitPenalty extends KnuthPenalty {
return alternatives;
}
- public FittingStrategy getStrategyType() {
+ public FittingStrategy getFittingStrategy() {
return strategy;
}
- public Alternative getBestAlternative() {
- if (bestAlternative != null) {
- return bestAlternative;
+ @Override
+ public int getWidth() {
+ if (currentAltIndex == -1) {
+ return 0;
+ }
+ return alternatives.get(currentAltIndex).getLength();
+ }
+
+ public boolean hasMoreAlternatives() {
+ return currentAltIndex != -1;
+ }
+
+ public void considerNextAlternative() {
+ if (currentAltIndex < alternatives.size() - 1) {
+ currentAltIndex++;
} else {
- bestAlternative = strategy.filter(alternatives);
- return bestAlternative;
+ currentAltIndex = -1;
}
}
-// public void setBestAlternative(Alternative bestAlternative) {
-// this.bestAlternative = bestAlternative;
-// }
+ @Override
+ public Position getPosition() {
+ if (currentAltIndex != -1) {
+ Position pos = super.getPosition();
+ if (alternatives.size() > 0) {
+ getBestFitPosition().setKnuthList(alternatives.get(currentAltIndex).getKnuthList());
+ }
+ return pos;
+ }
+ return null;
+ }
+
+ public BestFitPosition getBestFitPosition() {
+ Position pos = super.getPosition();
+ while (pos != null) {
+ if (pos instanceof BestFitPosition) {
+ return (BestFitPosition) pos;
+ }
+ pos = pos.getPosition();
+ }
+ return null;
+ }
- /** {@inheritDoc} */
@Override
public String toString() {
String str = super.toString();
StringBuffer buffer = new StringBuffer(64);
buffer.append(" number of alternatives = " + getAlternatives().size());
- buffer.append(" fitting-strategy = " + strategy);
+ buffer.append(" fitting-strategy = " + strategy.getStrategyName());
return str + buffer.toString();
}
diff --git a/src/java/org/apache/fop/layoutmgr/BreakingAlgorithm.java b/src/java/org/apache/fop/layoutmgr/BreakingAlgorithm.java
index 71106f516..4cf15f3a0 100644
--- a/src/java/org/apache/fop/layoutmgr/BreakingAlgorithm.java
+++ b/src/java/org/apache/fop/layoutmgr/BreakingAlgorithm.java
@@ -304,7 +304,6 @@ public abstract class BreakingAlgorithm {
}
/** {@inheritDoc} */
- @Override
public String toString() {
return "<KnuthNode at " + position + " "
+ totalWidth + "+" + totalStretch + "-" + totalShrink
@@ -931,13 +930,7 @@ public abstract class BreakingAlgorithm {
if (node.position == elementIdx) {
continue;
}
- int difference;
- if (element instanceof BestFitPenalty) {
- BestFitPenalty penalty = (BestFitPenalty)element;
- difference = handleBestFitPenalty(penalty, node, elementIdx);
- } else {
- difference = computeDifference(node, element, elementIdx);
- }
+ int difference = computeDifference(node, element, elementIdx);
if (!elementCanEndLine(element, endLine, difference)) {
log.trace("Skipping legal break");
break;
@@ -976,33 +969,6 @@ public abstract class BreakingAlgorithm {
}
}
- private int handleBestFitPenalty(BestFitPenalty penalty, KnuthNode node,
- int elementIdx) {
- // Find the alternatives that can be fitted inside the remaining space
- for (int i = 0; i < penalty.getAlternatives().size(); ++i) {
- Alternative alt = penalty.getAlternatives().get(i);
- int difference = computeDifference(node, new KnuthPenalty(alt.getWidth(),
- 0, false, null, false), elementIdx);
- double r = computeAdjustmentRatio(node, difference);
- //if (r >= -1) {
- alt.setRemainingBPD(difference);
- alt.setEnabled(r >= -1);
- //altManager.addAlternative(alt);
- //}
- }
- Alternative bestAlt = penalty.getBestAlternative();
- if (bestAlt != null) {
- //penalty.setBestAlternative(bestAlt);
- // Add an empty KnuthBox to represent the chosen alternative
- par.add(elementIdx + 1, new KnuthBox(bestAlt.getWidth(), null, false));
- return bestAlt.getRemainingBPD();
- } else {
- // No "good" alternative was found
- return computeDifference(node, new KnuthPenalty(0,
- 0, false, null, false), elementIdx);
- }
- }
-
/**
* Check if the given {@link KnuthElement} can end the line with the given
* number.
diff --git a/src/java/org/apache/fop/layoutmgr/ElementListUtils.java b/src/java/org/apache/fop/layoutmgr/ElementListUtils.java
index 560747bcc..e6be4ca63 100644
--- a/src/java/org/apache/fop/layoutmgr/ElementListUtils.java
+++ b/src/java/org/apache/fop/layoutmgr/ElementListUtils.java
@@ -163,37 +163,6 @@ public final class ElementListUtils {
}
/**
- * Calculates the full content length of the given element list. Warning: It doesn't take any
- * stretch and shrink possibilities into account.
- * @param elems the element list
- * @return the content length
- */
- public static int calcFullContentLength(List elems) {
- ListIterator iter = elems.listIterator(0);
- int count = elems.size();
- int len = 0;
- while (iter.hasNext()) {
- ListElement el = (ListElement)iter.next();
- if (el.isBox()) {
- len += ((KnuthElement)el).getWidth();
- } else if (el.isGlue()) {
- len += ((KnuthElement)el).getWidth();
- } else if (el.isUnresolvedElement() && !(el instanceof BreakElement)) {
- // Handle properties space-before and space-after
- UnresolvedListElementWithLength uresolvedEl = (UnresolvedListElementWithLength)el;
- if (uresolvedEl.isLast() || uresolvedEl.isFirst()) {
- len += uresolvedEl.getLength().getOpt();
- }
- }
- count--;
- if (count == 0) {
- break;
- }
- }
- return len;
- }
-
- /**
* Calculates the content length of the given element list. Warning: It doesn't take any
* stretch and shrink possibilities into account.
* @param elems the element list
diff --git a/src/java/org/apache/fop/layoutmgr/LayoutManagerMapping.java b/src/java/org/apache/fop/layoutmgr/LayoutManagerMapping.java
index 2d08e674c..cf8b74cc0 100644
--- a/src/java/org/apache/fop/layoutmgr/LayoutManagerMapping.java
+++ b/src/java/org/apache/fop/layoutmgr/LayoutManagerMapping.java
@@ -34,8 +34,6 @@ import org.apache.fop.fo.FONode;
import org.apache.fop.fo.FONode.FONodeIterator;
import org.apache.fop.fo.FOText;
import org.apache.fop.fo.FObjMixed;
-import org.apache.fop.fo.extensions.AlternativeBlock;
-import org.apache.fop.fo.extensions.BestFit;
import org.apache.fop.fo.extensions.ExternalDocument;
import org.apache.fop.fo.flow.BasicLink;
import org.apache.fop.fo.flow.BidiOverride;
@@ -51,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;
@@ -98,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() {
@@ -144,8 +144,8 @@ public class LayoutManagerMapping implements LayoutManagerMaker {
registerMaker(TableHeader.class, new Maker());
registerMaker(Wrapper.class, new WrapperLayoutManagerMaker());
registerMaker(Title.class, new InlineLayoutManagerMaker());
- registerMaker(BestFit.class, new BestFitLayoutManagerMaker());
- registerMaker(AlternativeBlock.class, new AlternativeBlockLayoutManagerMaker());
+ registerMaker(MultiCase.class, new MultiCaseLayoutManagerMaker());
+ registerMaker(MultiSwitch.class, new MultiSwitchLayoutManagerMaker());
}
/**
@@ -449,19 +449,30 @@ public class LayoutManagerMapping implements LayoutManagerMaker {
}
}
- /** a layout manager maker */
- public class BestFitLayoutManagerMaker extends Maker {
- /** {@inheritDoc} */
+ public class MultiSwitchLayoutManagerMaker extends Maker {
+
+ @Override
public void make(FONode node, List lms) {
- lms.add(new BestFitLayoutManager((BestFit) node));
+ MultiSwitch multiSwitch = (MultiSwitch) node;
+ MultiSwitchLayoutManager mslm = new MultiSwitchLayoutManager(multiSwitch);
+ FONode multiCase = multiSwitch.getCurrentlyVisibleNode();
+ if (multiCase != null) {
+ FONodeIterator childIter = multiCase.getChildNodes();
+ while (childIter.hasNext()) {
+ FONode child = (FONode) childIter.next();
+ makeLayoutManagers(child, lms);
+ }
+ } else {
+ lms.add(mslm);
+ }
}
}
- /** a layout manager maker */
- public class AlternativeBlockLayoutManagerMaker extends Maker {
- /** {@inheritDoc} */
+ public class MultiCaseLayoutManagerMaker extends Maker {
+
+ @Override
public void make(FONode node, List lms) {
- lms.add(new AlternativeBlockLayoutManager((AlternativeBlock) node));
+ 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..bc3e61b8e
--- /dev/null
+++ b/src/java/org/apache/fop/layoutmgr/MultiCaseLayoutManager.java
@@ -0,0 +1,89 @@
+/*
+ * 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.area.Block;
+import org.apache.fop.area.LineArea;
+import org.apache.fop.fo.FObj;
+
+public class MultiCaseLayoutManager extends BlockStackingLayoutManager {
+
+ private Block curBlockArea;
+
+ public MultiCaseLayoutManager(FObj node) {
+ super(node);
+ }
+
+ @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) {
+ if (curBlockArea == null) {
+ curBlockArea = new Block();
+ curBlockArea.setIPD(super.getContentAreaIPD());
+ // Set up dimensions
+ // Must get dimensions from parent area
+ /*Area parentArea = */parentLayoutManager.getParentArea(curBlockArea);
+ setCurrentArea(curBlockArea);
+ }
+ return curBlockArea;
+ }
+
+ @Override
+ public void addChildArea(Area childArea) {
+ if (curBlockArea != null) {
+ if (childArea instanceof LineArea) {
+ curBlockArea.addLineArea((LineArea) childArea);
+ } else {
+ curBlockArea.addBlock((Block) childArea);
+ }
+ }
+ }
+
+ /**
+ * Force current area to be added to parent area.
+ */
+ @Override
+ protected void flush() {
+ if (getCurrentArea() != null) {
+ super.flush();
+ }
+ }
+
+ /** {@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..6f628d1f5
--- /dev/null
+++ b/src/java/org/apache/fop/layoutmgr/MultiSwitchLayoutManager.java
@@ -0,0 +1,157 @@
+/*
+ * 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.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.fop.area.Area;
+import org.apache.fop.area.Block;
+import org.apache.fop.area.LineArea;
+import org.apache.fop.fo.FONode;
+import org.apache.fop.fo.FONode.FONodeIterator;
+import org.apache.fop.fo.FObj;
+import org.apache.fop.fo.flow.MultiSwitch;
+import org.apache.fop.layoutmgr.Alternative.FittingStrategy;
+
+public class MultiSwitchLayoutManager extends BlockStackingLayoutManager {
+
+ private Block curBlockArea;
+
+ public MultiSwitchLayoutManager(FObj node) {
+ super(node);
+ }
+
+ @Override
+ public List<ListElement> getNextKnuthElements(LayoutContext context, int alignment) {
+
+ referenceIPD = context.getRefIPD();
+ List<List<ListElement>> childrenLists = new LinkedList<List<ListElement>>();
+ LayoutManager childLM;
+ while ((childLM = getChildLM()) != null) {
+ if (!childLM.isFinished()) {
+ LayoutContext childLC = makeChildLayoutContext(context);
+ List childElements = childLM.getNextKnuthElements(childLC, alignment);
+ if (childElements != null) {
+ List<ListElement> newList = new LinkedList<ListElement>();
+ wrapPositionElements(childElements, newList);
+ childrenLists.add(newList);
+ }
+ }
+ }
+ setFinished(true);
+ return BestFitLayoutUtils.getKnuthList(this, childrenLists, FittingStrategy.FIRST_FIT);
+ }
+
+ @Override
+ protected List<LayoutManager> createChildLMs(int size) {
+ MultiSwitch multiSwitch = (MultiSwitch) getFObj();
+ if (multiSwitch.getCurrentlyVisibleNode() != null) {
+ List<LayoutManager> newLMs = new ArrayList<LayoutManager>(size);
+ if (childLMs.size() == 0) {
+ createMultiCaseLM(multiSwitch.getCurrentlyVisibleNode());
+ return new ArrayList<LayoutManager>(size);
+ }
+ return newLMs;
+ } else {
+ return super.createChildLMs(size);
+ }
+ }
+
+ private void createMultiCaseLM(FONode multiCase) {
+ FONodeIterator childIter = multiCase.getChildNodes();
+ while (childIter.hasNext()) {
+ List<LayoutManager> newLMs = new ArrayList<LayoutManager>(1);
+ getPSLM().getLayoutManagerMaker()
+ .makeLayoutManagers((childIter.nextNode()), newLMs);
+ if (!newLMs.isEmpty()) {
+ this.getParent().addChildLM(newLMs.get(0));
+ }
+ }
+ }
+
+ @Override
+ public Keep getKeepTogether() {
+ return Keep.KEEP_AUTO;
+ }
+
+ @Override
+ public Keep getKeepWithNext() {
+ return Keep.KEEP_AUTO;
+ }
+
+ @Override
+ public Keep getKeepWithPrevious() {
+ return Keep.KEEP_AUTO;
+ }
+
+ @Override
+ public int getContentAreaIPD() {
+ if (curBlockArea != null) {
+ return curBlockArea.getIPD();
+ }
+ return super.getContentAreaIPD();
+ }
+
+ @Override
+ public Area getParentArea(Area childArea) {
+ if (curBlockArea == null) {
+ curBlockArea = new Block();
+ curBlockArea.setIPD(super.getContentAreaIPD());
+ setCurrentArea(curBlockArea);
+ // Set up dimensions
+ // Must get dimensions from parent area
+ /*Area parentArea = */parentLayoutManager.getParentArea(curBlockArea);
+ }
+ return curBlockArea;
+ }
+
+ @Override
+ public void addChildArea(Area childArea) {
+ if (curBlockArea != null) {
+ if (childArea instanceof LineArea) {
+ curBlockArea.addLineArea((LineArea) childArea);
+ } else {
+ curBlockArea.addBlock((Block) childArea);
+ }
+ }
+ }
+
+ /**
+ * Force current area to be added to parent area.
+ */
+ @Override
+ protected void flush() {
+ if (getCurrentArea() != null) {
+ parentLayoutManager.addChildArea(getCurrentArea());
+ }
+ }
+
+ @Override
+ public void addAreas(PositionIterator posIter, LayoutContext context) {
+
+ List<Position> positionList = BestFitLayoutUtils.getPositionList(this, posIter);
+ 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 7183de45a..d441b37bd 100644
--- a/src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java
+++ b/src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java
@@ -149,6 +149,9 @@ class PageBreakingAlgorithm extends BreakingAlgorithm {
/** Index of the last inserted element of the last inserted footnote. */
public int footnoteElementIndex;
+ public boolean bestFitNode = false;
+ public boolean skipNode = false;
+
public KnuthPageNode(int position,
int line, int fitness,
int totalWidth, int totalStretch, int totalShrink,
@@ -162,6 +165,12 @@ class PageBreakingAlgorithm extends BreakingAlgorithm {
this.totalFootnotes = totalFootnotes;
this.footnoteListIndex = footnoteListIndex;
this.footnoteElementIndex = footnoteElementIndex;
+ if (getElement(position) instanceof BestFitPenalty) {
+ if (log.isDebugEnabled()) {
+ log.debug("Creating a KnuthPageNode for a BestFitPenalty.");
+ }
+ bestFitNode = true;
+ }
}
}
@@ -394,6 +403,25 @@ class PageBreakingAlgorithm extends BreakingAlgorithm {
/** {@inheritDoc} */
@Override
protected int restartFrom(KnuthNode restartingNode, int currentIndex) {
+ if (getLastTooLong() != null) {
+ KnuthPageNode lastTooLong = (KnuthPageNode) getLastTooLong();
+ if (lastTooLong.skipNode) {
+ if (log.isDebugEnabled()) {
+ log.debug("Alternative does not fit in the current page. "
+ + "Switching to the next one in the list");
+ }
+ int penaltyIndex = currentIndex;
+ // In case the paragraph has changed...
+ if (lastTooLong.previous.previous == null) {
+ if (par.get(0) == KnuthPenalty.DUMMY_ZERO_PENALTY) {
+ ++penaltyIndex;
+ }
+ }
+ BestFitPenalty bestFitPenalty = (BestFitPenalty) getElement(penaltyIndex);
+ bestFitPenalty.considerNextAlternative();
+ restartingNode = restartingNode.previous;
+ }
+ }
int returnValue = super.restartFrom(restartingNode, currentIndex);
newFootnotes = false;
if (footnotesPending) {
@@ -491,6 +519,22 @@ class PageBreakingAlgorithm extends BreakingAlgorithm {
}
/** {@inheritDoc} */
+ protected void forceNode(KnuthNode node, int line, int elementIdx,
+ int difference, double r, double demerits, int fitnessClass,
+ int availableShrink, int availableStretch) {
+
+ super.forceNode(node, line, elementIdx, difference, r, demerits,
+ fitnessClass, availableShrink, availableStretch);
+
+ KnuthPageNode lastTooLong = (KnuthPageNode) getLastTooLong();
+ if (lastTooLong != null) {
+ if (lastTooLong.bestFitNode) {
+ lastTooLong.skipNode = true;
+ }
+ }
+ }
+
+ /** {@inheritDoc} */
@Override
protected int computeDifference(KnuthNode activeNode, KnuthElement element,
int elementIndex) {