You are viewing a plain text version of this content. The canonical link for it is here.
Posted to fop-commits@xmlgraphics.apache.org by lf...@apache.org on 2005/05/17 16:30:33 UTC

cvs commit: xml-fop/src/java/org/apache/fop/render AbstractRenderer.java

lfurini     2005/05/17 07:30:33

  Modified:    src/java/org/apache/fop/area Footnote.java
               src/java/org/apache/fop/fo/flow Footnote.java
               src/java/org/apache/fop/layoutmgr AbstractBreaker.java
                        BlockContainerLayoutManager.java
                        BlockStackingLayoutManager.java
                        BreakingAlgorithm.java FlowLayoutManager.java
                        InlineStackingLayoutManager.java KnuthBlockBox.java
                        KnuthInlineBox.java LayoutManagerMaker.java
                        LayoutManagerMapping.java LineLayoutManager.java
                        PageBreakingAlgorithm.java
                        PageSequenceLayoutManager.java
                        StaticContentLayoutManager.java
               src/java/org/apache/fop/render AbstractRenderer.java
  Log:
  Footnote implementation: changes to existing files
  
  Revision  Changes    Path
  1.4       +22 -0     xml-fop/src/java/org/apache/fop/area/Footnote.java
  
  Index: Footnote.java
  ===================================================================
  RCS file: /home/cvs/xml-fop/src/java/org/apache/fop/area/Footnote.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- Footnote.java	11 Mar 2005 07:23:43 -0000	1.3
  +++ Footnote.java	17 May 2005 14:30:32 -0000	1.4
  @@ -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 @@
           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;
  +    }
   }
   
  
  
  
  1.32      +16 -8     xml-fop/src/java/org/apache/fop/fo/flow/Footnote.java
  
  Index: Footnote.java
  ===================================================================
  RCS file: /home/cvs/xml-fop/src/java/org/apache/fop/fo/flow/Footnote.java,v
  retrieving revision 1.31
  retrieving revision 1.32
  diff -u -r1.31 -r1.32
  --- Footnote.java	24 Dec 2004 12:06:26 -0000	1.31
  +++ Footnote.java	17 May 2005 14:30:33 -0000	1.32
  @@ -38,7 +38,7 @@
       private CommonAccessibility commonAccessibility;
       // End of property values
   
  -    private Inline inlineFO = null;
  +    private Inline footnoteCitation = null;
       private FootnoteBody footnoteBody;
   
       /**
  @@ -69,7 +69,7 @@
        */
       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 @@
       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 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 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;
       }
   
       /**
  
  
  
  1.4       +16 -8     xml-fop/src/java/org/apache/fop/layoutmgr/AbstractBreaker.java
  
  Index: AbstractBreaker.java
  ===================================================================
  RCS file: /home/cvs/xml-fop/src/java/org/apache/fop/layoutmgr/AbstractBreaker.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- AbstractBreaker.java	17 May 2005 07:02:14 -0000	1.3
  +++ AbstractBreaker.java	17 May 2005 14:30:33 -0000	1.4
  @@ -35,16 +35,24 @@
       /** 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 @@
   
       /** 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 @@
           //nop
       }
       
  -    protected abstract void finishPart();
  +    protected abstract void finishPart(PageBreakingAlgorithm alg, PageBreakPosition pbp);
   
       protected LayoutContext createLayoutContext() {
           return new LayoutContext(0);
  @@ -157,7 +165,7 @@
               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 @@
                           startElementIndex, endElementIndex + 1), childLC);
               }
   
  -            finishPart();
  +            finishPart(alg, pbp);
   
               startElementIndex = pbp.getLeafPos() + 1;
           }
  
  
  
  1.38      +1 -1      xml-fop/src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java
  
  Index: BlockContainerLayoutManager.java
  ===================================================================
  RCS file: /home/cvs/xml-fop/src/java/org/apache/fop/layoutmgr/BlockContainerLayoutManager.java,v
  retrieving revision 1.37
  retrieving revision 1.38
  diff -u -r1.37 -r1.38
  --- BlockContainerLayoutManager.java	13 May 2005 19:16:51 -0000	1.37
  +++ BlockContainerLayoutManager.java	17 May 2005 14:30:33 -0000	1.38
  @@ -521,7 +521,7 @@
               this.deferredEffectiveList = effectiveList;
           }
           
  -        protected void finishPart() {
  +        protected void finishPart(PageBreakingAlgorithm alg, PageBreakPosition pbp) {
               //nop for bclm
           }
           
  
  
  
  1.14      +2 -2      xml-fop/src/java/org/apache/fop/layoutmgr/BlockStackingLayoutManager.java
  
  Index: BlockStackingLayoutManager.java
  ===================================================================
  RCS file: /home/cvs/xml-fop/src/java/org/apache/fop/layoutmgr/BlockStackingLayoutManager.java,v
  retrieving revision 1.13
  retrieving revision 1.14
  diff -u -r1.13 -r1.14
  --- BlockStackingLayoutManager.java	17 May 2005 07:02:14 -0000	1.13
  +++ BlockStackingLayoutManager.java	17 May 2005 14:30:33 -0000	1.14
  @@ -230,8 +230,8 @@
                   childLC.setRefIPD(ipd);
               } else {
                   // curLM is a ?
  -                childLC.setStackLimit(MinOptMax.subtract(context
  -                        .getStackLimit(), stackSize));
  +                //childLC.setStackLimit(MinOptMax.subtract(context
  +                //        .getStackLimit(), stackSize));
                   childLC.setRefIPD(referenceIPD);
               }
   
  
  
  
  1.4       +68 -46    xml-fop/src/java/org/apache/fop/layoutmgr/BreakingAlgorithm.java
  
  Index: BreakingAlgorithm.java
  ===================================================================
  RCS file: /home/cvs/xml-fop/src/java/org/apache/fop/layoutmgr/BreakingAlgorithm.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- BreakingAlgorithm.java	17 May 2005 07:02:14 -0000	1.3
  +++ BreakingAlgorithm.java	17 May 2005 14:30:33 -0000	1.4
  @@ -23,6 +23,9 @@
   
   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 @@
       // 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 @@
       /**
        * 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 @@
       /**
        * The set of active nodes.
        */
  -    private KnuthNode[] activeLines;
  +    protected KnuthNode[] activeLines;
       
       /**
        * The number of active nodes.
  @@ -97,22 +98,22 @@
       /**
        * 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 @@
   
   
       // 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 @@
       // 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 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 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 @@
           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 @@
   
           // 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 @@
                   // 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 @@
                   }
   
                   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 @@
           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 @@
                       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 @@
                           }
                       } 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 @@
                   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 @@
        * @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 @@
        * @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 @@
           }
       }
   
  -    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 @@
        * @param idx index of the element.
        * @return
        */
  -    private KnuthElement getElement(int idx) {
  +    protected KnuthElement getElement(int idx) {
           return (KnuthElement) par.get(idx);
       }
   
  
  
  
  1.15      +4 -12     xml-fop/src/java/org/apache/fop/layoutmgr/FlowLayoutManager.java
  
  Index: FlowLayoutManager.java
  ===================================================================
  RCS file: /home/cvs/xml-fop/src/java/org/apache/fop/layoutmgr/FlowLayoutManager.java,v
  retrieving revision 1.14
  retrieving revision 1.15
  diff -u -r1.14 -r1.15
  --- FlowLayoutManager.java	14 May 2005 19:28:32 -0000	1.14
  +++ FlowLayoutManager.java	17 May 2005 14:30:33 -0000	1.15
  @@ -52,7 +52,6 @@
        */
       private int numSubsequentOverflows = 0;
       
  -/*LF*/
       private static class StackingIter extends PositionIterator {
           StackingIter(Iterator parentIter) {
               super(parentIter);
  @@ -66,7 +65,6 @@
               return ((Position) nextObj);
           }
       }
  -/*LF*/
   
       /**
        * This is the top level layout manager.
  @@ -223,15 +221,14 @@
                           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 @@
           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 @@
           // 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 @@
                                                    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 @@
           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 @@
        * @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 @@
                       "area class (" + aclass + ") requested.");
           }
           
  -        this.currentAreas[parentArea.getAreaClass()] = parentArea;
  +        this.currentAreas[aclass] = parentArea;
           setCurrentArea(parentArea);
           return parentArea;
       }
  
  
  
  1.22      +1 -0      xml-fop/src/java/org/apache/fop/layoutmgr/InlineStackingLayoutManager.java
  
  Index: InlineStackingLayoutManager.java
  ===================================================================
  RCS file: /home/cvs/xml-fop/src/java/org/apache/fop/layoutmgr/InlineStackingLayoutManager.java,v
  retrieving revision 1.21
  retrieving revision 1.22
  diff -u -r1.21 -r1.22
  --- InlineStackingLayoutManager.java	13 May 2005 19:16:51 -0000	1.21
  +++ InlineStackingLayoutManager.java	17 May 2005 14:30:33 -0000	1.22
  @@ -603,6 +603,7 @@
                                                returnedElement.getPosition()));
                       returnList.add(returnedElement);
                   }
  +                setFinished(curLM.isFinished() && (getChildLM() == null));
                   return returnList;
               } else {
                   // curLM returned null because it finished;
  
  
  
  1.3       +32 -1     xml-fop/src/java/org/apache/fop/layoutmgr/KnuthBlockBox.java
  
  Index: KnuthBlockBox.java
  ===================================================================
  RCS file: /home/cvs/xml-fop/src/java/org/apache/fop/layoutmgr/KnuthBlockBox.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- KnuthBlockBox.java	13 May 2005 19:16:51 -0000	1.2
  +++ KnuthBlockBox.java	17 May 2005 14:30:33 -0000	1.3
  @@ -20,15 +20,46 @@
   
   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() {
  
  
  
  1.3       +23 -1     xml-fop/src/java/org/apache/fop/layoutmgr/KnuthInlineBox.java
  
  Index: KnuthInlineBox.java
  ===================================================================
  RCS file: /home/cvs/xml-fop/src/java/org/apache/fop/layoutmgr/KnuthInlineBox.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- KnuthInlineBox.java	13 May 2005 19:16:51 -0000	1.2
  +++ KnuthInlineBox.java	17 May 2005 14:30:33 -0000	1.3
  @@ -23,6 +23,7 @@
       private int lead;
       private int total;
       private int middle;
  +    private FootnoteBodyLayoutManager footnoteBodyLM = null;
   
       /**
        * Create a new KnuthBox.
  @@ -61,4 +62,25 @@
       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
  
  
  
  1.5       +12 -2     xml-fop/src/java/org/apache/fop/layoutmgr/LayoutManagerMaker.java
  
  Index: LayoutManagerMaker.java
  ===================================================================
  RCS file: /home/cvs/xml-fop/src/java/org/apache/fop/layoutmgr/LayoutManagerMaker.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- LayoutManagerMaker.java	16 May 2005 02:54:19 -0000	1.4
  +++ LayoutManagerMaker.java	17 May 2005 14:30:33 -0000	1.5
  @@ -23,7 +23,7 @@
   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 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);
  +
   }
   
  
  
  
  1.10      +10 -5     xml-fop/src/java/org/apache/fop/layoutmgr/LayoutManagerMapping.java
  
  Index: LayoutManagerMapping.java
  ===================================================================
  RCS file: /home/cvs/xml-fop/src/java/org/apache/fop/layoutmgr/LayoutManagerMapping.java,v
  retrieving revision 1.9
  retrieving revision 1.10
  diff -u -r1.9 -r1.10
  --- LayoutManagerMapping.java	16 May 2005 02:54:19 -0000	1.9
  +++ LayoutManagerMapping.java	17 May 2005 14:30:33 -0000	1.10
  @@ -166,6 +166,14 @@
           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 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));
           }
       }
   
  
  
  
  1.44      +22 -2     xml-fop/src/java/org/apache/fop/layoutmgr/LineLayoutManager.java
  
  Index: LineLayoutManager.java
  ===================================================================
  RCS file: /home/cvs/xml-fop/src/java/org/apache/fop/layoutmgr/LineLayoutManager.java,v
  retrieving revision 1.43
  retrieving revision 1.44
  diff -u -r1.43 -r1.44
  --- LineLayoutManager.java	13 May 2005 19:16:51 -0000	1.43
  +++ LineLayoutManager.java	17 May 2005 14:30:33 -0000	1.44
  @@ -620,6 +620,12 @@
                       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 @@
                   /* "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 @@
                           // 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));
                   }
               }
           }
  
  
  
  1.4       +461 -3    xml-fop/src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java
  
  Index: PageBreakingAlgorithm.java
  ===================================================================
  RCS file: /home/cvs/xml-fop/src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- PageBreakingAlgorithm.java	17 May 2005 07:02:14 -0000	1.3
  +++ PageBreakingAlgorithm.java	17 May 2005 14:30:33 -0000	1.4
  @@ -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 @@
           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 @@
                       + " 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 @@
           return bestActiveNode.line;
       }
   
  +    public LinkedList getFootnoteList(int index) {
  +        return (LinkedList) footnotesList.get(index);
  +    }
   }
  \ No newline at end of file
  
  
  
  1.57      +105 -12   xml-fop/src/java/org/apache/fop/layoutmgr/PageSequenceLayoutManager.java
  
  Index: PageSequenceLayoutManager.java
  ===================================================================
  RCS file: /home/cvs/xml-fop/src/java/org/apache/fop/layoutmgr/PageSequenceLayoutManager.java,v
  retrieving revision 1.56
  retrieving revision 1.57
  diff -u -r1.56 -r1.57
  --- PageSequenceLayoutManager.java	17 May 2005 07:02:14 -0000	1.56
  +++ PageSequenceLayoutManager.java	17 May 2005 14:30:33 -0000	1.57
  @@ -22,6 +22,8 @@
   
   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.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 @@
       private int startPageNum = 0;
       private int currentPageNum = 0;
   
  +    private Block separatorArea = null;
  +    
       /**
        * Constructor
        *
  @@ -137,6 +144,9 @@
           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 @@
           }
           
           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 @@
               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 @@
           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 @@
                   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;
  
  
  
  1.12      +24 -1     xml-fop/src/java/org/apache/fop/layoutmgr/StaticContentLayoutManager.java
  
  Index: StaticContentLayoutManager.java
  ===================================================================
  RCS file: /home/cvs/xml-fop/src/java/org/apache/fop/layoutmgr/StaticContentLayoutManager.java,v
  retrieving revision 1.11
  retrieving revision 1.12
  diff -u -r1.11 -r1.12
  --- StaticContentLayoutManager.java	16 May 2005 02:54:19 -0000	1.11
  +++ StaticContentLayoutManager.java	17 May 2005 14:30:33 -0000	1.12
  @@ -39,6 +39,7 @@
    */
   public class StaticContentLayoutManager extends BlockStackingLayoutManager {
       private RegionReference targetRegion;
  +    private Block targetBlock;
       private List blockBreaks = new ArrayList();
       private SideRegion regionFO;
   
  @@ -50,6 +51,13 @@
           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 @@
        * @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 @@
           }
       }
       
  +    /**
  +     * 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 @@
               }
           }
           
  -        protected void finishPart() {
  +        protected void finishPart(PageBreakingAlgorithm alg, PageBreakPosition pbp) {
               //nop for static content
           }
           
  
  
  
  1.45      +1 -0      xml-fop/src/java/org/apache/fop/render/AbstractRenderer.java
  
  Index: AbstractRenderer.java
  ===================================================================
  RCS file: /home/cvs/xml-fop/src/java/org/apache/fop/render/AbstractRenderer.java,v
  retrieving revision 1.44
  retrieving revision 1.45
  diff -u -r1.44 -r1.45
  --- AbstractRenderer.java	13 May 2005 19:16:54 -0000	1.44
  +++ AbstractRenderer.java	17 May 2005 14:30:33 -0000	1.45
  @@ -348,6 +348,7 @@
        * @param footnote  The footnote
        */
       protected void renderFootnote(Footnote footnote) {
  +        currentBPPosition += footnote.getTop();
           List blocks = footnote.getChildAreas();
           if (blocks != null) {
               Block sep = footnote.getSeparator();
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: fop-commits-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: fop-commits-help@xmlgraphics.apache.org