private String layer;
// End of property values
+ private boolean forceKeepTogether;
+
/**
* Create a new formatting object.
*
return (super.toString() + "[@id=" + this.id + "]");
}
+ public boolean isForceKeepTogether() {
+ return forceKeepTogether;
+ }
+
+ public void setForceKeepTogether(boolean b) {
+ forceKeepTogether = b;
+ }
+
/** Basic {@link FONode.FONodeIterator} implementation */
public static class FObjIterator implements FONodeIterator {
package org.apache.fop.layoutmgr;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-import org.apache.fop.events.EventBroadcaster;
import org.apache.fop.fo.Constants;
import org.apache.fop.layoutmgr.BreakingAlgorithm.KnuthNode;
import org.apache.fop.traits.MinOptMax;
/** logging instance */
protected static final Log log = LogFactory.getLog(AbstractBreaker.class);
- private LayoutManager originalRestartAtLM;
- private Position positionAtBreak;
- private List firstElementsForRestart;
+ protected LayoutManager originalRestartAtLM;
+ protected Position positionAtBreak;
+ protected List firstElementsForRestart;
protected PageSequenceLayoutManager pslm;
/**
}
firstElementsForRestart = null;
- LayoutManager restartAtLM = getRestartAtLM(alg, ipdChangesOnNextPage, onLastPageAndIPDChanges,
- visitedBefore, blockList, 1);
+ RestartAtLM restartAtLMClass = new RestartAtLM();
+ LayoutManager restartAtLM = restartAtLMClass.getRestartAtLM(this, alg, ipdChangesOnNextPage,
+ onLastPageAndIPDChanges, visitedBefore, blockList, 1);
+ if (restartAtLMClass.invalidPosition) {
+ return false;
+ }
if (restartAtLM == null || restartAtLM.getChildLMs().isEmpty()) {
firstElementsForRestart = null;
- LayoutManager restartAtLM2 = getRestartAtLM(alg, ipdChangesOnNextPage, onLastPageAndIPDChanges,
- visitedBefore, blockList, 0);
+ LayoutManager restartAtLM2 = new RestartAtLM().getRestartAtLM(this, alg, ipdChangesOnNextPage,
+ onLastPageAndIPDChanges, visitedBefore, blockList, 0);
if (restartAtLM2 != null) {
restartAtLM = restartAtLM2;
}
return true;
}
- private LayoutManager getRestartAtLM(PageBreakingAlgorithm alg, boolean ipdChangesOnNextPage,
- boolean onLastPageAndIPDChanges, boolean visitedBefore,
- BlockSequence blockList, int start) {
- KnuthNode optimalBreak = ipdChangesOnNextPage ? alg.getBestNodeBeforeIPDChange() : alg
- .getBestNodeForLastPage();
- if (onLastPageAndIPDChanges && visitedBefore && this.originalRestartAtLM == null) {
- optimalBreak = null;
- }
- int positionIndex = findPositionIndex(optimalBreak, alg, start);
- if (ipdChangesOnNextPage || (positionAtBreak != null && positionAtBreak.getIndex() > -1)) {
- firstElementsForRestart = Collections.EMPTY_LIST;
- if (ipdChangesOnNextPage) {
- if (containsNonRestartableLM(positionAtBreak)) {
- if (alg.getIPDdifference() > 0) {
- EventBroadcaster eventBroadcaster = getCurrentChildLM().getFObj()
- .getUserAgent().getEventBroadcaster();
- BlockLevelEventProducer eventProducer = BlockLevelEventProducer.Provider
- .get(eventBroadcaster);
- eventProducer.nonRestartableContentFlowingToNarrowerPage(this);
- }
- firstElementsForRestart = new LinkedList();
- boolean boxFound = false;
- Iterator iter = blockList.listIterator(positionIndex + 1);
- Position position = null;
- while (iter.hasNext()
- && (position == null || containsNonRestartableLM(position))) {
- positionIndex++;
- KnuthElement element = (KnuthElement) iter.next();
- position = element.getPosition();
- if (element.isBox()) {
- boxFound = true;
- firstElementsForRestart.add(element);
- } else if (boxFound) {
- firstElementsForRestart.add(element);
- }
- }
- if (position instanceof SpaceResolver.SpaceHandlingBreakPosition) {
- /* Retrieve the original position wrapped into this space position */
- positionAtBreak = position.getPosition();
- } else {
- positionAtBreak = null;
- }
- }
- }
- }
- LayoutManager restartAtLM = null;
- if (ipdChangesOnNextPage || !(positionAtBreak != null && positionAtBreak.getIndex() > -1)) {
- if (positionAtBreak != null && positionAtBreak.getIndex() == -1) {
- Position position;
- Iterator iter = blockList.listIterator(positionIndex + 1);
- do {
- KnuthElement nextElement = (KnuthElement) iter.next();
- position = nextElement.getPosition();
- } while (position == null
- || position instanceof SpaceResolver.SpaceHandlingPosition
- || position instanceof SpaceResolver.SpaceHandlingBreakPosition
- && position.getPosition().getIndex() == -1);
- LayoutManager surroundingLM = positionAtBreak.getLM();
- while (position.getLM() != surroundingLM) {
- position = position.getPosition();
- }
- restartAtLM = position.getPosition().getLM();
- }
- if (onLastPageAndIPDChanges && restartAtLM != null) {
- if (originalRestartAtLM == null) {
- originalRestartAtLM = restartAtLM;
- } else {
- restartAtLM = originalRestartAtLM;
- }
- firstElementsForRestart = Collections.EMPTY_LIST;
- }
- }
- if (onLastPageAndIPDChanges && !visitedBefore && positionAtBreak.getPosition() != null) {
- restartAtLM = positionAtBreak.getPosition().getLM();
- }
- return restartAtLM;
- }
-
- private int findPositionIndex(KnuthNode optimalBreak, PageBreakingAlgorithm alg, int start) {
- int positionIndex = (optimalBreak != null) ? optimalBreak.position : start;
- for (int i = positionIndex; i < alg.par.size(); i++) {
- KnuthElement elementAtBreak = alg.getElement(i);
- if (elementAtBreak.getPosition() == null) {
- elementAtBreak = alg.getElement(0);
- }
- positionAtBreak = elementAtBreak.getPosition();
- /* Retrieve the original position wrapped into this space position */
- positionAtBreak = positionAtBreak.getPosition();
- if (positionAtBreak != null) {
- return i;
- }
- }
- return positionIndex;
- }
-
/**
* Returns {@code true} if the given position or one of its descendants
* corresponds to a non-restartable LM.
* @param position a position
* @return {@code true} if there is a non-restartable LM in the hierarchy
*/
- private boolean containsNonRestartableLM(Position position) {
+ protected boolean containsNonRestartableLM(Position position) {
LayoutManager lm = position.getLM();
if (lm != null && !lm.isRestartable()) {
return true;
public Keep getKeepTogether() {
Keep keep = Keep.getKeep(getKeepTogetherProperty());
keep = keep.compare(getParentKeepTogether());
+ if (getFObj().isForceKeepTogether()) {
+ keep = Keep.KEEP_ALWAYS;
+ }
return keep;
}
--- /dev/null
+/*
+ * 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.Collections;
+import java.util.Iterator;
+import java.util.LinkedList;
+
+import org.apache.fop.events.EventBroadcaster;
+
+/**
+ * Class to find the restart layoutmanager for changing IPD
+ */
+class RestartAtLM {
+ protected boolean invalidPosition;
+
+ protected LayoutManager getRestartAtLM(AbstractBreaker breaker, PageBreakingAlgorithm alg,
+ boolean ipdChangesOnNextPage, boolean onLastPageAndIPDChanges,
+ boolean visitedBefore, AbstractBreaker.BlockSequence blockList, int start) {
+ BreakingAlgorithm.KnuthNode optimalBreak = ipdChangesOnNextPage ? alg.getBestNodeBeforeIPDChange() : alg
+ .getBestNodeForLastPage();
+ if (onLastPageAndIPDChanges && visitedBefore && breaker.originalRestartAtLM == null) {
+ optimalBreak = null;
+ }
+ int positionIndex = findPositionIndex(breaker, optimalBreak, alg, start);
+ if (ipdChangesOnNextPage || (breaker.positionAtBreak != null && breaker.positionAtBreak.getIndex() > -1)) {
+ breaker.firstElementsForRestart = Collections.EMPTY_LIST;
+ if (ipdChangesOnNextPage) {
+ if (breaker.containsNonRestartableLM(breaker.positionAtBreak)) {
+ if (alg.getIPDdifference() > 0) {
+ EventBroadcaster eventBroadcaster = breaker.getCurrentChildLM().getFObj()
+ .getUserAgent().getEventBroadcaster();
+ BlockLevelEventProducer eventProducer = BlockLevelEventProducer.Provider
+ .get(eventBroadcaster);
+ eventProducer.nonRestartableContentFlowingToNarrowerPage(this);
+ }
+ breaker.firstElementsForRestart = new LinkedList();
+ boolean boxFound = false;
+ Iterator iter = blockList.listIterator(positionIndex + 1);
+ Position position = null;
+ while (iter.hasNext()
+ && (position == null || breaker.containsNonRestartableLM(position))) {
+ positionIndex++;
+ KnuthElement element = (KnuthElement) iter.next();
+ position = element.getPosition();
+ if (element.isBox()) {
+ boxFound = true;
+ breaker.firstElementsForRestart.add(element);
+ } else if (boxFound) {
+ breaker.firstElementsForRestart.add(element);
+ }
+ }
+ if (position instanceof SpaceResolver.SpaceHandlingBreakPosition) {
+ /* Retrieve the original position wrapped into this space position */
+ breaker.positionAtBreak = position.getPosition();
+ } else {
+ breaker.positionAtBreak = null;
+ }
+ }
+ }
+ }
+ LayoutManager restartAtLM = null;
+ if (ipdChangesOnNextPage || !(breaker.positionAtBreak != null && breaker.positionAtBreak.getIndex() > -1)) {
+ if (breaker.positionAtBreak != null && breaker.positionAtBreak.getIndex() == -1) {
+ Position position;
+ Iterator iter = blockList.listIterator(positionIndex + 1);
+ do {
+ KnuthElement nextElement = (KnuthElement) iter.next();
+ position = nextElement.getPosition();
+ } while (position == null
+ || position instanceof SpaceResolver.SpaceHandlingPosition
+ || position instanceof SpaceResolver.SpaceHandlingBreakPosition
+ && position.getPosition().getIndex() == -1);
+ LayoutManager surroundingLM = breaker.positionAtBreak.getLM();
+ while (position.getLM() != surroundingLM) {
+ position = position.getPosition();
+ }
+ if (position.getPosition() == null) {
+ position.getLM().getFObj().setForceKeepTogether(true);
+ invalidPosition = true;
+ return null;
+ }
+ restartAtLM = position.getPosition().getLM();
+ }
+ if (onLastPageAndIPDChanges && restartAtLM != null) {
+ if (breaker.originalRestartAtLM == null) {
+ breaker.originalRestartAtLM = restartAtLM;
+ } else {
+ restartAtLM = breaker.originalRestartAtLM;
+ }
+ breaker.firstElementsForRestart = Collections.EMPTY_LIST;
+ }
+ }
+ if (onLastPageAndIPDChanges && !visitedBefore && breaker.positionAtBreak.getPosition() != null) {
+ restartAtLM = breaker.positionAtBreak.getPosition().getLM();
+ }
+ return restartAtLM;
+ }
+
+ private int findPositionIndex(AbstractBreaker breaker, BreakingAlgorithm.KnuthNode optimalBreak,
+ PageBreakingAlgorithm alg, int start) {
+ int positionIndex = (optimalBreak != null) ? optimalBreak.position : start;
+ for (int i = positionIndex; i < alg.par.size(); i++) {
+ KnuthElement elementAtBreak = alg.getElement(i);
+ if (elementAtBreak.getPosition() == null) {
+ elementAtBreak = alg.getElement(0);
+ }
+ breaker.positionAtBreak = elementAtBreak.getPosition();
+ /* Retrieve the original position wrapped into this space position */
+ breaker.positionAtBreak = breaker.positionAtBreak.getPosition();
+ if (breaker.positionAtBreak != null) {
+ return i;
+ }
+ }
+ return positionIndex;
+ }
+}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<!-- $Id$ -->
+<testcase>
+ <info>
+ <p>
+ This test checks that the definition of a special page-master for the last page with a
+ different width that the previous "rest" page causes FOP to redo the line breaking layout.
+ </p>
+ </info>
+ <fo>
+<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:fox="http://xmlgraphics.apache.org/fop/extensions">
+ <fo:layout-master-set>
+ <fo:simple-page-master margin-bottom="8mm" master-name="PageFront" page-width="210mm" page-height="297mm" margin-right="20mm" margin-top="15mm" margin-left="20mm">
+ <fo:region-body margin-right="58mm" margin-top="35mm" margin-bottom="20mm" margin-left="0mm" region-name="PageBody"/>
+ </fo:simple-page-master>
+ <fo:simple-page-master margin-bottom="8mm" master-name="PageRest" page-width="210mm" page-height="297mm" margin-right="20mm" margin-top="15mm" margin-left="20mm">
+ <fo:region-body margin-bottom="0mm" margin-top="0mm" margin-right="0mm" margin-left="0mm" region-name="PageBody"/>
+ </fo:simple-page-master>
+ <fo:page-sequence-master master-name="LetterPages">
+ <fo:repeatable-page-master-alternatives>
+ <fo:conditional-page-master-reference page-position="first" master-reference="PageFront"/>
+ <fo:conditional-page-master-reference page-position="rest" master-reference="PageRest"/>
+ <fo:conditional-page-master-reference page-position="last" master-reference="PageRest"/>
+ </fo:repeatable-page-master-alternatives>
+ </fo:page-sequence-master>
+ </fo:layout-master-set>
+ <fo:page-sequence format="1" id="th_default_sequence1" initial-page-number="auto" force-page-count="auto" master-reference="LetterPages">
+ <fo:flow flow-name="PageBody">
+ <fo:block-container height="210mm">
+ <fo:block>test</fo:block>
+ </fo:block-container>
+ <fo:block font-size="9pt" line-height="11pt">
+ <fo:inline>Step 2 – Finance<fo:block/>
+ </fo:inline>
+ If there is any Hire Purchase (HP) / Finance agreement associated with this vehicle, please contact the finance company to provide your authorisation for Bank Box to liaise with them in order to obtain the early settlement figure.</fo:block>
+ </fo:flow>
+ </fo:page-sequence>
+</fo:root>
+</fo>
+ <checks>
+ <eval expected="test" xpath="//pageViewport[1]//lineArea[1]//text[1]/word[1]"/>
+ <eval expected="Step" xpath="//pageViewport[2]//lineArea[1]//text[1]/word[1]"/>
+ <eval expected="2" xpath="count(//pageViewport)"/>
+ </checks>
+</testcase>