Index: src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java
===================================================================
--- src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java	(revision 1526306)
+++ src/java/org/apache/fop/layoutmgr/PageBreakingAlgorithm.java	(working copy)
@@ -140,7 +140,10 @@
      */
     protected class KnuthPageNode extends KnuthNode {
 
-        /** Additional length due to footnotes. */
+        /** Additional length due to already inserted footnotes. */
+        public int insertedFootnotes;
+
+        /** Total length of the footnotes. */
         public int totalFootnotes;
 
         /** Index of the last inserted footnote. */
@@ -152,7 +155,8 @@
         public KnuthPageNode(int position,
                              int line, int fitness,
                              int totalWidth, int totalStretch, int totalShrink,
-                             int totalFootnotes, int footnoteListIndex, int footnoteElementIndex,
+                             int insertedFootnotes, int totalFootnotes,
+                             int footnoteListIndex, int footnoteElementIndex,
                              double adjustRatio, int availableShrink, int availableStretch,
                              int difference, double totalDemerits, KnuthNode previous) {
             super(position, line, fitness,
@@ -160,6 +164,7 @@
                   adjustRatio, availableShrink, availableStretch,
                   difference, totalDemerits, previous);
             this.totalFootnotes = totalFootnotes;
+            this.insertedFootnotes = insertedFootnotes;
             this.footnoteListIndex = footnoteListIndex;
             this.footnoteElementIndex = footnoteElementIndex;
         }
@@ -172,7 +177,8 @@
      */
     protected class BestPageRecords extends BestRecords {
 
-        private int[] bestFootnotesLength = new int[4];
+        private int[] bestInsertedFootnotesLength = new int[4];
+        private int[] bestTotalFootnotesLength = new int[4];
         private int[] bestFootnoteListIndex = new int[4];
         private int[] bestFootnoteElementIndex = new int[4];
 
@@ -182,15 +188,20 @@
             super.addRecord(demerits, node, adjust,
                             availableShrink, availableStretch,
                             difference, fitness);
-            bestFootnotesLength[fitness] = insertedFootnotesLength;
+            bestInsertedFootnotesLength[fitness] = insertedFootnotesLength;
+            bestTotalFootnotesLength[fitness] = totalFootnotesLength;
             bestFootnoteListIndex[fitness] = footnoteListIndex;
             bestFootnoteElementIndex[fitness] = footnoteElementIndex;
         }
 
-        public int getFootnotesLength(int fitness) {
-            return bestFootnotesLength[fitness];
+        public int getInsertedFootnotesLength(int fitness) {
+            return bestInsertedFootnotesLength[fitness];
         }
 
+        public int getTotalFootnotesLength(int fitness) {
+            return bestTotalFootnotesLength[fitness];
+        }
+
         public int getFootnoteListIndex(int fitness) {
             return bestFootnoteListIndex[fitness];
         }
@@ -287,7 +298,8 @@
                                    int difference, double totalDemerits, KnuthNode previous) {
         return new KnuthPageNode(position, line, fitness,
                                  totalWidth, totalStretch, totalShrink,
-                                 insertedFootnotesLength, footnoteListIndex, footnoteElementIndex,
+                                 insertedFootnotesLength, totalFootnotesLength,
+                                 footnoteListIndex, footnoteElementIndex,
                                  adjustRatio, availableShrink, availableStretch,
                                  difference, totalDemerits, previous);
     }
@@ -298,7 +310,8 @@
                                    int totalWidth, int totalStretch, int totalShrink) {
         return new KnuthPageNode(position, line, fitness,
                                  totalWidth, totalStretch, totalShrink,
-                                 ((BestPageRecords) best).getFootnotesLength(fitness),
+                                 ((BestPageRecords) best).getInsertedFootnotesLength(fitness),
+                                 ((BestPageRecords) best).getTotalFootnotesLength(fitness),
                                  ((BestPageRecords) best).getFootnoteListIndex(fitness),
                                  ((BestPageRecords) best).getFootnoteElementIndex(fitness),
                                  best.getAdjust(fitness), best.getAvailableShrink(fitness),
@@ -405,6 +418,10 @@
                     resetFootnotes(((KnuthBlockBox) resetElement).getElementLists());
                 }
             }
