aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/java/org/apache/fop/area/Footnote.java22
-rw-r--r--src/java/org/apache/fop/fo/flow/Footnote.java24
-rw-r--r--src/java/org/apache/fop/layoutmgr/AbstractBreaker.java22
-rw-r--r--src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java2
-rw-r--r--src/java/org/apache/fop/layoutmgr/BlockStackingLayoutManager.java4
-rw-r--r--src/java/org/apache/fop/layoutmgr/BreakingAlgorithm.java112
-rw-r--r--src/java/org/apache/fop/layoutmgr/FlowLayoutManager.java16
-rw-r--r--src/java/org/apache/fop/layoutmgr/InlineStackingLayoutManager.java1
-rw-r--r--src/java/org/apache/fop/layoutmgr/KnuthBlockBox.java31
-rw-r--r--src/java/org/apache/fop/layoutmgr/KnuthInlineBox.java22
-rw-r--r--src/java/org/apache/fop/layoutmgr/LayoutManagerMaker.java12
-rw-r--r--src/java/org/apache/fop/layoutmgr/LayoutManagerMapping.java13
-rw-r--r--src/java/org/apache/fop/layoutmgr/LineLayoutManager.java24
-rw-r--r--src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java462
-rw-r--r--src/java/org/apache/fop/layoutmgr/PageSequenceLayoutManager.java115
-rw-r--r--src/java/org/apache/fop/layoutmgr/StaticContentLayoutManager.java25
-rw-r--r--src/java/org/apache/fop/render/AbstractRenderer.java1
17 files changed, 812 insertions, 96 deletions
diff --git a/src/java/org/apache/fop/area/Footnote.java b/src/java/org/apache/fop/area/Footnote.java
index e1b0c453e..edcff170c 100644
--- a/src/java/org/apache/fop/area/Footnote.java
+++ b/src/java/org/apache/fop/area/Footnote.java
@@ -18,6 +18,9 @@
package org.apache.fop.area;
+import java.util.ArrayList;
+import java.util.List;
+
// may combine with before float into a conditional area
/**
@@ -53,5 +56,24 @@ public class Footnote extends BlockParent {
return separator;
}
+ public void setTop(int top) {
+ this.top = top;
+ }
+
+ public int getTop() {
+ return top;
+ }
+
+ public void addBlock(Block child) {
+ if (children == null) {
+ children = new ArrayList();
+ }
+ this.setBPD(this.getBPD() + child.getBPD());
+ children.add(child);
+ }
+
+ public List getChildAreas() {
+ return children;
+ }
}
diff --git a/src/java/org/apache/fop/fo/flow/Footnote.java b/src/java/org/apache/fop/fo/flow/Footnote.java
index 2d161c2c8..7c7b1a8f8 100644
--- a/src/java/org/apache/fop/fo/flow/Footnote.java
+++ b/src/java/org/apache/fop/fo/flow/Footnote.java
@@ -38,7 +38,7 @@ public class Footnote extends FObj {
private CommonAccessibility commonAccessibility;
// End of property values
- private Inline inlineFO = null;
+ private Inline footnoteCitation = null;
private FootnoteBody footnoteBody;
/**
@@ -69,7 +69,7 @@ public class Footnote extends FObj {
*/
protected void endOfNode() throws FOPException {
super.endOfNode();
- if (inlineFO == null || footnoteBody == null) {
+ if (footnoteCitation == null || footnoteBody == null) {
missingChildElementError("(inline,footnote-body)");
}
getFOEventHandler().endFootnote(this);
@@ -87,11 +87,11 @@ public class Footnote extends FObj {
protected void validateChildNode(Locator loc, String nsURI, String localName)
throws ValidationException {
if (nsURI == FO_URI && localName.equals("inline")) {
- if (inlineFO != null) {
+ if (footnoteCitation != null) {
tooManyNodesError(loc, "fo:inline");
}
} else if (nsURI == FO_URI && localName.equals("footnote-body")) {
- if (inlineFO == null) {
+ if (footnoteCitation == null) {
nodesOutOfOrderError(loc, "fo:inline", "fo:footnote-body");
} else if (footnoteBody != null) {
tooManyNodesError(loc, "fo:footnote-body");
@@ -106,7 +106,7 @@ public class Footnote extends FObj {
*/
public void addChildNode(FONode child) {
if (((FObj)child).getNameId() == FO_INLINE) {
- inlineFO = (Inline) child;
+ footnoteCitation = (Inline) child;
} else if (((FObj)child).getNameId() == FO_FOOTNOTE_BODY) {
footnoteBody = (FootnoteBody) child;
}
@@ -114,10 +114,18 @@ public class Footnote extends FObj {
/**
* Public accessor for inline FO
- * @return the Inline object stored as inline FO
+ * @return the Inline child
*/
- public Inline getInlineFO() {
- return inlineFO;
+ public Inline getFootnoteCitation() {
+ return footnoteCitation;
+ }
+
+ /**
+ * Public accessor for footnote-body FO
+ * @return the FootnoteBody child
+ */
+ public FootnoteBody getFootnoteBody() {
+ return footnoteBody;
}
/**
diff --git a/src/java/org/apache/fop/layoutmgr/AbstractBreaker.java b/src/java/org/apache/fop/layoutmgr/AbstractBreaker.java
index e170616e0..73dd8678c 100644
--- a/src/java/org/apache/fop/layoutmgr/AbstractBreaker.java
+++ b/src/java/org/apache/fop/layoutmgr/AbstractBreaker.java
@@ -35,16 +35,24 @@ public abstract class AbstractBreaker {
/** logging instance */
protected static Log log = LogFactory.getLog(AbstractBreaker.class);
- /*LF*/
public static class PageBreakPosition extends LeafPosition {
double bpdAdjust; // Percentage to adjust (stretch or shrink)
int difference;
+ int footnoteFirstListIndex;
+ int footnoteFirstElementIndex;
+ int footnoteLastListIndex;
+ int footnoteLastElementIndex;
PageBreakPosition(LayoutManager lm, int iBreakIndex,
+ int ffli, int ffei, int flli, int flei,
double bpdA, int diff) {
super(lm, iBreakIndex);
bpdAdjust = bpdA;
difference = diff;
+ footnoteFirstListIndex = ffli;
+ footnoteFirstElementIndex = ffei;
+ footnoteLastListIndex = flli;
+ footnoteLastElementIndex = flei;
}
}
@@ -83,13 +91,13 @@ public abstract class AbstractBreaker {
/** blockListIndex of the current BlockSequence in blockLists */
private int blockListIndex = 0;
-/*LF*/
- /*LF*/
+
private List blockLists = null;
private int alignment;
private int alignmentLast;
- /*LF*/
+
+ protected MinOptMax footnoteSeparatorLength = new MinOptMax(0);
protected abstract int getCurrentDisplayAlign();
protected abstract boolean hasMoreContent();
@@ -107,7 +115,7 @@ public abstract class AbstractBreaker {
//nop
}
- protected abstract void finishPart();
+ protected abstract void finishPart(PageBreakingAlgorithm alg, PageBreakPosition pbp);
protected LayoutContext createLayoutContext() {
return new LayoutContext(0);
@@ -157,7 +165,7 @@ public abstract class AbstractBreaker {
log.debug("PLM> start of algorithm (" + this.getClass().getName()
+ "), flow BPD =" + flowBPD);
PageBreakingAlgorithm alg = new PageBreakingAlgorithm(getTopLevelLM(),
- alignment, alignmentLast);
+ alignment, alignmentLast, footnoteSeparatorLength);
int iOptPageNumber;
BlockSequence effectiveList;
@@ -286,7 +294,7 @@ public abstract class AbstractBreaker {
startElementIndex, endElementIndex + 1), childLC);
}
- finishPart();
+ finishPart(alg, pbp);
startElementIndex = pbp.getLeafPos() + 1;
}
diff --git a/src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java b/src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java
index 1fda2cfc4..76ed74224 100644
--- a/src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java
@@ -521,7 +521,7 @@ public class BlockContainerLayoutManager extends BlockStackingLayoutManager {
this.deferredEffectiveList = effectiveList;
}
- protected void finishPart() {
+ protected void finishPart(PageBreakingAlgorithm alg, PageBreakPosition pbp) {
//nop for bclm
}
diff --git a/src/java/org/apache/fop/layoutmgr/BlockStackingLayoutManager.java b/src/java/org/apache/fop/layoutmgr/BlockStackingLayoutManager.java
index 05abe663f..82faa794b 100644
--- a/src/java/org/apache/fop/layoutmgr/BlockStackingLayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/BlockStackingLayoutManager.java
@@ -230,8 +230,8 @@ public abstract class BlockStackingLayoutManager extends AbstractLayoutManager
childLC.setRefIPD(ipd);
} else {
// curLM is a ?
- childLC.setStackLimit(MinOptMax.subtract(context
- .getStackLimit(), stackSize));
+ //childLC.setStackLimit(MinOptMax.subtract(context
+ // .getStackLimit(), stackSize));
childLC.setRefIPD(referenceIPD);
}
diff --git a/src/java/org/apache/fop/layoutmgr/BreakingAlgorithm.java b/src/java/org/apache/fop/layoutmgr/BreakingAlgorithm.java
index bd947febc..0aa581b77 100644
--- a/src/java/org/apache/fop/layoutmgr/BreakingAlgorithm.java
+++ b/src/java/org/apache/fop/layoutmgr/BreakingAlgorithm.java
@@ -23,6 +23,9 @@ import org.apache.commons.logging.LogFactory;
import org.apache.fop.traits.MinOptMax;
+import java.util.LinkedList;
+import java.util.ListIterator;
+
/**
* The set of nodes is sorted into lines indexed into activeLines.
* The nodes in each line are linked together in a single linked list by the
@@ -43,11 +46,9 @@ public abstract class BreakingAlgorithm {
// penalty value for flagged penalties
private int flaggedPenalty = 50;
// demerit for consecutive lines ending at flagged penalties
- private int repeatedFlaggedDemerit = 50;
+ protected int repeatedFlaggedDemerit = 50;
// demerit for consecutive lines belonging to incompatible fitness classes
- private int incompatibleFitnessDemerit = 50;
- // suggested modification to the "optimum" number of lines
- private int looseness = 0;
+ protected int incompatibleFitnessDemerit = 50;
/**
* The threshold for considering breaks to be acceptable.
@@ -62,7 +63,7 @@ public abstract class BreakingAlgorithm {
/**
* The width of a line.
*/
- private int lineWidth = 0;
+ protected int lineWidth = 0;
private boolean force = false;
protected KnuthNode lastDeactivatedNode = null;
@@ -77,7 +78,7 @@ public abstract class BreakingAlgorithm {
/**
* The set of active nodes.
*/
- private KnuthNode[] activeLines;
+ protected KnuthNode[] activeLines;
/**
* The number of active nodes.
@@ -97,22 +98,22 @@ public abstract class BreakingAlgorithm {
/**
* The total width of all elements handled so far.
*/
- private int totalWidth;
+ protected int totalWidth;
/**
* The total stretch of all elements handled so far.
*/
- private int totalStretch = 0;
+ protected int totalStretch = 0;
/**
* The total shrink of all elements handled so far.
*/
- private int totalShrink = 0;
+ protected int totalShrink = 0;
- private BestRecords best;
+ protected BestRecords best;
private KnuthNode[] positions;
- private static final int INFINITE_RATIO = 1000;
+ protected static final int INFINITE_RATIO = 1000;
protected static Log log = LogFactory.getLog(KnuthParagraph.class);
@@ -126,7 +127,7 @@ public abstract class BreakingAlgorithm {
// this class represent a feasible breaking point
- public class KnuthNode {
+ protected class KnuthNode {
// index of the breakpoint represented by this node
public int position;
@@ -198,7 +199,7 @@ public abstract class BreakingAlgorithm {
// this class stores information about how the nodes
// which could start a line
// ending at the current element
- private class BestRecords {
+ protected class BestRecords {
private static final double INFINITE_DEMERITS = Double.POSITIVE_INFINITY;
//private static final double INFINITE_DEMERITS = 1E11;
@@ -215,7 +216,8 @@ public abstract class BreakingAlgorithm {
}
public void addRecord(double demerits, KnuthNode node, double adjust,
- int availableShrink, int availableStretch, int difference, int fitness) {
+ int availableShrink, int availableStretch,
+ int difference, int fitness) {
if (demerits > bestDemerits[fitness]) {
log.error("New demerits value greter than the old one");
}
@@ -274,11 +276,7 @@ public abstract class BreakingAlgorithm {
public void reset() {
for (int i = 0; i < 4; i ++) {
bestDemerits[i] = INFINITE_DEMERITS;
- bestNode[i] = null;
- bestAdjust[i] = 0.0;
- bestDifference[i] = 0;
- bestAvailableShrink[i] = 0;
- bestAvailableStretch[i] = 0;
+ // there is no need to reset the other arrays
}
bestIndex = -1;
}
@@ -299,9 +297,7 @@ public abstract class BreakingAlgorithm {
this.threshold = threshold;
this.force = force;
this.lineWidth = lineWidth;
- this.totalWidth = 0;
- this.totalStretch = 0;
- this.totalShrink = 0;
+ initialize();
activeLines = new KnuthNode[20];
@@ -324,7 +320,7 @@ public abstract class BreakingAlgorithm {
// create an active node representing the starting point
activeLines = new KnuthNode[20];
- addNode(0, new KnuthNode(firstBoxIndex, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, null));
+ addNode(0, createNode(firstBoxIndex, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, null));
if (log.isTraceEnabled()) {
log.trace("Looping over " + par.size() + " box objects");
@@ -339,6 +335,7 @@ public abstract class BreakingAlgorithm {
// a KnuthBox object is not a legal line break
totalWidth += thisElement.getW();
previousIsBox = true;
+ handleBox((KnuthBox) thisElement);
} else if (thisElement.isGlue()) {
// a KnuthGlue object is a legal line break
// only if the previous object is a KnuthBox
@@ -372,15 +369,8 @@ public abstract class BreakingAlgorithm {
}
log.debug("Restarting at node " + lastForced);
- lastForced.totalDemerits = 0;
- addNode(lastForced.line, lastForced);
+ restartFrom(lastForced, i);
i = lastForced.position;
- startLine = lastForced.line;
- endLine = startLine + 1;
- totalWidth = lastForced.totalWidth;
- totalStretch = lastForced.totalStretch;
- totalShrink = lastForced.totalShrink;
- lastTooShort = lastTooLong = null;
}
}
if (log.isTraceEnabled()) {
@@ -404,6 +394,44 @@ public abstract class BreakingAlgorithm {
return line;
}
+ protected void initialize() {
+ this.totalWidth = 0;
+ this.totalStretch = 0;
+ this.totalShrink = 0;
+ }
+
+ protected KnuthNode createNode(int position, int line, int fitness,
+ int totalWidth, int totalStretch, int totalShrink,
+ double adjustRatio, int availableShrink, int availableStretch, int difference,
+ double totalDemerits, KnuthNode previous) {
+ return new KnuthNode(position, line, fitness,
+ totalWidth, totalStretch, totalShrink,
+ adjustRatio, availableShrink, availableStretch,
+ difference, totalDemerits, previous);
+ }
+
+ protected KnuthNode createNode(int position, int line, int fitness,
+ int totalWidth, int totalStretch, int totalShrink) {
+ return new KnuthNode(position, line, fitness,
+ totalWidth, totalStretch, totalShrink,
+ best.getAdjust(fitness), best.getAvailableShrink(fitness), best.getAvailableStretch(fitness),
+ best.getDifference(fitness), best.getDemerits(fitness), best.getNode(fitness));
+ }
+
+ protected void handleBox(KnuthBox box) {
+ }
+
+ protected void restartFrom(KnuthNode restartingNode, int currentIndex) {
+ restartingNode.totalDemerits = 0;
+ addNode(restartingNode.line, restartingNode);
+ startLine = restartingNode.line;
+ endLine = startLine + 1;
+ totalWidth = restartingNode.totalWidth;
+ totalStretch = restartingNode.totalStretch;
+ totalShrink = restartingNode.totalShrink;
+ lastTooShort = lastTooLong = null;
+ }
+
private void considerLegalBreak(KnuthElement element, int elementIdx) {
if (log.isTraceEnabled()) {
@@ -462,7 +490,7 @@ public abstract class BreakingAlgorithm {
double demerits = computeDemerits(node, element, fitnessClass, r);
if (r <= -1) {
if (lastTooLong == null || demerits < lastTooLong.totalDemerits) {
- lastTooLong = new KnuthNode(elementIdx, line + 1, fitnessClass,
+ lastTooLong = createNode(elementIdx, line + 1, fitnessClass,
totalWidth, totalStretch, totalShrink,
r, availableShrink, availableStretch,
difference, demerits, node);
@@ -472,7 +500,7 @@ public abstract class BreakingAlgorithm {
}
} else {
if (lastTooShort == null || demerits <= lastTooShort.totalDemerits) {
- lastTooShort = new KnuthNode(elementIdx, line + 1, fitnessClass,
+ lastTooShort = createNode(elementIdx, line + 1, fitnessClass,
totalWidth, totalStretch, totalShrink,
r, availableShrink, availableStretch,
difference, demerits, node);
@@ -518,14 +546,8 @@ public abstract class BreakingAlgorithm {
if (log.isTraceEnabled()) {
log.trace("\tInsert new break in list of " + activeNodeCount);
}
- KnuthNode newNode = new KnuthNode(elementIdx, line + 1, i,
- newWidth, newStretch, newShrink,
- best.getAdjust(i),
- best.getAvailableShrink(i),
- best.getAvailableStretch(i),
- best.getDifference(i),
- best.getDemerits(i),
- best.getNode(i));
+ KnuthNode newNode = createNode(elementIdx, line + 1, i,
+ newWidth, newStretch, newShrink);
addNode(line + 1, newNode);
}
}
@@ -540,7 +562,7 @@ public abstract class BreakingAlgorithm {
* @return The difference in width. Positive numbers mean extra space in the line,
* negative number that the line overflows.
*/
- private int computeDifference(KnuthNode activeNode, KnuthElement element) {
+ protected int computeDifference(KnuthNode activeNode, KnuthElement element) {
// compute the adjustment ratio
int actualWidth = totalWidth - activeNode.totalWidth;
if (element.isPenalty()) {
@@ -563,7 +585,7 @@ public abstract class BreakingAlgorithm {
* @param difference
* @return The ration.
*/
- private double computeAdjustmentRatio(KnuthNode activeNode, int difference) {
+ protected double computeAdjustmentRatio(KnuthNode activeNode, int difference) {
// compute the adjustment ratio
if (difference > 0) {
int maxAdjustment = totalStretch - activeNode.totalStretch;
@@ -603,7 +625,7 @@ public abstract class BreakingAlgorithm {
}
}
- private double computeDemerits(KnuthNode activeNode, KnuthElement element,
+ protected double computeDemerits(KnuthNode activeNode, KnuthElement element,
int fitnessClass, double r) {
double demerits = 0;
// compute demerits
@@ -639,7 +661,7 @@ public abstract class BreakingAlgorithm {
* @param idx index of the element.
* @return
*/
- private KnuthElement getElement(int idx) {
+ protected KnuthElement getElement(int idx) {
return (KnuthElement) par.get(idx);
}
diff --git a/src/java/org/apache/fop/layoutmgr/FlowLayoutManager.java b/src/java/org/apache/fop/layoutmgr/FlowLayoutManager.java
index 08b29e211..3c1f090cb 100644
--- a/src/java/org/apache/fop/layoutmgr/FlowLayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/FlowLayoutManager.java
@@ -52,7 +52,6 @@ public class FlowLayoutManager extends BlockStackingLayoutManager
*/
private int numSubsequentOverflows = 0;
-/*LF*/
private static class StackingIter extends PositionIterator {
StackingIter(Iterator parentIter) {
super(parentIter);
@@ -66,7 +65,6 @@ public class FlowLayoutManager extends BlockStackingLayoutManager
return ((Position) nextObj);
}
}
-/*LF*/
/**
* This is the top level layout manager.
@@ -223,15 +221,14 @@ public class FlowLayoutManager extends BlockStackingLayoutManager
returnList.add(new KnuthPenalty(0, 0, false, new Position(this), false));
}
}
-/*LF*/ if (returnedList.size() > 0) { // controllare!
+ if (returnedList.size() > 0) { // controllare!
returnList.addAll(returnedList);
if (((KnuthElement)returnedList.getLast()).isPenalty()
&& ((KnuthPenalty)returnedList.getLast()).getP() == -KnuthElement.INFINITE) {
// a descendant of this flow has break-after
-/*LF*/ //System.out.println("FLM - break after!!");
return returnList;
}
-/*LF*/ }
+ }
}
prevLM = curLM;
}
@@ -294,8 +291,6 @@ public class FlowLayoutManager extends BlockStackingLayoutManager
KnuthElement currElement = null;
int fromIndex = 0;
-/*LF*/ //System.out.println("");
-/*LF*/ //System.out.println("FLM.getChangedKnuthElements> prima dell'unwrap, oldList.size() = " + oldList.size() + " da 0 a " + (oldList.size() - 1));
// "unwrap" the Positions stored in the elements
KnuthElement oldElement;
while (oldListIterator.hasNext()) {
@@ -311,11 +306,9 @@ public class FlowLayoutManager extends BlockStackingLayoutManager
// reset the iterator
oldListIterator = oldList.listIterator();
-/*LF*/ //System.out.println("FLM.getChangedKnuthElements> dopo l'unwrap, oldList.size() = " + oldList.size() + " da 0 a " + (oldList.size() - 1));
while (oldListIterator.hasNext()) {
currElement = (KnuthElement) oldListIterator.next();
-/*LF*/ //System.out.println("elemento n. " + oldListIterator.previousIndex() + " nella oldList");
if (prevElement != null
&& prevElement.getLayoutManager() != currElement.getLayoutManager()) {
// prevElement is the last element generated by the same LM
@@ -323,7 +316,6 @@ public class FlowLayoutManager extends BlockStackingLayoutManager
prevElement.getLayoutManager();
BlockLevelLayoutManager currLM = (BlockLevelLayoutManager)
currElement.getLayoutManager();
-/*LF*/ //System.out.println("FLM.getChangedKnuthElements> chiamata da " + fromIndex + " a " + oldListIterator.previousIndex());
returnedList.addAll(prevLM.getChangedKnuthElements(oldList.subList(fromIndex, oldListIterator.previousIndex()),
/*flaggedPenalty,*/ alignment));
fromIndex = oldListIterator.previousIndex();
@@ -343,7 +335,6 @@ public class FlowLayoutManager extends BlockStackingLayoutManager
if (currElement != null) {
BlockLevelLayoutManager currLM = (BlockLevelLayoutManager)
currElement.getLayoutManager();
-/*LF*/ //System.out.println("FLM.getChangedKnuthElements> chiamata da " + fromIndex + " a " + oldList.size());
returnedList.addAll(currLM.getChangedKnuthElements(oldList.subList(fromIndex, oldList.size()),
/*flaggedPenalty,*/ alignment));
}
@@ -416,6 +407,7 @@ public class FlowLayoutManager extends BlockStackingLayoutManager
* @see org.apache.fop.layoutmgr.LayoutManager#addChildArea(Area)
*/
public void addChildArea(Area childArea) {
+ getParentArea(childArea);
addChildToArea(childArea,
this.currentAreas[childArea.getAreaClass()]);
}
@@ -438,7 +430,7 @@ public class FlowLayoutManager extends BlockStackingLayoutManager
"area class (" + aclass + ") requested.");
}
- this.currentAreas[parentArea.getAreaClass()] = parentArea;
+ this.currentAreas[aclass] = parentArea;
setCurrentArea(parentArea);
return parentArea;
}
diff --git a/src/java/org/apache/fop/layoutmgr/InlineStackingLayoutManager.java b/src/java/org/apache/fop/layoutmgr/InlineStackingLayoutManager.java
index 199314576..fbff4ff0f 100644
--- a/src/java/org/apache/fop/layoutmgr/InlineStackingLayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/InlineStackingLayoutManager.java
@@ -603,6 +603,7 @@ public class InlineStackingLayoutManager extends AbstractLayoutManager
returnedElement.getPosition()));
returnList.add(returnedElement);
}
+ setFinished(curLM.isFinished() && (getChildLM() == null));
return returnList;
} else {
// curLM returned null because it finished;
diff --git a/src/java/org/apache/fop/layoutmgr/KnuthBlockBox.java b/src/java/org/apache/fop/layoutmgr/KnuthBlockBox.java
index 896532ebb..671cfecab 100644
--- a/src/java/org/apache/fop/layoutmgr/KnuthBlockBox.java
+++ b/src/java/org/apache/fop/layoutmgr/KnuthBlockBox.java
@@ -20,15 +20,46 @@ package org.apache.fop.layoutmgr;
import org.apache.fop.traits.MinOptMax;
+import java.util.LinkedList;
+
public class KnuthBlockBox extends KnuthBox {
private MinOptMax ipdRange;
private int bpd;
+ private LinkedList footnoteList;
+ private LinkedList elementLists = null;
public KnuthBlockBox(int w, MinOptMax range, int bpdim, Position pos, boolean bAux) {
super(w, pos, bAux);
ipdRange = (MinOptMax) range.clone();
bpd = bpdim;
+ footnoteList = new LinkedList();
+ }
+
+ public KnuthBlockBox(int w, LinkedList list, Position pos, boolean bAux) {
+ super(w, pos, bAux);
+ ipdRange = new MinOptMax(0);
+ bpd = 0;
+ footnoteList = new LinkedList(list);
+ }
+
+ public LinkedList getFootnoteBodyLMs() {
+ return footnoteList;
+ }
+
+ public boolean hasAnchors() {
+ return (footnoteList.size() > 0);
+ }
+
+ public void addElementList(LinkedList list) {
+ if (elementLists == null) {
+ elementLists = new LinkedList();
+ }
+ elementLists.add(list);
+ }
+
+ public LinkedList getElementLists() {
+ return elementLists;
}
public MinOptMax getIPDRange() {
diff --git a/src/java/org/apache/fop/layoutmgr/KnuthInlineBox.java b/src/java/org/apache/fop/layoutmgr/KnuthInlineBox.java
index cca2bbbb5..ded7e6593 100644
--- a/src/java/org/apache/fop/layoutmgr/KnuthInlineBox.java
+++ b/src/java/org/apache/fop/layoutmgr/KnuthInlineBox.java
@@ -23,6 +23,7 @@ public class KnuthInlineBox extends KnuthBox {
private int lead;
private int total;
private int middle;
+ private FootnoteBodyLayoutManager footnoteBodyLM = null;
/**
* Create a new KnuthBox.
@@ -61,4 +62,25 @@ public class KnuthInlineBox extends KnuthBox {
public int getMiddle() {
return middle;
}
+
+ /**
+ * @param fblm the FootnoteBodyLM this box must hold a reference to
+ */
+ public void setFootnoteBodyLM(FootnoteBodyLayoutManager fblm) {
+ footnoteBodyLM = fblm;
+ }
+
+ /**
+ * @return the FootnoteBodyLM this box holds a reference to
+ */
+ public FootnoteBodyLayoutManager getFootnoteBodyLM() {
+ return footnoteBodyLM;
+ }
+
+ /**
+ * @return true if this box holds a reference to a FootnoteBodyLM
+ */
+ public boolean isAnchor() {
+ return (footnoteBodyLM != null);
+ }
} \ No newline at end of file
diff --git a/src/java/org/apache/fop/layoutmgr/LayoutManagerMaker.java b/src/java/org/apache/fop/layoutmgr/LayoutManagerMaker.java
index 38ddc1e57..bfd08599f 100644
--- a/src/java/org/apache/fop/layoutmgr/LayoutManagerMaker.java
+++ b/src/java/org/apache/fop/layoutmgr/LayoutManagerMaker.java
@@ -23,7 +23,7 @@ import org.apache.fop.fo.pagination.PageSequence;
import org.apache.fop.fo.pagination.SideRegion;
import org.apache.fop.fo.pagination.StaticContent;
import org.apache.fop.area.AreaTreeHandler;
-
+import org.apache.fop.area.Block;
/**
* The interface for all LayoutManager makers
@@ -68,5 +68,15 @@ public interface LayoutManagerMaker {
public StaticContentLayoutManager makeStaticContentLayoutManager(
PageSequenceLayoutManager pslm, StaticContent sc, SideRegion reg);
+ /**
+ * Make a StaticContentLayoutManager object for a footnote-separator.
+ * @param pslm the parent PageSequenceLayoutManager object
+ * @param sc the fo:static-content object this SCLM will process
+ * @param block the Block area this SCLM must add its areas to
+ * @return The created StaticContentLayoutManager object
+ */
+ public StaticContentLayoutManager makeStaticContentLayoutManager(
+ PageSequenceLayoutManager pslm, StaticContent sc, Block block);
+
}
diff --git a/src/java/org/apache/fop/layoutmgr/LayoutManagerMapping.java b/src/java/org/apache/fop/layoutmgr/LayoutManagerMapping.java
index d47cd059f..b3bb1c438 100644
--- a/src/java/org/apache/fop/layoutmgr/LayoutManagerMapping.java
+++ b/src/java/org/apache/fop/layoutmgr/LayoutManagerMapping.java
@@ -166,6 +166,14 @@ public class LayoutManagerMapping implements LayoutManagerMaker {
return new StaticContentLayoutManager(pslm, sc, reg);
}
+ /*
+ * @see org.apache.fop.layoutmgr.LayoutManagerMaker#makeStaticContentLayoutManager(org.apache.fop.layoutmgr.PageSequenceLayoutManager, org.apache.fop.fo.pagination.StaticContent, org.apache.fop.area.Block)
+ */
+ public StaticContentLayoutManager makeStaticContentLayoutManager(
+ PageSequenceLayoutManager pslm, StaticContent sc, org.apache.fop.area.Block block) {
+ return new StaticContentLayoutManager(pslm, sc, block);
+ }
+
public static class Maker {
public void make(FONode node, List lms) {
// no layout manager
@@ -230,10 +238,7 @@ public class LayoutManagerMapping implements LayoutManagerMaker {
public static class FootnodeLayoutManagerMaker extends Maker {
public void make(FONode node, List lms) {
- Inline citation = ((Footnote) node).getInlineFO();
- if (citation != null) {
- lms.add(new InlineLayoutManager(citation));
- }
+ lms.add(new FootnoteLayoutManager((Footnote) node));
}
}
diff --git a/src/java/org/apache/fop/layoutmgr/LineLayoutManager.java b/src/java/org/apache/fop/layoutmgr/LineLayoutManager.java
index 0f72ef124..83da8ba22 100644
--- a/src/java/org/apache/fop/layoutmgr/LineLayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/LineLayoutManager.java
@@ -620,6 +620,12 @@ public class LineLayoutManager extends InlineStackingLayoutManager
knuthPar.addAll(((InlineLevelLayoutManager)
prevBox.getLayoutManager())
.addALetterSpaceTo(oldList));
+ if (((KnuthInlineBox) prevBox).isAnchor()) {
+ // prevBox represents a footnote citation: copy footnote info
+ // from prevBox to the new box
+ KnuthInlineBox newBox = (KnuthInlineBox) knuthPar.getLast();
+ newBox.setFootnoteBodyLM(((KnuthInlineBox) prevBox).getFootnoteBodyLM());
+ }
}
// look at the last element
@@ -941,6 +947,7 @@ public class LineLayoutManager extends InlineStackingLayoutManager
/* "normal" vertical alignment: create a sequence whose boxes
represent effective lines, and contain LineBreakPositions */
Position returnPosition = new LeafPosition(this, p);
+ int startIndex = 0;
for (int i = 0;
i < lineLayouts.getChosenLineCount();
i++) {
@@ -951,8 +958,21 @@ public class LineLayoutManager extends InlineStackingLayoutManager
// null penalty allowing a page break between lines
returnList.add(new KnuthPenalty(0, 0, false, returnPosition, false));
}
- returnList.add(new KnuthBox(((LineBreakPosition) lineLayouts.getChosenPosition(i)).lineHeight,
- lineLayouts.getChosenPosition(i), false));
+ int endIndex = ((LineBreakPosition) lineLayouts.getChosenPosition(i)).getLeafPos();
+ // create a list of the FootnoteBodyLM handling footnotes
+ // whose citations are in this line
+ LinkedList footnoteList = new LinkedList();
+ ListIterator elementIterator = ((Paragraph) knuthParagraphs.get(p)).listIterator(startIndex);
+ while (elementIterator.nextIndex() <= endIndex) {
+ KnuthElement element = (KnuthElement) elementIterator.next();
+ if (element instanceof KnuthInlineBox
+ && ((KnuthInlineBox) element).isAnchor()) {
+ footnoteList.add(((KnuthInlineBox) element).getFootnoteBodyLM());
+ }
+ }
+ startIndex = endIndex + 1;
+ returnList.add(new KnuthBlockBox(((LineBreakPosition) lineLayouts.getChosenPosition(i)).lineHeight,
+ footnoteList, lineLayouts.getChosenPosition(i), false));
}
}
}
diff --git a/src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java b/src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java
index 6ca570d3b..c2df28b17 100644
--- a/src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java
+++ b/src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java
@@ -18,18 +18,458 @@
package org.apache.fop.layoutmgr;
+import java.util.ArrayList;
import java.util.LinkedList;
+import java.util.ListIterator;
import org.apache.fop.layoutmgr.AbstractBreaker.PageBreakPosition;
+import org.apache.fop.traits.MinOptMax;
+
class PageBreakingAlgorithm extends BreakingAlgorithm {
private LayoutManager topLevelLM;
private LinkedList pageBreaks = null;
+ private ArrayList footnotesList = null;
+ private ArrayList lengthList = null;
+ private int totalFootnotesLength = 0;
+ private int insertedFootnotesLength = 0;
+ private boolean bPendingFootnotes = false;
+ private int footnoteListIndex = 0;
+ private int footnoteElementIndex = -1;
+
+ // demerits for a page break that splits a footnote
+ private int splitFootnoteDemerits = 5000;
+ // demerits for a page break that defers a whole footnote to the following page
+ private int deferredFootnoteDemerits = 10000;
+ private MinOptMax footnoteSeparatorLength = new MinOptMax(0);
+
public PageBreakingAlgorithm(LayoutManager topLevelLM,
- int alignment, int alignmentLast) {
+ int alignment, int alignmentLast,
+ MinOptMax fnSeparatorLength) {
super(alignment, alignmentLast, true);
this.topLevelLM = topLevelLM;
+ best = new BestPageRecords();
+ footnoteSeparatorLength = (MinOptMax) fnSeparatorLength.clone();
+ // add some stretch, to avoid a restart for every page containing footnotes
+ if (footnoteSeparatorLength.min == footnoteSeparatorLength.max) {
+ footnoteSeparatorLength.max += 10000;
+ }
+ }
+
+ /**
+ * this class represent a feasible breaking point
+ * with extra information about footnotes
+ */
+ protected class KnuthPageNode extends KnuthNode {
+
+ // additional length due to footnotes
+ public int totalFootnotes;
+
+ // index of the last inserted footnote
+ public int footnoteListIndex;
+
+ // index of the last inserted element of the last inserted footnote
+ public int footnoteElementIndex;
+
+ public KnuthPageNode(int position, int line, int fitness,
+ int totalWidth, int totalStretch, int totalShrink,
+ int totalFootnotes, int footnoteListIndex, int footnoteElementIndex,
+ double adjustRatio, int availableShrink, int availableStretch,
+ int difference, double totalDemerits, KnuthNode previous) {
+ super(position, line, fitness,
+ totalWidth, totalStretch, totalShrink,
+ adjustRatio, availableShrink, availableStretch,
+ difference, totalDemerits, previous);
+ this.totalFootnotes = totalFootnotes;
+ this.footnoteListIndex = footnoteListIndex;
+ this.footnoteElementIndex = footnoteElementIndex;
+ }
+
+ }
+
+ /**
+ * this class stores information about how the nodes
+ * which could start a line ending at the current element
+ */
+ protected class BestPageRecords extends BestRecords {
+
+ private int bestFootnotesLength[] = new int[4];
+ private int bestFootnoteListIndex[] = new int[4];
+ private int bestFootnoteElementIndex[] = new int[4];
+
+ public void addRecord(double demerits, KnuthNode node, double adjust,
+ int availableShrink, int availableStretch,
+ int difference, int fitness) {
+ super.addRecord(demerits, node, adjust,
+ availableShrink, availableStretch,
+ difference, fitness);
+ bestFootnotesLength[fitness] = insertedFootnotesLength;
+ bestFootnoteListIndex[fitness] = footnoteListIndex;
+ bestFootnoteElementIndex[fitness] = footnoteElementIndex;
+ }
+
+ public int getFootnotesLength(int fitness) {
+ return bestFootnotesLength[fitness];
+ }
+
+ public int getFootnoteListIndex(int fitness) {
+ return bestFootnoteListIndex[fitness];
+ }
+
+ public int getFootnoteElementIndex(int fitness) {
+ return bestFootnoteElementIndex[fitness];
+ }
+ }
+
+ protected void initialize() {
+ super.initialize();
+ insertedFootnotesLength = 0;
+ footnoteListIndex = 0;
+ footnoteElementIndex = -1;
+ }
+
+ protected KnuthNode createNode(int position, int line, int fitness,
+ int totalWidth, int totalStretch, int totalShrink,
+ double adjustRatio, int availableShrink, int availableStretch,
+ int difference, double totalDemerits, KnuthNode previous) {
+ return new KnuthPageNode(position, line, fitness,
+ totalWidth, totalStretch, totalShrink,
+ insertedFootnotesLength, footnoteListIndex, footnoteElementIndex,
+ adjustRatio, availableShrink, availableStretch,
+ difference, totalDemerits, previous);
+ }
+
+ protected KnuthNode createNode(int position, int line, int fitness,
+ int totalWidth, int totalStretch, int totalShrink) {
+ return new KnuthPageNode(position, line, fitness,
+ totalWidth, totalStretch, totalShrink,
+ ((BestPageRecords) best).getFootnotesLength(fitness),
+ ((BestPageRecords) best).getFootnoteListIndex(fitness),
+ ((BestPageRecords) best).getFootnoteElementIndex(fitness),
+ best.getAdjust(fitness), best.getAvailableShrink(fitness), best.getAvailableStretch(fitness),
+ best.getDifference(fitness), best.getDemerits(fitness), best.getNode(fitness));
+ }
+
+ protected void handleBox(KnuthBox box) {
+ if (box instanceof KnuthBlockBox
+ && ((KnuthBlockBox) box).hasAnchors()) {
+ handleFootnotes(((KnuthBlockBox) box).getElementLists());
+ }
+ }
+
+ private void handleFootnotes(LinkedList elementLists) {
+ // initialization
+ if (!bPendingFootnotes) {
+ bPendingFootnotes = true;
+ footnotesList = new ArrayList();
+ lengthList = new ArrayList();
+ totalFootnotesLength = 0;
+ }
+
+ // compute the total length of the footnotes
+ ListIterator elementListsIterator = elementLists.listIterator();
+ while (elementListsIterator.hasNext()) {
+ LinkedList noteList = (LinkedList) elementListsIterator.next();
+ int noteLength = 0;
+ footnotesList.add(noteList);
+ ListIterator noteListIterator = noteList.listIterator();
+ while (noteListIterator.hasNext()) {
+ KnuthElement element = (KnuthElement) noteListIterator.next();
+ if (element.isBox() || element.isGlue()) {
+ noteLength += element.getW();
+ }
+ }
+ int prevLength = (lengthList.size() == 0 ? 0 : ((Integer) lengthList.get(lengthList.size() - 1)).intValue());
+ lengthList.add(new Integer(prevLength + noteLength));
+ totalFootnotesLength += noteLength;
+ }
+ }
+
+ protected void restartFrom(KnuthNode restartingNode, int currentIndex) {
+ super.restartFrom(restartingNode, currentIndex);
+ if (bPendingFootnotes) {
+ // remove from footnotesList the note lists that will be met
+ // after the restarting point
+ for (int j = currentIndex; j >= restartingNode.position; j--) {
+ KnuthElement resettedElement = getElement(j);
+ if (resettedElement instanceof KnuthBlockBox
+ && ((KnuthBlockBox) resettedElement).hasAnchors()) {
+ resetFootnotes(((KnuthBlockBox) resettedElement).getElementLists());
+ }
+ }
+ }
+ }
+
+ private void resetFootnotes(LinkedList elementLists) {
+ for (int i = 0; i < elementLists.size(); i++) {
+ LinkedList removedList = (LinkedList) footnotesList.remove(footnotesList.size() - 1);
+ lengthList.remove(lengthList.size() - 1);
+
+ // update totalFootnotesLength
+ if (lengthList.size() > 0) {
+ totalFootnotesLength = ((Integer) lengthList.get(lengthList.size() - 1)).intValue();
+ } else {
+ totalFootnotesLength = 0;
+ }
+ }
+ // update bPendingFootnotes;
+ if (footnotesList.size() == 0) {
+ bPendingFootnotes = false;
+ }
+ }
+
+ /**
+ * Return the difference between the line width and the width of the break that
+ * ends in 'element'.
+ * @param activeNode
+ * @param element
+ * @return The difference in width. Positive numbers mean extra space in the line,
+ * negative number that the line overflows.
+ */
+ protected int computeDifference(KnuthNode activeNode, KnuthElement element) {
+ int actualWidth = totalWidth - activeNode.totalWidth;
+ if (element.isPenalty()) {
+ actualWidth += element.getW();
+ }
+ if (bPendingFootnotes) {
+ int newFootnotes = totalFootnotesLength - ((KnuthPageNode) activeNode).totalFootnotes;
+ // add the footnote separator width if some footnote content will be added
+ if (((KnuthPageNode) activeNode).totalFootnotes < totalFootnotesLength) {
+ actualWidth += footnoteSeparatorLength.opt;
+ }
+ if (actualWidth + newFootnotes <= lineWidth) {
+ // there is enough space to insert all footnotes:
+ // add the whole newFootnotes length
+ actualWidth += newFootnotes;
+ insertedFootnotesLength = ((KnuthPageNode) activeNode).totalFootnotes + newFootnotes;
+ footnoteListIndex = footnotesList.size() - 1;
+ footnoteElementIndex = ((LinkedList) footnotesList.get(footnoteListIndex)).size() - 1;
+ } else {
+ // check if there is enough space to insert at least a piece
+ // of the last footnote (and all the previous ones)
+ int footnoteSplit = getFootnoteSplit((KnuthPageNode) activeNode, lineWidth - actualWidth);
+ if (actualWidth + footnoteSplit <= lineWidth) {
+ // the last footnote will be split
+ // add more footnote content as possible
+ actualWidth += footnoteSplit;
+ insertedFootnotesLength = ((KnuthPageNode) activeNode).totalFootnotes + footnoteSplit;
+ footnoteListIndex = footnotesList.size() - 1;
+ // footnoteElementIndex has been set in getFootnoteSplit()
+ } else {
+ // there is no space to add the smallest piece of the last footnote:
+ // add the whole newFootnotes length, so this breakpoint will be discarded
+ actualWidth += newFootnotes;
+ insertedFootnotesLength = ((KnuthPageNode) activeNode).totalFootnotes + newFootnotes;
+ footnoteListIndex = footnotesList.size() - 1;
+ footnoteElementIndex = ((LinkedList) footnotesList.get(footnoteListIndex)).size() - 1;
+ }
+ }
+ }
+ return lineWidth - actualWidth;
+ }
+
+ private int getFootnoteSplit(KnuthPageNode activeNode, int availableLength) {
+ // length of all the not-yet-inserted footnotes
+ int newFootnotes = totalFootnotesLength - activeNode.totalFootnotes;
+ if (availableLength <= 0) {
+ return newFootnotes;
+ } else {
+ // the split must contain a piece of the last footnote
+ // together with all previous, not yet inserted footnotes
+ int firstFootnoteIndex = activeNode.footnoteListIndex;
+ int firstElementIndex = activeNode.footnoteElementIndex;
+ if (firstElementIndex == ((LinkedList) footnotesList.get(firstFootnoteIndex)).size() - 1) {
+ // advance to the next list
+ firstFootnoteIndex ++;
+ firstElementIndex = 0;
+ } else {
+ firstElementIndex ++;
+ }
+ int splitLength = 0;
+ ListIterator noteListIterator = null;
+ KnuthElement element = null;
+
+ // add previous notes
+ if (footnotesList.size() > 1) {
+ splitLength = ((Integer) lengthList.get(footnotesList.size() - 2)).intValue()
+ - activeNode.totalFootnotes;
+ }
+
+ // add a split of the last note
+ noteListIterator = ((LinkedList) footnotesList.get(footnotesList.size() - 1)).listIterator();
+ boolean bSomethingAdded = false;
+ int prevSplitLength = 0;
+ int prevIndex = 0;
+ int index = 0;
+
+ while (!(bSomethingAdded && splitLength > availableLength)) {
+ if (!bSomethingAdded) {
+ bSomethingAdded = true;
+ } else {
+ prevSplitLength = splitLength;
+ prevIndex = index;
+ }
+ // get a sub-sequence from the note element list
+ boolean bPrevIsBox = false;
+ while (noteListIterator.hasNext()) {
+ element = (KnuthElement) noteListIterator.next();
+ if (element.isBox()) {
+ // element is a box
+ splitLength += element.getW();
+ bPrevIsBox = true;
+ } else if (element.isGlue()) {
+ // element is a glue
+ if (bPrevIsBox) {
+ // end of the sub-sequence
+ index = noteListIterator.previousIndex();
+ break;
+ }
+ bPrevIsBox = false;
+ splitLength += element.getW();
+ } else {
+ // element is a penalty
+ if (element.getP() < KnuthElement.INFINITE) {
+ index = noteListIterator.previousIndex();
+ break;
+ }
+ }
+ }
+ }
+ // if prevSplitLength is 0, this means that the available length isn't enough
+ // to insert even the smallest split of the last footnote, so we cannot end a
+ // page here
+ // if prevSplitLength is > 0 we can insert some footnote content in this page
+ // and insert the remaining in the following one
+ if (prevSplitLength > 0 ) {
+ footnoteElementIndex = prevIndex;
+ return prevSplitLength;
+ } else {
+ return newFootnotes;
+ }
+ }
+ }
+
+ /**
+ * Return the adjust ration needed to make up for the difference. A ration of
+ * <ul>
+ * <li>0 means that the break has the exact right width</li>
+ * <li>&gt;= -1 && &lt; 0 means that the break is to wider than the line,
+ * but within the minimim values of the glues.</li>
+ * <li>&gt;0 && &lt 1 means that the break is smaller than the line width,
+ * but within the maximum values of the glues.</li>
+ * <li>&gt 1 means that the break is too small to make up for the glues.</li>
+ * </ul>
+ * @param activeNode
+ * @param difference
+ * @return The ration.
+ */
+ protected double computeAdjustmentRatio(KnuthNode activeNode, int difference) {
+ // compute the adjustment ratio
+ if (difference > 0) {
+ int maxAdjustment = totalStretch - activeNode.totalStretch;
+ // add the footnote separator stretch if some footnote content will be added
+ if (((KnuthPageNode) activeNode).totalFootnotes < totalFootnotesLength) {
+ maxAdjustment += footnoteSeparatorLength.max - footnoteSeparatorLength.opt;
+ }
+ if (maxAdjustment > 0) {
+ return (double) difference / maxAdjustment;
+ } else {
+ return INFINITE_RATIO;
+ }
+ } else if (difference < 0) {
+ int maxAdjustment = totalShrink - activeNode.totalShrink;
+ // add the footnote separator shrink if some footnote content will be added
+ if (((KnuthPageNode) activeNode).totalFootnotes < totalFootnotesLength) {
+ maxAdjustment += footnoteSeparatorLength.opt - footnoteSeparatorLength.min;
+ }
+ if (maxAdjustment > 0) {
+ return (double) difference / maxAdjustment;
+ } else {
+ return -INFINITE_RATIO;
+ }
+ } else {
+ return 0;
+ }
+ }
+
+ protected double computeDemerits(KnuthNode activeNode, KnuthElement element,
+ int fitnessClass, double r) {
+ double demerits = 0;
+ // compute demerits
+ double f = Math.abs(r);
+ f = 1 + 100 * f * f * f;
+ if (element.isPenalty() && element.getP() >= 0) {
+ f += element.getP();
+ demerits = f * f;
+ } else if (element.isPenalty() && !element.isForcedBreak()) {
+ double penalty = element.getP();
+ demerits = f * f - penalty * penalty;
+ } else {
+ demerits = f * f;
+ }
+
+ if (element.isPenalty() && ((KnuthPenalty) element).isFlagged()
+ && getElement(activeNode.position).isPenalty()
+ && ((KnuthPenalty) getElement(activeNode.position)).isFlagged()) {
+ // add demerit for consecutive breaks at flagged penalties
+ demerits += repeatedFlaggedDemerit;
+ }
+ if (Math.abs(fitnessClass - activeNode.fitness) > 1) {
+ // add demerit for consecutive breaks
+ // with very different fitness classes
+ demerits += incompatibleFitnessDemerit;
+ }
+
+ if (bPendingFootnotes) {
+ if (footnoteListIndex < footnotesList.size() - 1) {
+ // add demerits for the deferred footnotes
+ demerits += deferredFootnoteDemerits;
+ } else if (footnoteElementIndex < ((LinkedList) footnotesList.get(footnoteListIndex)).size() - 1) {
+ // add demerits for the footnote split between pages
+ demerits += splitFootnoteDemerits;
+ } else {
+ // reduce demerits when all footnotes are inserted in the page where their citations are
+ demerits /= 2;
+ }
+ }
+ demerits += activeNode.totalDemerits;
+ return demerits;
+ }
+
+ /**
+ * Remove the first node in line 'line'. If the line then becomes empty, adjust the
+ * startLine accordingly.
+ * @param line
+ * @param node
+ */
+ protected void removeNode(int line, KnuthNode node) {
+ KnuthNode n = getNode(line);
+ if (n != node) {
+ if (bPendingFootnotes) {
+ // nodes could be rightly deactivated in a different order
+ KnuthNode prevNode = null;
+ while (n != node) {
+ prevNode = n;
+ n = n.next;
+ }
+ prevNode.next = n.next;
+ if (prevNode.next == null) {
+ activeLines[line*2+1] = prevNode;
+ }
+ } else {
+ log.error("Should be first");
+ }
+ } else {
+ activeLines[line*2] = node.next;
+ if (node.next == null) {
+ activeLines[line*2+1] = null;
+ }
+ while (startLine < endLine && getNode(startLine) == null) {
+ startLine++;
+ }
+ }
+ activeNodeCount--;
}
public LinkedList getPageBreaks() {
@@ -55,6 +495,17 @@ class PageBreakingAlgorithm extends BreakingAlgorithm {
double ratio = (blockAlignment == org.apache.fop.fo.Constants.EN_JUSTIFY
|| bestActiveNode.adjustRatio < 0) ? bestActiveNode.adjustRatio : 0;
+ // compute the indexes of the first footnote list and the first element in that list
+ int firstListIndex = ((KnuthPageNode) bestActiveNode.previous).footnoteListIndex;
+ int firstElementIndex = ((KnuthPageNode) bestActiveNode.previous).footnoteElementIndex;
+ if (footnotesList != null
+ && firstElementIndex == ((LinkedList) footnotesList.get(firstListIndex)).size() - 1) {
+ // advance to the next list
+ firstListIndex ++;
+ firstElementIndex = 0;
+ } else {
+ firstElementIndex ++;
+ }
// add nodes at the beginning of the list, as they are found
// backwards, from the last one to the first one
@@ -63,7 +514,11 @@ class PageBreakingAlgorithm extends BreakingAlgorithm {
+ " posizione= " + bestActiveNode.position);
}
insertPageBreakAsFirst(new PageBreakPosition(this.topLevelLM,
- bestActiveNode.position, ratio, difference));
+ bestActiveNode.position,
+ firstListIndex, firstElementIndex,
+ ((KnuthPageNode) bestActiveNode).footnoteListIndex,
+ ((KnuthPageNode) bestActiveNode).footnoteElementIndex,
+ ratio, difference));
}
protected int filterActiveNodes() {
@@ -80,4 +535,7 @@ class PageBreakingAlgorithm extends BreakingAlgorithm {
return bestActiveNode.line;
}
+ public LinkedList getFootnoteList(int index) {
+ return (LinkedList) footnotesList.get(index);
+ }
} \ No newline at end of file
diff --git a/src/java/org/apache/fop/layoutmgr/PageSequenceLayoutManager.java b/src/java/org/apache/fop/layoutmgr/PageSequenceLayoutManager.java
index 64b35f0c6..d5363f2c6 100644
--- a/src/java/org/apache/fop/layoutmgr/PageSequenceLayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/PageSequenceLayoutManager.java
@@ -22,6 +22,8 @@ import org.apache.fop.apps.FOPException;
import org.apache.fop.area.AreaTreeHandler;
import org.apache.fop.area.AreaTreeModel;
+import org.apache.fop.area.Block;
+import org.apache.fop.area.Footnote;
import org.apache.fop.area.PageViewport;
import org.apache.fop.area.LineArea;
import org.apache.fop.area.Resolvable;
@@ -37,8 +39,11 @@ import org.apache.fop.fo.pagination.SideRegion;
import org.apache.fop.fo.pagination.SimplePageMaster;
import org.apache.fop.fo.pagination.StaticContent;
+import org.apache.fop.traits.MinOptMax;
+
import java.util.LinkedList;
import java.util.List;
+import java.util.ListIterator;
/**
* LayoutManager for a PageSequence. This class is instantiated by
@@ -80,6 +85,8 @@ public class PageSequenceLayoutManager extends AbstractLayoutManager {
private int startPageNum = 0;
private int currentPageNum = 0;
+ private Block separatorArea = null;
+
/**
* Constructor
*
@@ -137,6 +144,9 @@ public class PageSequenceLayoutManager extends AbstractLayoutManager {
private PageSequenceLayoutManager pslm;
private boolean firstPart = true;
+ private StaticContentLayoutManager footnoteSeparatorLM = null;
+ private LinkedList footnoteSeparatorList = null;
+
public PageBreaker(PageSequenceLayoutManager pslm) {
this.pslm = pslm;
}
@@ -153,7 +163,67 @@ public class PageSequenceLayoutManager extends AbstractLayoutManager {
}
protected LinkedList getNextKnuthElements(LayoutContext context, int alignment) {
- return pslm.getNextKnuthElements(context, alignment);
+ LinkedList contentList = pslm.getNextKnuthElements(context, alignment);
+
+ // scan contentList, searching for footnotes
+ boolean bFootnotesPresent = false;
+ if (contentList != null) {
+ ListIterator contentListIterator = contentList.listIterator();
+ while (contentListIterator.hasNext()) {
+ KnuthElement element = (KnuthElement) contentListIterator.next();
+ if (element instanceof KnuthBlockBox
+ && ((KnuthBlockBox) element).hasAnchors()) {
+ // element represents a line with footnote citations
+ bFootnotesPresent = true;
+ LinkedList footnoteBodyLMs = ((KnuthBlockBox) element).getFootnoteBodyLMs();
+ ListIterator footnoteBodyIterator = footnoteBodyLMs.listIterator();
+ // store the lists of elements representing the footnote bodies
+ // in the box representing the line containing their references
+ while (footnoteBodyIterator.hasNext()) {
+ FootnoteBodyLayoutManager fblm = (FootnoteBodyLayoutManager) footnoteBodyIterator.next();
+ fblm.setParent(childFLM);
+ ((KnuthBlockBox) element).addElementList(fblm.getNextKnuthElements(context, alignment));
+ }
+ }
+ }
+ }
+
+ // handle the footnote separator
+ StaticContent footnoteSeparator;
+ if (bFootnotesPresent
+ && (footnoteSeparator = pageSeq.getStaticContent("xsl-footnote-separator")) != null) {
+ // create a Block area that will contain the separator areas
+ separatorArea = new Block();
+
+ // create a StaticContentLM for the footnote separator
+ footnoteSeparatorLM = (StaticContentLayoutManager)
+ getLayoutManagerMaker().makeStaticContentLayoutManager(
+ pslm, footnoteSeparator, separatorArea);
+
+ // get the list of elements representing the footnote separator
+ footnoteSeparatorList = footnoteSeparatorLM.getNextKnuthElements(context, alignment);
+
+ // compute the total length of the elements
+ footnoteSeparatorLength = new MinOptMax(0);
+ ListIterator separatorIterator = footnoteSeparatorList.listIterator();
+ while (separatorIterator.hasNext()) {
+ KnuthElement element = (KnuthElement) separatorIterator.next();
+ if (element.isBox()) {
+ footnoteSeparatorLength.add(new MinOptMax(element.getW()));
+ } else if (element.isGlue()) {
+ footnoteSeparatorLength.add(new MinOptMax(element.getW()));
+ footnoteSeparatorLength.max += element.getY();
+ footnoteSeparatorLength.min -= element.getZ();
+ }
+ }
+
+ // add the footnote separator areas to the Block area
+ if (footnoteSeparatorList != null) {
+ LayoutContext childLC = new LayoutContext(0);
+ footnoteSeparatorLM.addAreas(new KnuthPossPosIter(footnoteSeparatorList, 0, footnoteSeparatorList.size()), childLC);
+ }
+ }
+ return contentList;
}
protected int getCurrentDisplayAlign() {
@@ -198,7 +268,30 @@ public class PageSequenceLayoutManager extends AbstractLayoutManager {
firstPart = false;
}
- protected void finishPart() {
+ protected void finishPart(PageBreakingAlgorithm alg, PageBreakPosition pbp) {
+ // add footnote areas
+ if (pbp.footnoteFirstListIndex < pbp.footnoteLastListIndex
+ || pbp.footnoteFirstElementIndex <= pbp.footnoteLastElementIndex) {
+ // call addAreas() for each FootnoteBodyLM
+ for (int i = pbp.footnoteFirstListIndex; i <= pbp.footnoteLastListIndex; i++) {
+ LinkedList elementList = alg.getFootnoteList(i);
+ int firstIndex = (i == pbp.footnoteFirstListIndex ? pbp.footnoteFirstElementIndex : 0);
+ int lastIndex = (i == pbp.footnoteLastListIndex ? pbp.footnoteLastElementIndex : elementList.size() - 1);
+
+ FootnoteBodyLayoutManager fblm = (FootnoteBodyLayoutManager)
+ ((KnuthElement) elementList.getFirst()).getLayoutManager();
+ LayoutContext childLC = new LayoutContext(0);
+ fblm.addAreas(new KnuthPossPosIter(elementList, firstIndex, lastIndex + 1), childLC);
+ }
+ // set the offset from the top margin
+ Footnote parentArea = (Footnote) getCurrentPV().getBodyRegion().getFootnote();
+ int topOffset = (int) curPV.getBodyRegion().getBPD() - parentArea.getBPD();
+ if (separatorArea != null) {
+ topOffset -= separatorArea.getBPD();
+ }
+ parentArea.setTop(topOffset);
+ parentArea.setSeparator(separatorArea);
+ }
}
protected LayoutManager getCurrentChildLM() {
@@ -225,14 +318,14 @@ public class PageSequenceLayoutManager extends AbstractLayoutManager {
LayoutManager curLM; // currently active LM
while ((curLM = getChildLM()) != null) {
-/*LF*/ LinkedList returnedList = null;
-/*LF*/ if (childFLM == null && (curLM instanceof FlowLayoutManager)) {
-/*LF*/ childFLM = (FlowLayoutManager)curLM;
-/*LF*/ } else {
-/*LF*/ if (curLM != childFLM) {
-/*LF*/ log.error("PSLM> invalid child LM");
-/*LF*/ }
-/*LF*/ }
+ LinkedList returnedList = null;
+ if (childFLM == null && (curLM instanceof FlowLayoutManager)) {
+ childFLM = (FlowLayoutManager)curLM;
+ } else {
+ if (curLM != childFLM) {
+ log.error("PSLM> invalid child LM");
+ }
+ }
LayoutContext childLC = new LayoutContext(0);
childLC.setStackLimit(context.getStackLimit());
@@ -243,7 +336,7 @@ public class PageSequenceLayoutManager extends AbstractLayoutManager {
int flowBPD = (int) curPV.getBodyRegion().getBPD();
pageSeq.setLayoutDimension(PercentBase.REFERENCE_AREA_IPD, flowIPD);
pageSeq.setLayoutDimension(PercentBase.REFERENCE_AREA_BPD, flowBPD);
-/*LF*/ returnedList = curLM.getNextKnuthElements(childLC, alignment);
+ returnedList = curLM.getNextKnuthElements(childLC, alignment);
}
if (returnedList != null) {
return returnedList;
diff --git a/src/java/org/apache/fop/layoutmgr/StaticContentLayoutManager.java b/src/java/org/apache/fop/layoutmgr/StaticContentLayoutManager.java
index 828f2bf6a..e305ff48e 100644
--- a/src/java/org/apache/fop/layoutmgr/StaticContentLayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/StaticContentLayoutManager.java
@@ -39,6 +39,7 @@ import java.util.ListIterator;
*/
public class StaticContentLayoutManager extends BlockStackingLayoutManager {
private RegionReference targetRegion;
+ private Block targetBlock;
private List blockBreaks = new ArrayList();
private SideRegion regionFO;
@@ -50,6 +51,13 @@ public class StaticContentLayoutManager extends BlockStackingLayoutManager {
targetRegion = getCurrentPV().getRegionReference(regionFO.getNameId());
}
+ public StaticContentLayoutManager(PageSequenceLayoutManager pslm,
+ StaticContent node, Block block) {
+ super(node);
+ setParent(pslm);
+ targetBlock = block;
+ }
+
/**
* @see org.apache.fop.layoutmgr.LayoutManager#getNextKnuthElements(org.apache.fop.layoutmgr.LayoutContext, int)
*/
@@ -206,15 +214,23 @@ public class StaticContentLayoutManager extends BlockStackingLayoutManager {
* @see org.apache.fop.layoutmgr.LayoutManager#addChildArea(Area)
*/
public void addChildArea(Area childArea) {
+ if (getStaticContentFO().getFlowName().equals("xsl-footnote-separator")) {
+ targetBlock.addBlock((Block)childArea);
+ } else {
targetRegion.addBlock((Block)childArea);
}
+ }
/**
* @see org.apache.fop.layoutmgr.LayoutManager#getParentArea(Area)
*/
public Area getParentArea(Area childArea) {
+ if (getStaticContentFO().getFlowName().equals("xsl-footnote-separator")) {
+ return targetBlock;
+ } else {
return targetRegion;
}
+ }
public void doLayout() {
StaticContentBreaker breaker = new StaticContentBreaker(
@@ -228,6 +244,13 @@ public class StaticContentLayoutManager extends BlockStackingLayoutManager {
}
}
+ /**
+ * convenience method that returns the Static Content node
+ */
+ protected StaticContent getStaticContentFO() {
+ return (StaticContent) fobj;
+ }
+
private class StaticContentBreaker extends AbstractBreaker {
private StaticContentLayoutManager lm;
private int displayAlign;
@@ -298,7 +321,7 @@ public class StaticContentLayoutManager extends BlockStackingLayoutManager {
}
}
- protected void finishPart() {
+ protected void finishPart(PageBreakingAlgorithm alg, PageBreakPosition pbp) {
//nop for static content
}
diff --git a/src/java/org/apache/fop/render/AbstractRenderer.java b/src/java/org/apache/fop/render/AbstractRenderer.java
index 2bbd89fad..ea7ce4da1 100644
--- a/src/java/org/apache/fop/render/AbstractRenderer.java
+++ b/src/java/org/apache/fop/render/AbstractRenderer.java
@@ -348,6 +348,7 @@ public abstract class AbstractRenderer
* @param footnote The footnote
*/
protected void renderFootnote(Footnote footnote) {
+ currentBPPosition += footnote.getTop();
List blocks = footnote.getChildAreas();
if (blocks != null) {
Block sep = footnote.getSeparator();