Browse Source

Footnote implementation: changes to existing files


git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@198637 13f79535-47bb-0310-9956-ffa450edef68
tags/fop-0_90-alpha1
Luca Furini 19 years ago
parent
commit
8a6f6d0013

+ 22
- 0
src/java/org/apache/fop/area/Footnote.java View File

@@ -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;
}
}


+ 16
- 8
src/java/org/apache/fop/fo/flow/Footnote.java View File

@@ -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;
}

/**

+ 15
- 7
src/java/org/apache/fop/layoutmgr/AbstractBreaker.java View File

@@ -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;
}

+ 1
- 1
src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java View File

@@ -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
}

+ 2
- 2
src/java/org/apache/fop/layoutmgr/BlockStackingLayoutManager.java View File

@@ -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);
}


+ 67
- 45
src/java/org/apache/fop/layoutmgr/BreakingAlgorithm.java View File

@@ -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);
}


+ 4
- 12
src/java/org/apache/fop/layoutmgr/FlowLayoutManager.java View File

@@ -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;
}

+ 1
- 0
src/java/org/apache/fop/layoutmgr/InlineStackingLayoutManager.java View File

@@ -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;

+ 31
- 0
src/java/org/apache/fop/layoutmgr/KnuthBlockBox.java View File

@@ -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() {

+ 22
- 0
src/java/org/apache/fop/layoutmgr/KnuthInlineBox.java View File

@@ -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);
}
}

+ 11
- 1
src/java/org/apache/fop/layoutmgr/LayoutManagerMaker.java View File

@@ -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);

}


+ 9
- 4
src/java/org/apache/fop/layoutmgr/LayoutManagerMapping.java View File

@@ -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));
}
}


+ 22
- 2
src/java/org/apache/fop/layoutmgr/LineLayoutManager.java View File

@@ -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));
}
}
}

+ 460
- 2
src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java View File

@@ -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);
}
}

+ 104
- 11
src/java/org/apache/fop/layoutmgr/PageSequenceLayoutManager.java View File

@@ -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;

+ 24
- 1
src/java/org/apache/fop/layoutmgr/StaticContentLayoutManager.java View File

@@ -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
}

+ 1
- 0
src/java/org/apache/fop/render/AbstractRenderer.java View File

@@ -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();

Loading…
Cancel
Save