make floats and footnotes play nice together

git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/Temp_BasicSideFloats@1641619 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/src/java/org/apache/fop/layoutmgr/PageBreaker.java b/src/java/org/apache/fop/layoutmgr/PageBreaker.java
index 206aac8..ba676ab 100644
--- a/src/java/org/apache/fop/layoutmgr/PageBreaker.java
+++ b/src/java/org/apache/fop/layoutmgr/PageBreaker.java
@@ -56,6 +56,19 @@
     private int floatHeight;
     private int floatYOffset;
 
+    private List relayedFootnotesList;
+    private List relayedLengthList;
+    private int relayedTotalFootnotesLength;
+    private int relayedInsertedFootnotesLength;
+    private boolean relayedFootnotesPending;
+    private boolean relayedNewFootnotes;
+    private int relayedFirstNewFootnoteIndex;
+    private int relayedFootnoteListIndex;
+    private int relayedFootnoteElementIndex = -1;
+    private MinOptMax relayedFootnoteSeparatorLength;
+    private int previousFootnoteListIndex = -2;
+    private int previousFootnoteElementIndex = -2;
+
     /**
      * The FlowLayoutManager object, which processes
      * the single fo:flow of the fo:page-sequence
@@ -814,6 +827,10 @@
                 int effectiveFloatHeight = alg.getFloatHeight();
                 pslm.recordEndOfFloat(effectiveFloatHeight);
             }
+            if (alg.handlingFloat()) {
+                PageSequenceLayoutManager pslm = (PageSequenceLayoutManager) getTopLevelLM();
+                alg.relayFootnotes(pslm);
+            }
         } else {
             // no content for this part
             handleEmptyContent();
@@ -821,4 +838,40 @@
 
         pageBreakHandled = true;
     }
+
+    public void holdFootnotes(List fl, List ll, int tfl, int ifl, boolean fp, boolean nf, int fnfi, int fli,
+            int fei, MinOptMax fsl, int pfli, int pfei) {
+        relayedFootnotesList = fl;
+        relayedLengthList = ll;
+        relayedTotalFootnotesLength = tfl;
+        relayedInsertedFootnotesLength = ifl;
+        relayedFootnotesPending = fp;
+        relayedNewFootnotes = nf;
+        relayedFirstNewFootnoteIndex = fnfi;
+        relayedFootnoteListIndex = fli;
+        relayedFootnoteElementIndex = fei;
+        relayedFootnoteSeparatorLength = fsl;
+        previousFootnoteListIndex = pfli;
+        previousFootnoteElementIndex = pfei;
+    }
+
+    public void retrieveFootones(PageBreakingAlgorithm alg) {
+        if (relayedFootnotesList != null && relayedFootnotesList.size() > 0) {
+            alg.loadFootnotes(relayedFootnotesList, relayedLengthList, relayedTotalFootnotesLength,
+                    relayedInsertedFootnotesLength, relayedFootnotesPending, relayedNewFootnotes,
+                    relayedFirstNewFootnoteIndex, relayedFootnoteListIndex, relayedFootnoteElementIndex,
+                    relayedFootnoteSeparatorLength, previousFootnoteListIndex,
+                    previousFootnoteElementIndex);
+            relayedFootnotesList = null;
+            relayedLengthList = null;
+            relayedTotalFootnotesLength = 0;
+            relayedInsertedFootnotesLength = 0;
+            relayedFootnotesPending = false;
+            relayedNewFootnotes = false;
+            relayedFirstNewFootnoteIndex = 0;
+            relayedFootnoteListIndex = 0;
+            relayedFootnoteElementIndex = -1;
+            relayedFootnoteSeparatorLength = null;
+        }
+    }
 }
diff --git a/src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java b/src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java
index dc3cc59..008ec22 100644
--- a/src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java
+++ b/src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java
@@ -103,10 +103,12 @@
     // just one float for now...
     private boolean handlingStartOfFloat;
     private boolean handlingEndOfFloat;
-    private int floatYOffset;
     private int floatHeight;
     private KnuthNode bestFloatEdgeNode;
     private FloatPosition floatPosition;
+    private int previousFootnoteListIndex = -2;
+    private int previousFootnoteElementIndex = -2;
+    private boolean relayingFootnotes;
 
     /**
      * Construct a page breaking algorithm.
@@ -246,11 +248,14 @@
         footnoteElementIndex = -1;
         if (topLevelLM instanceof PageSequenceLayoutManager) {
             PageSequenceLayoutManager pslm = (PageSequenceLayoutManager) topLevelLM;
+            if (pslm.handlingStartOfFloat() || pslm.handlingEndOfFloat()) {
+                pslm.retrieveFootnotes(this);
+            }
             if (pslm.handlingStartOfFloat()) {
                 floatHeight = Math.min(pslm.getFloatHeight(), lineWidth - pslm.getFloatYOffset());
             }
             if (pslm.handlingEndOfFloat()) {
-                totalWidth += pslm.getOffsetDueToFloat();
+                totalWidth += pslm.getOffsetDueToFloat() + insertedFootnotesLength;
             }
         }
     }
@@ -1088,17 +1093,6 @@
                 difference = 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 == getFootnoteList(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
@@ -1109,6 +1103,24 @@
         if (handlingFloat() && floatPosition == null) {
             floatPosition = new FloatPosition(this.topLevelLM, bestActiveNode.position, ratio, difference);
         } else {
+            boolean useRelayedFootnotes = relayingFootnotes && bestActiveNode.previous.position == 0;
+            // compute the indexes of the first footnote list and the first element in that list
+            int firstListIndex = (useRelayedFootnotes) ? previousFootnoteListIndex
+                    : ((KnuthPageNode) bestActiveNode.previous).footnoteListIndex;
+            int firstElementIndex = (useRelayedFootnotes) ? previousFootnoteElementIndex
+                    : ((KnuthPageNode) bestActiveNode.previous).footnoteElementIndex;
+            if (useRelayedFootnotes) {
+                previousFootnoteListIndex = -2;
+                previousFootnoteElementIndex = -2;
+                relayingFootnotes = false;
+            }
+            if (footnotesList != null && firstElementIndex == getFootnoteList(firstListIndex).size() - 1) {
+                // advance to the next list
+                firstListIndex++;
+                firstElementIndex = 0;
+            } else {
+                firstElementIndex++;
+            }
             insertPageBreakAsFirst(new PageBreakPosition(this.topLevelLM, bestActiveNode.position,
                     firstListIndex, firstElementIndex, ((KnuthPageNode) bestActiveNode).footnoteListIndex,
                     ((KnuthPageNode) bestActiveNode).footnoteElementIndex, ratio, difference));
@@ -1266,13 +1278,14 @@
     protected void createForcedNodes(KnuthNode node, int line, int elementIdx, int difference, double r,
             double demerits, int fitnessClass, int availableShrink, int availableStretch, int newWidth,
             int newStretch, int newShrink) {
-        super.createForcedNodes(node, line, elementIdx, difference, r, demerits, fitnessClass,
-                availableShrink, availableStretch, newWidth, newStretch, newShrink);
         if (handlingFloat()) {
             if (bestFloatEdgeNode == null || demerits <= bestFloatEdgeNode.totalDemerits) {
                 bestFloatEdgeNode = createNode(elementIdx, line + 1, fitnessClass, newWidth, newStretch,
                         newShrink, r, availableShrink, availableStretch, difference, demerits, node);
             }
+        } else {
+            super.createForcedNodes(node, line, elementIdx, difference, r, demerits, fitnessClass,
+                    availableShrink, availableStretch, newWidth, newStretch, newShrink);
         }
     }
 
@@ -1319,4 +1332,32 @@
         handlingEndOfFloat = false;
         handlingStartOfFloat = false;
     }
+
+    public void loadFootnotes(List fl, List ll, int tfl, int ifl, boolean fp, boolean nf, int fnfi, int fli,
+            int fei, MinOptMax fsl, int pfli, int pfei) {
+        footnotesList = fl;
+        lengthList = ll;
+        totalFootnotesLength = tfl;
+        insertedFootnotesLength = ifl;
+        footnotesPending = fp;
+        newFootnotes = nf;
+        firstNewFootnoteIndex = fnfi;
+        footnoteListIndex = fli;
+        footnoteElementIndex = fei;
+        footnoteSeparatorLength = fsl;
+        previousFootnoteListIndex = pfli;
+        previousFootnoteElementIndex = pfei;
+        relayingFootnotes = !(previousFootnoteListIndex == -2 && previousFootnoteElementIndex == -2);
+    }
+
+    public void relayFootnotes(PageSequenceLayoutManager pslm) {
+        if (!relayingFootnotes) {
+            previousFootnoteListIndex = ((KnuthPageNode) bestFloatEdgeNode.previous).footnoteListIndex;
+            previousFootnoteElementIndex = ((KnuthPageNode) bestFloatEdgeNode.previous).footnoteElementIndex;
+        }
+        pslm.holdFootnotes(footnotesList, lengthList, totalFootnotesLength, insertedFootnotesLength,
+                footnotesPending, newFootnotes, firstNewFootnoteIndex, footnoteListIndex,
+                footnoteElementIndex, footnoteSeparatorLength, previousFootnoteListIndex,
+                previousFootnoteElementIndex);
+    }
 }
diff --git a/src/java/org/apache/fop/layoutmgr/PageSequenceLayoutManager.java b/src/java/org/apache/fop/layoutmgr/PageSequenceLayoutManager.java
index 5cc2423..20c4616 100644
--- a/src/java/org/apache/fop/layoutmgr/PageSequenceLayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/PageSequenceLayoutManager.java
@@ -36,6 +36,7 @@
 import org.apache.fop.fo.pagination.SideRegion;
 import org.apache.fop.fo.pagination.StaticContent;
 import org.apache.fop.layoutmgr.inline.ContentLayoutManager;
+import org.apache.fop.traits.MinOptMax;
 
 /**
  * LayoutManager for a PageSequence.  This class is instantiated by
@@ -345,4 +346,15 @@
         flowIPD -= startIntrusionAdjustment + endIntrusionAdjustment;
         return flowIPD;
     }
+
+    public void holdFootnotes(List fl, List ll, int tfl, int ifl, boolean fp, boolean nf, int fnfi, int fli,
+            int fei, MinOptMax fsl, int pfli, int pfei) {
+        if (fl != null && fl.size() > 0) {
+            pageBreaker.holdFootnotes(fl, ll, tfl, ifl, fp, nf, fnfi, fli, fei, fsl, pfli, pfei);
+        }
+    }
+
+    public void retrieveFootnotes(PageBreakingAlgorithm alg) {
+        pageBreaker.retrieveFootones(alg);
+    }
 }
diff --git a/test/layoutengine/standard-testcases/float_7.xml b/test/layoutengine/standard-testcases/float_7.xml
new file mode 100644
index 0000000..6e51ea9
--- /dev/null
+++ b/test/layoutengine/standard-testcases/float_7.xml
@@ -0,0 +1,107 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<!-- $Id$ -->
+<testcase>
+  <info>
+    <p>
+      This test checks floats.
+    </p>
+  </info>
+  <fo>
+    <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
+      <fo:layout-master-set>
+        <fo:simple-page-master master-name="simple" page-height="5in" page-width="5in" margin="0.2in">
+          <fo:region-body />
+        </fo:simple-page-master>
+      </fo:layout-master-set>
+      <fo:page-sequence master-reference="simple">
+        <fo:flow flow-name="xsl-region-body">
+          <fo:block font-size="12pt" space-before="3pt" text-indent="0.75cm" text-align="justify">
+            Footnote in normal block before a float.<fo:footnote>
+              <fo:inline font-size="60%" baseline-shift="super">1)</fo:inline>
+              <fo:footnote-body>
+                <fo:block start-indent="0.5cm" text-indent="-0.5cm">
+                  <fo:inline font-size="60%" baseline-shift="super">1)</fo:inline> The footnote from the normal block before the float.</fo:block>
+              </fo:footnote-body>
+            </fo:footnote>.
+          </fo:block>
+          <fo:list-block provisional-distance-between-starts="30pt" provisional-label-separation="10pt">
+            <fo:list-item>
+              <fo:list-item-label end-indent="label-end()">
+                <fo:block>(a)</fo:block>
+              </fo:list-item-label>
+              <fo:list-item-body start-indent="body-start()">
+                <fo:block>
+                  Test for float and footnote inside a list. Test for float and footnote inside a list. Test for float and footnote inside a list. (see box)
+        <fo:float float="end">
+          <fo:block border="1pt solid red" padding="5pt" end-indent="0pt" start-indent="0pt">
+            <fo:block-container inline-progression-dimension="120pt">
+              <fo:block background-color="yellow">
+The former dean's house at the University of Wisconsin (this is the alt text of the image in the Wikipedia page)
+              </fo:block>
+            </fo:block-container>
+          </fo:block>
+        </fo:float>
+                  Test for float and footnote inside a list. Test for float and footnote inside a list.
+                </fo:block>
+              </fo:list-item-body>
+            </fo:list-item>
+            <fo:list-item>
+              <fo:list-item-label end-indent="label-end()">
+                <fo:block>(b)</fo:block>
+              </fo:list-item-label>
+              <fo:list-item-body start-indent="body-start()">
+                <fo:block>
+                  Footnote in list that is being wrapped around a float.<fo:footnote>
+                  <fo:inline font-size="60%" baseline-shift="super">2)</fo:inline>
+                    <fo:footnote-body>
+                      <fo:block start-indent="0.5cm" text-indent="-0.5cm">
+                        <fo:inline font-size="60%" baseline-shift="super">2)</fo:inline> The footnote from the list that is being wrapped around a float.</fo:block>
+                    </fo:footnote-body>
+                  </fo:footnote>.
+                  Test for float and footnote inside a list. Test for float and footnote inside a list. Test for float and footnote inside a list. Test for float and footnote inside a list. Test for float and footnote inside a list.
+                </fo:block>
+              </fo:list-item-body>
+            </fo:list-item>
+          </fo:list-block>
+          <fo:block font-size="12pt" space-before="3pt" text-indent="0.75cm" text-align="justify">
+            Footnote in normal block after the float.<fo:footnote>
+              <fo:inline font-size="60%" baseline-shift="super">3)</fo:inline>
+              <fo:footnote-body>
+                <fo:block start-indent="0.5cm" text-indent="-0.5cm">
+                  <fo:inline font-size="60%" baseline-shift="super">3)</fo:inline> The footnote from the normal block after the float.</fo:block>
+              </fo:footnote-body>
+            </fo:footnote>.
+          </fo:block>
+          <fo:block>
+Some filler text.  Some filler text.  Some filler text.  Some filler text.  Some filler text.  Some filler text.  Some filler text.  Some filler text.  Some filler text.  Some filler text.  Some filler text.  Some filler text.  Some filler text.  Some filler text.  Some filler text.  Some filler text.  Some filler text.  Some filler text.  Some filler text.  Some filler text.  Some filler text.  Some filler text.  Some filler text.  Some filler text.  Some filler text.  Some filler text.  Some filler text.  Some filler text.  Some filler text.  Some filler text.  Some filler text.  Some filler text.  Some filler text.  Some filler text.  Some filler text.  Some filler text.  Some filler text.  Some filler text.  Some filler text.  Some filler text.  Some filler text.  Some filler text.  Some filler text.  Some filler text.  Some filler text.  Some filler text.  Some filler text.  Some filler text.  Some filler text.  Some filler text.  Some filler text.
+          </fo:block>
+        </fo:flow>
+      </fo:page-sequence>
+    </fo:root>
+  </fo>
+  <checks>
+    <!-- footnotes -->
+    <eval expected="265113" xpath="//pageViewport[1]/page/regionViewport[1]//footnote[1]/@top-offset" />
+    <eval expected="1) The footnote from the normal block before the float." xpath="//pageViewport[1]/page/regionViewport[1]//footnote[1]/block[1]/lineArea[1]" />
+    <eval expected="2) The footnote from the list that is being wrapped around a" xpath="//pageViewport[1]/page/regionViewport[1]//footnote[1]/block[2]/lineArea[1]" />
+    <eval expected="3) The footnote from the normal block after the float." xpath="//pageViewport[1]/page/regionViewport[1]//footnote[1]/block[3]/lineArea[1]" />
+   <!-- last line in second page -->
+    <eval expected="text. Some filler text. Some filler text. Some filler text." xpath="//pageViewport[2]/page/regionViewport[1]//flow[1]/block[1]/lineArea[11]" />
+  </checks>
+</testcase>