+            footnoteElementIndex = ((KnuthPageNode) restartingNode).footnoteElementIndex;
+            footnoteListIndex = ((KnuthPageNode) restartingNode).footnoteListIndex;
+            totalFootnotesLength = ((KnuthPageNode) restartingNode).totalFootnotes;
+            insertedFootnotesLength = ((KnuthPageNode) restartingNode).insertedFootnotes;
         }
         return returnValue;
     }
@@ -413,13 +430,6 @@
         for (int i = 0; i < elementLists.size(); i++) {
             ListUtil.removeLast(footnotesList);
             ListUtil.removeLast(lengthList);
-
-            // update totalFootnotesLength
-            if (!lengthList.isEmpty()) {
-                totalFootnotesLength = ListUtil.getLast(lengthList);
-            } else {
-                totalFootnotesLength = 0;
-            }
         }
         // update footnotesPending;
         if (footnotesList.size() == 0) {
@@ -502,7 +512,7 @@
         }
         if (footnotesPending) {
             // compute the total length of the footnotes not yet inserted
-            int allFootnotes = totalFootnotesLength - pageNode.totalFootnotes;
+            int allFootnotes = totalFootnotesLength - pageNode.insertedFootnotes;
             if (allFootnotes > 0) {
                 // this page contains some footnote citations
                 // add the footnote separator width
@@ -511,7 +521,7 @@
                     // there is enough space to insert all footnotes:
                     // add the whole allFootnotes length
                     actualWidth += allFootnotes;
-                    insertedFootnotesLength = pageNode.totalFootnotes + allFootnotes;
+                    insertedFootnotesLength = pageNode.insertedFootnotes + allFootnotes;
                     footnoteListIndex = footnotesList.size() - 1;
                     footnoteElementIndex
                         = getFootnoteList(footnoteListIndex).size() - 1;
@@ -528,7 +538,7 @@
                     //    this is the first feasible break; in this case it is allowed
                     //    to break and defer, if necessary, old and new footnotes
                     actualWidth += footnoteSplit;
-                    insertedFootnotesLength = pageNode.totalFootnotes + footnoteSplit;
+                    insertedFootnotesLength = pageNode.insertedFootnotes + footnoteSplit;
                     // footnoteListIndex has been set in getFootnoteSplit()
                     // footnoteElementIndex has been set in getFootnoteSplit()
                 } else {
@@ -538,7 +548,7 @@
                     // that cannot be broken:
                     // add the whole allFootnotes length, so this breakpoint will be discarded
                     actualWidth += allFootnotes;
-                    insertedFootnotesLength = pageNode.totalFootnotes + allFootnotes;
+                    insertedFootnotesLength = pageNode.insertedFootnotes + allFootnotes;
                     footnoteListIndex = footnotesList.size() - 1;
                     footnoteElementIndex
                         = getFootnoteList(footnoteListIndex).size() - 1;
@@ -569,7 +579,7 @@
     private boolean canDeferOldFootnotes(KnuthPageNode node, int contentElementIndex) {
         return (noBreakBetween(node.position, contentElementIndex)
                 && deferredFootnotes(node.footnoteListIndex,
-                        node.footnoteElementIndex, node.totalFootnotes));
+                        node.footnoteElementIndex, node.insertedFootnotes));
     }
 
     /**
@@ -635,7 +645,7 @@
                  && firstNewFootnoteIndex != 0
                  && (listIndex < firstNewFootnoteIndex - 1
                      || elementIndex < getFootnoteList(listIndex).size() - 1))
-                || length < totalFootnotesLength);
+                || length < insertedFootnotesLength);
     }
 
     /**
@@ -649,7 +659,7 @@
                 boolean canDeferOldFootnotes) {
         return getFootnoteSplit(activeNode.footnoteListIndex,
                                 activeNode.footnoteElementIndex,
-                                activeNode.totalFootnotes,
+                                activeNode.insertedFootnotes,
                                 availableLength, canDeferOldFootnotes);
     }
 
@@ -714,10 +724,8 @@
             int prevIndex = -1;
             int index = -1;
 
-            while (!(somethingAdded && splitLength > availableLength)) {
-                if (!somethingAdded) {
-                    somethingAdded = true;
-                } else {
+            while (splitLength <= availableLength) {
+                if (somethingAdded) {
                     prevSplitLength = splitLength;
                     prevIndex = index;
                 }
@@ -733,6 +741,10 @@
                         // element is a box
                         splitLength += element.getWidth();
                         boxPreceding = true;
+                        if (splitLength > prevSplitLength) {
+                            // and it is non-empty
+                            somethingAdded = true;
+                        }
                     } else if (element.isGlue()) {
                         // element is a glue
                         if (boxPreceding) {
@@ -749,6 +761,7 @@
                             index = noteListIterator.previousIndex();
                             break;
                         }
+                        boxPreceding = false;
                     }
                 }
             }
@@ -758,7 +771,6 @@
             // page here
             // if prevSplitLength is > 0 we can insert some footnote content in this page
             // and insert the remaining in the following one
-            //TODO: check this conditional, as the first one is always false...?
             if (!somethingAdded) {
                 // there was not enough space to add a piece of the first new footnote
                 // this is not a good break
@@ -781,7 +793,7 @@
         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) {
+            if (((KnuthPageNode) activeNode).insertedFootnotes < totalFootnotesLength) {
                 maxAdjustment += footnoteSeparatorLength.getStretch();
             }
             if (maxAdjustment > 0) {
@@ -792,7 +804,7 @@
         } 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) {
+            if (((KnuthPageNode) activeNode).insertedFootnotes < totalFootnotesLength) {
                 maxAdjustment += footnoteSeparatorLength.getShrink();
             }
             if (maxAdjustment > 0) {
@@ -866,7 +878,7 @@
             for (KnuthPageNode node = (KnuthPageNode) getNode(i);
                  node != null;
                  node = (KnuthPageNode) node.next) {
-                if (node.totalFootnotes < totalFootnotesLength) {
+                if (node.insertedFootnotes < totalFootnotesLength) {
                     // layout remaining footnote bodies
                     createFootnotePages(node);
                 }
@@ -876,7 +888,7 @@
 
     private void createFootnotePages(KnuthPageNode lastNode) {
 
-        insertedFootnotesLength = lastNode.totalFootnotes;
+        insertedFootnotesLength = lastNode.insertedFootnotes;
         footnoteListIndex = lastNode.footnoteListIndex;
         footnoteElementIndex = lastNode.footnoteElementIndex;
         int availableBPD = getLineWidth(lastNode.line);
@@ -902,7 +914,7 @@
                 // cannot add any content: create a new node and start again
                 KnuthPageNode node = (KnuthPageNode)
                                      createNode(lastNode.position, prevNode.line + 1, 1,
-                                                insertedFootnotesLength - prevNode.totalFootnotes,
+                                                insertedFootnotesLength - prevNode.insertedFootnotes,
                                                 0, 0,
                                                 0, 0, 0,
                                                 0, 0, prevNode);
@@ -916,7 +928,7 @@
         // create the last node
         KnuthPageNode node = (KnuthPageNode)
                              createNode(lastNode.position, prevNode.line + 1, 1,
-                                        totalFootnotesLength - prevNode.totalFootnotes, 0, 0,
+                                        totalFootnotesLength - prevNode.insertedFootnotes, 0, 0,
                                         0, 0, 0,
                                         0, 0, prevNode);
         addNode(node.line, node);
Index: test/layoutengine/standard-testcases/footnote_jira1749.xml
===================================================================
--- test/layoutengine/standard-testcases/footnote_jira1749.xml	(revision 0)
+++ test/layoutengine/standard-testcases/footnote_jira1749.xml	(working copy)
@@ -0,0 +1,55 @@
+<?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 verifies the issue described in FOP-1749: footnotes with
+      margin-top="..." that do not fit on the current page, but would've fit
+      without top margin cause FOP to hang (instead of being pushed
+      to the next page).
+    </p>
+  </info>
+  <fo>
+    <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:fox="http://xml.apache.org/fop/extensions">
+      <fo:layout-master-set>
+        <fo:simple-page-master page-height="50pt" page-width="240pt" master-name="Body">
+          <fo:region-body/>
+        </fo:simple-page-master>
+      </fo:layout-master-set>
+      <fo:page-sequence master-reference="Body">
+        <fo:flow flow-name="xsl-region-body" font-size="10pt">
+          <fo:block>a</fo:block>
+          <fo:block>b
+            <fo:footnote>
+              <fo:inline/>
+              <fo:footnote-body>
+                <fo:block margin-top="20pt">X</fo:block>
+              </fo:footnote-body>
+            </fo:footnote>
+          </fo:block>
+        </fo:flow>
+      </fo:page-sequence>
+    </fo:root>
+  </fo>
+  <checks>
+    <!-- The block with footnote reference is on page 2 -->
+    <eval expected="b" xpath="//pageViewport[2]//mainReference//word[1]"/>
+    <eval expected="X" xpath="//pageViewport[2]//footnote//word[1]"/>
+  </checks>
+</testcase>
Index: test/layoutengine/standard-testcases/footnote_jira2106_1.xml
===================================================================
--- test/layoutengine/standard-testcases/footnote_jira2106_1.xml	(revision 0)
+++ test/layoutengine/standard-testcases/footnote_jira2106_1.xml	(working copy)
@@ -0,0 +1,50 @@
+<?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 verifies the issue described in FOP-2106: footnote must
+      be positioned at the same page as the inline reference (not on the
+      page before).
+    </p>
+  </info>
+  <fo>
+    <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" font-family="serif" font-size="10pt">
+      <fo:layout-master-set>
+        <fo:simple-page-master master-name="body" page-width="100pt" page-height="35pt">
+          <fo:region-body/>
+        </fo:simple-page-master>
+      </fo:layout-master-set>
+      <fo:page-sequence master-reference="body">
+        <fo:flow flow-name="xsl-region-body">
+          <fo:block space-before.optimum="1em" space-before.minimum="0.8em" space-before.maximum="1.2em">publisher</fo:block>
+          <fo:block space-before.optimum="1em" space-before.minimum="0.8em" space-before.maximum="1.2em">access</fo:block>
+          <fo:block space-before.optimum="1em" space-before.minimum="0.8em" space-before.maximum="1.2em">are</fo:block>
+          <fo:block space-before.optimum="1em" space-before.minimum="0.8em" space-before.maximum="1.2em">William<fo:footnote><fo:inline baseline-shift="super" font-size="50%">1</fo:inline><fo:footnote-body><fo:block font-size="6pt">Footnote one page early</fo:block></fo:footnote-body></fo:footnote></fo:block>
+        </fo:flow>
+      </fo:page-sequence>
+    </fo:root>
+  </fo>
+  <checks>
+    <!-- The block with footnote reference is on page 3 -->
+    <eval expected="William" xpath="//pageViewport[3]//mainReference//word[1]"/>
+    <!-- ... and so is the footnote itself -->
+    <eval expected="Footnote" xpath="//pageViewport[3]//footnote//word[1]"/>
+  </checks>
+</testcase>
Index: test/layoutengine/standard-testcases/footnote_jira2106_2.xml
===================================================================
--- test/layoutengine/standard-testcases/footnote_jira2106_2.xml	(revision 0)
+++ test/layoutengine/standard-testcases/footnote_jira2106_2.xml	(working copy)
@@ -0,0 +1,56 @@
+<?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 verifies the 2nd issue described in FOP-2106: footnotes
+      broken to the next page.
+     </p>
+  </info>
+  <fo>
+    <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
+      <fo:layout-master-set>
+        <fo:simple-page-master master-name="page"
+          page-height="55pt" page-width="200pt">
+          <fo:region-body/>
+        </fo:simple-page-master>
+      </fo:layout-master-set>
+      <fo:page-sequence master-reference="page">
+        <fo:flow flow-name="xsl-region-body" font-size="8pt" line-height="10pt">
+          <fo:block>Line_1</fo:block>
+          <fo:block>Line_2</fo:block>
+          <fo:block>Line_3<fo:footnote>
+              <fo:inline>*</fo:inline>
+              <fo:footnote-body>
+                <fo:block>Footnote_line_1_of_3</fo:block>
+                <fo:block>Footnote_line_2_of_3</fo:block>
+                <fo:block>Footnote_line_3_of_3</fo:block>
+              </fo:footnote-body>
+          </fo:footnote></fo:block>
+          <fo:block>Line_4</fo:block>
+        </fo:flow>
+      </fo:page-sequence>
+    </fo:root>
+  </fo>
+  <checks>
+    <eval expected="Footnote_line_1_of_3" xpath="//pageViewport[1]//footnote[1]/block[1]//word[1]"/>
+    <eval expected="Footnote_line_2_of_3" xpath="//pageViewport[1]//footnote[1]/block[2]//word[1]"/>
+    <eval expected="Footnote_line_3_of_3" xpath="//pageViewport[2]//footnote[1]/block[1]//word[1]"/>
+  </checks>
+</testcase>
