Index: test/layoutengine/standard-testcases/block_list-block_orphans_widows.xml
===================================================================
--- test/layoutengine/standard-testcases/block_list-block_orphans_widows.xml	(revision )
+++ test/layoutengine/standard-testcases/block_list-block_orphans_widows.xml	(revision )
@@ -0,0 +1,128 @@
+<?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 the behavior of the "orphans" and "widows" properties
+      in case list-blocks are nested in blocks.
+    </p>
+  </info>
+  <fo>
+    <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
+      <fo:layout-master-set>
+        <fo:simple-page-master master-name="normal" page-width="3in" page-height="2in">
+          <fo:region-body />
+        </fo:simple-page-master>
+      </fo:layout-master-set>
+      <fo:page-sequence master-reference="normal">
+        <fo:flow flow-name="xsl-region-body">
+          <fo:block id="block-1">
+            <!-- Check that the last list-item is not unnecessarily kept together.
+                 The inner block's widows constraint causes the list-layout code
+                 to generate a merged last box, which as a single box, satisfies 
+                 the containing block's constraint.
+              -->
+            <fo:list-block>
+              <fo:list-item>
+                <fo:list-item-label><fo:block /></fo:list-item-label>
+                <fo:list-item-body>
+                  <fo:block>
+                  Lorem ipsum dolor sit amet, consectetur
+                  adipiscing elit. Cras placerat, lectus vel
+                  iaculis euismod, ipsum enim dapibus
+                  urna, eu pellentesque velit dolor ac 
+                  </fo:block>
+                </fo:list-item-body>
+              </fo:list-item>
+              <fo:list-item>
+                <fo:list-item-label><fo:block /></fo:list-item-label>
+                <fo:list-item-body>
+                  <fo:block>
+                  purus. Maecenas vitae pulvinar turpis.
+                  Duis venenatis tincidunt velit, fringilla
+                  dignissim sapien faucibus vel. Quisque
+                  placerat ornare consectetur. Aenean
+                  </fo:block>
+                </fo:list-item-body>
+              </fo:list-item>
+              <fo:list-item>
+                <fo:list-item-label><fo:block /></fo:list-item-label>
+                <fo:list-item-body>
+                  <fo:block>
+                  Lorem ipsum dolor sit amet, consectetur
+                  adipiscing elit. Cras placerat, lectus vel
+                  iaculis euismod, ipsum enim dapibus
+                  urna, eu pellentesque velit dolor ac 
+                  </fo:block>
+                </fo:list-item-body>
+              </fo:list-item>
+            </fo:list-block>
+          </fo:block>
+          <fo:block id="block-2" break-before="page">
+            <!-- Check that the first list-item is not unnecessarily kept together.
+                 The inner block's widows constraint causes the list-layout code
+                 to generate a merged first box, which as a single box, satisfies 
+                 the containing block's constraint.
+              -->
+            Lorem ipsum dolor sit amet, consectetur
+            adipiscing elit. Cras placerat, lectus vel
+            iaculis euismod, ipsum enim dapibus
+            urna, eu pellentesque velit dolor ac 
+            purus. Maecenas vitae pulvinar turpis.
+            Duis venenatis tincidunt velit, fringilla
+            dignissim sapien faucibus vel. Quisque
+            placerat ornare consectetur. Aenean
+            <fo:block id="block-2a">
+              <fo:list-block>
+                <fo:list-item>
+                <fo:list-item-label><fo:block /></fo:list-item-label>
+                  <fo:list-item-body>
+                    <fo:block>
+                    Lorem ipsum dolor sit amet, consectetur
+                    adipiscing elit. Cras placerat, lectus vel
+                    iaculis euismod, ipsum enim dapibus
+                    urna, eu pellentesque velit dolor ac 
+                    </fo:block>
+                  </fo:list-item-body>
+                </fo:list-item>
+                <fo:list-item>
+                <fo:list-item-label><fo:block /></fo:list-item-label>
+                  <fo:list-item-body>
+                    <fo:block>
+                    purus. Maecenas vitae pulvinar turpis.
+                    Duis venenatis tincidunt velit, fringilla
+                    dignissim sapien faucibus vel. Quisque
+                    placerat ornare consectetur. Aenean
+                    </fo:block>
+                  </fo:list-item-body>
+                </fo:list-item>
+              </fo:list-block>
+            </fo:block>
+          </fo:block>
+        </fo:flow>
+      </fo:page-sequence>
+    </fo:root>
+  </fo>
+  <checks>
+    <eval expected="10" xpath="count((//page)[1]//lineArea)" />
+    <eval expected="2" xpath="count((//page)[2]//lineArea)" />
+    <eval expected="10" xpath="count((//page)[3]//lineArea)" />
+    <eval expected="6" xpath="count((//page)[4]//lineArea)" />
+  </checks>
+</testcase>
Index: test/layoutengine/standard-testcases/block_table_orphans_widows.xml
===================================================================
--- test/layoutengine/standard-testcases/block_table_orphans_widows.xml	(revision )
+++ test/layoutengine/standard-testcases/block_table_orphans_widows.xml	(revision )
@@ -0,0 +1,119 @@
+<?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 the behavior of the "orphans" and "widows" properties
+      in case tables are nested in blocks.
+    </p>
+  </info>
+  <fo>
+    <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
+      <fo:layout-master-set>
+        <fo:simple-page-master master-name="normal" page-width="3in" page-height="2in">
+          <fo:region-body />
+        </fo:simple-page-master>
+      </fo:layout-master-set>
+      <fo:page-sequence master-reference="normal">
+        <fo:flow flow-name="xsl-region-body">
+          <fo:block id="block-1">
+            <!-- Check that the last row is not unnecessarily kept together.
+                 The inner block's widows constraint causes the table-layout code
+                 to generate a merged last box, which as a single box, satisfies 
+                 the containing block's constraint.
+              -->
+            <fo:table table-layout="fixed" width="100%">
+              <fo:table-column column-width="proportional-column-width(1)" />
+              <fo:table-body>
+                <fo:table-cell starts-row="true" ends-row="true">
+                  <fo:block>
+                  Lorem ipsum dolor sit amet, consectetur
+                  adipiscing elit. Cras placerat, lectus vel
+                  iaculis euismod, ipsum enim dapibus
+                  urna, eu pellentesque velit dolor ac 
+                  </fo:block>
+                </fo:table-cell>
+                <fo:table-cell starts-row="true" ends-row="true">
+                  <fo:block>
+                  purus. Maecenas vitae pulvinar turpis.
+                  Duis venenatis tincidunt velit, fringilla
+                  dignissim sapien faucibus vel. Quisque
+                  placerat ornare consectetur. Aenean
+                  </fo:block>
+                </fo:table-cell>
+                <fo:table-cell starts-row="true" ends-row="true">
+                  <fo:block>
+                  Lorem ipsum dolor sit amet, consectetur
+                  adipiscing elit. Cras placerat, lectus vel
+                  iaculis euismod, ipsum enim dapibus
+                  urna, eu pellentesque velit dolor ac 
+                  </fo:block>
+                </fo:table-cell>
+              </fo:table-body>
+            </fo:table>
+          </fo:block>
+          <fo:block id="block-2" break-before="page">
+            <!-- Check that the first row is not unnecessarily kept together.
+                 The inner block's orphans constraint causes the table-layout code
+                 to generate a merged first box, which as a single box, satisfies 
+                 the containing block's constraint.
+              -->
+            Lorem ipsum dolor sit amet, consectetur
+            adipiscing elit. Cras placerat, lectus vel
+            iaculis euismod, ipsum enim dapibus
+            urna, eu pellentesque velit dolor ac 
+            purus. Maecenas vitae pulvinar turpis.
+            Duis venenatis tincidunt velit, fringilla
+            dignissim sapien faucibus vel. Quisque
+            placerat ornare consectetur. Aenean
+            <fo:block id="block-2a">
+              <fo:table table-layout="fixed" width="100%">
+                <fo:table-column column-width="proportional-column-width(1)" />
+                <fo:table-body>
+                  <fo:table-cell starts-row="true" ends-row="true">
+                    <fo:block>
+                    Lorem ipsum dolor sit amet, consectetur
+                    adipiscing elit. Cras placerat, lectus vel
+                    iaculis euismod, ipsum enim dapibus
+                    urna, eu pellentesque velit dolor ac 
+                    </fo:block>
+                  </fo:table-cell>
+                  <fo:table-cell starts-row="true" ends-row="true">
+                    <fo:block>
+                    purus. Maecenas vitae pulvinar turpis.
+                    Duis venenatis tincidunt velit, fringilla
+                    dignissim sapien faucibus vel. Quisque
+                    placerat ornare consectetur. Aenean
+                    </fo:block>
+                  </fo:table-cell>
+                </fo:table-body>
+              </fo:table>
+            </fo:block>
+          </fo:block>
+        </fo:flow>
+      </fo:page-sequence>
+    </fo:root>
+  </fo>
+  <checks>
+    <eval expected="10" xpath="count((//page)[1]//lineArea)" />
+    <eval expected="2" xpath="count((//page)[2]//lineArea)" />
+    <eval expected="10" xpath="count((//page)[3]//lineArea)" />
+    <eval expected="6" xpath="count((//page)[4]//lineArea)" />
+  </checks>
+</testcase>
Index: test/layoutengine/standard-testcases/block_widows.xml
===================================================================
--- test/layoutengine/standard-testcases/block_widows.xml	(revision )
+++ test/layoutengine/standard-testcases/block_widows.xml	(revision )
@@ -0,0 +1,143 @@
+<?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 the default behavior of the "widows" property.
+    </p>
+  </info>
+  <fo>
+    <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
+      <fo:layout-master-set>
+        <fo:simple-page-master master-name="normal" page-width="3in" page-height="2in">
+          <fo:region-body />
+        </fo:simple-page-master>
+      </fo:layout-master-set>
+      <fo:page-sequence master-reference="normal">
+        <fo:flow flow-name="xsl-region-body">
+          <fo:block id="block-1">
+            <!-- Basic test: simple paragraph generating 11 lines.
+                 2 last lines should be kept together due to initial 
+                 value for widows
+              -->
+            Lorem ipsum dolor sit amet, consectetur
+            adipiscing elit. Cras placerat, lectus vel
+            iaculis euismod, ipsum enim dapibus
+            urna, eu pellentesque velit dolor ac 
+            purus. Maecenas vitae pulvinar turpis.
+            Duis venenatis tincidunt velit, fringilla
+            dignissim sapien faucibus vel. Quisque
+            placerat ornare consectetur. Aenean
+            dui tortor, tempor ut convallis in,
+            fermentum tempor nunc. Class aptent 
+            taciti sociosqu ad litora torquent per
+          </fo:block>
+          <fo:block id="block-2" break-before="page">
+            <!-- Basic test: simple paragraph generating 11 lines, followed by
+                 another block.
+                 A break between lines 10 and 11 is allowed.
+              -->
+            Lorem ipsum dolor sit amet, consectetur
+            adipiscing elit. Cras placerat, lectus vel
+            iaculis euismod, ipsum enim dapibus
+            urna, eu pellentesque velit dolor ac 
+            purus. Maecenas vitae pulvinar turpis.
+            Duis venenatis tincidunt velit, fringilla
+            dignissim sapien faucibus vel. Quisque
+            placerat ornare consectetur. Aenean
+            dui tortor, tempor ut convallis in,
+            fermentum tempor nunc. Class aptent 
+            taciti sociosqu ad litora torquent per
+            <fo:block>
+            Lorem ipsum dolor sit amet, consectetur
+            adipiscing elit. Cras placerat, lectus vel
+            iaculis euismod, ipsum enim dapibus
+            urna, eu pellentesque velit dolor ac
+            </fo:block>
+          </fo:block>
+          <fo:block id="block-3" break-before="page">
+            <!-- Basic test: 1 paragraph consisting of 11 single-line subparagraphs.
+                 Last 2 lines of the main paragraph should be kept together due to 
+                 initial value for widows.
+              -->
+            <fo:block>
+              <fo:block>Lorem ipsum</fo:block>
+              <fo:block>Lorem ipsum</fo:block>
+              <fo:block>Lorem ipsum</fo:block>
+              <fo:block>Lorem ipsum</fo:block>
+              <fo:block>Lorem ipsum</fo:block>
+              <fo:block>Lorem ipsum</fo:block>
+              <fo:block>Lorem ipsum</fo:block>
+              <fo:block>Lorem ipsum</fo:block>
+              <fo:block>Lorem ipsum</fo:block>
+              <fo:block>Lorem ipsum</fo:block>
+              <fo:block>Lorem ipsum</fo:block>
+            </fo:block>
+          </fo:block>
+          <fo:block id="block-4" break-before="page">
+            <!-- Special case: linefeed-treatment="preserve" (see Bugzilla 44328) -->
+            <fo:block linefeed-treatment="preserve">Lorem ipsum
+            dolor sit amet,
+            consectetur
+            adipiscing elit.
+            Cras placerat,
+            lectus vel
+            iaculis euismod,
+            ipsum enim
+            dapibus urna,
+            eu pellentesque
+            velit dolor</fo:block>
+          </fo:block>
+          <fo:block id="block-5" break-before="page">
+            <!-- Special case: 1 paragraph with 10 lines, and 1 with 1.
+                 Last 2 lines of the first paragraph should be kept
+                 together with the only line of the second due to initial
+                 value of widows on the outer block.
+              -->
+            <fo:block>
+            Lorem ipsum dolor sit amet, consectetur
+            adipiscing elit. Cras placerat, lectus vel
+            iaculis euismod, ipsum enim dapibus
+            urna, eu pellentesque velit dolor ac 
+            purus. Maecenas vitae pulvinar turpis.
+            Duis venenatis tincidunt velit, fringilla
+            dignissim sapien faucibus vel. Quisque
+            placerat ornare consectetur. Aenean
+            dui tortor, tempor ut convallis in,
+            fermentum tempor nunc. Class aptent 
+            </fo:block>
+            <fo:block>Lorem ipsum</fo:block>
+          </fo:block>
+        </fo:flow>
+      </fo:page-sequence>
+    </fo:root>
+  </fo>
+  <checks>
+    <eval expected="9" xpath="count((//page)[1]//lineArea)" />
+    <eval expected="2" xpath="count((//page)[2]//lineArea)" />
+    <eval expected="10" xpath="count((//page)[3]//lineArea)" />
+    <eval expected="5" xpath="count((//page)[4]//lineArea)" />
+    <eval expected="9" xpath="count((//page)[5]//lineArea)" />
+    <eval expected="2" xpath="count((//page)[6]//lineArea)" />
+    <eval expected="9" xpath="count((//page)[7]//lineArea)" />
+    <eval expected="2" xpath="count((//page)[8]//lineArea)" />
+    <eval expected="8" xpath="count((//page)[9]//lineArea)" />
+    <eval expected="3" xpath="count((//page)[10]//lineArea)" />
+  </checks>
+</testcase>
\ No newline at end of file
Index: test/layoutengine/standard-testcases/block_orphans.xml
===================================================================
--- test/layoutengine/standard-testcases/block_orphans.xml	(revision )
+++ test/layoutengine/standard-testcases/block_orphans.xml	(revision )
@@ -0,0 +1,167 @@
+<?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 the default behavior of the "orphans" property.
+    </p>
+  </info>
+  <fo>
+    <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
+      <fo:layout-master-set>
+        <fo:simple-page-master master-name="normal" page-width="3in" page-height="2in">
+          <fo:region-body />
+        </fo:simple-page-master>
+      </fo:layout-master-set>
+      <fo:page-sequence master-reference="normal">
+        <fo:flow flow-name="xsl-region-body">
+          <fo:block id="block-1" break-before="page">
+            <!-- Basic test: 1 paragraph with 9 lines and 1 with 4.
+                 All 4 lines of the second paragraph should be kept 
+                 together due to initial value for orphans.
+              -->
+            <fo:block>
+            Lorem ipsum dolor sit amet, consectetur
+            adipiscing elit. Cras placerat, lectus vel
+            iaculis euismod, ipsum enim dapibus
+            urna, eu pellentesque velit dolor ac 
+            purus. Maecenas vitae pulvinar turpis.
+            Duis venenatis tincidunt velit, fringilla
+            dignissim sapien faucibus vel. Quisque
+            placerat ornare consectetur. Aenean
+            dui tortor, tempor ut convallis in,
+            </fo:block>
+            <fo:block>
+            Lorem ipsum dolor sit amet, consectetur
+            adipiscing elit. Cras placerat, lectus vel
+            iaculis euismod, ipsum enim dapibus
+            urna, eu pellentesque velit dolor ac
+            </fo:block>
+          </fo:block>
+          <fo:block id="block-2" break-before="page">
+            <!-- Basic test: 1 block with 9 lines and 1 paragraph with 4 lines.
+                 A break after the first line of the second paragraph is allowed.
+              -->
+            <fo:block>
+            Lorem ipsum dolor sit amet, consectetur
+            adipiscing elit. Cras placerat, lectus vel
+            iaculis euismod, ipsum enim dapibus
+            urna, eu pellentesque velit dolor ac 
+            purus. Maecenas vitae pulvinar turpis.
+            Duis venenatis tincidunt velit, fringilla
+            dignissim sapien faucibus vel. Quisque
+            placerat ornare consectetur. Aenean
+            dui tortor, tempor ut convallis in,
+            </fo:block>
+            Lorem ipsum dolor sit amet, consectetur
+            adipiscing elit. Cras placerat, lectus vel
+            iaculis euismod, ipsum enim dapibus
+            urna, eu pellentesque velit dolor ac
+          </fo:block>
+          <fo:block id="block-3" break-before="page">
+            <!-- Basic test: 1 regular paragraph of 9 lines followed by 1 consisting 
+                 of 4 single-line subparagraphs.
+                 All 4 lines of the second paragraph should be kept together due
+                 to initial value for orphans.
+              -->
+            <fo:block id="block-3a">
+            Lorem ipsum dolor sit amet, consectetur
+            adipiscing elit. Cras placerat, lectus vel
+            iaculis euismod, ipsum enim dapibus
+            urna, eu pellentesque velit dolor ac 
+            purus. Maecenas vitae pulvinar turpis.
+            Duis venenatis tincidunt velit, fringilla
+            dignissim sapien faucibus vel. Quisque
+            placerat ornare consectetur. Aenean
+            dui tortor, tempor ut convallis in,
+            </fo:block>
+            <fo:block id="block-3b">
+              <fo:block>Lorem ipsum</fo:block>
+              <fo:block>Lorem ipsum</fo:block>
+              <fo:block>Lorem ipsum</fo:block>
+              <fo:block>Lorem ipsum</fo:block>
+            </fo:block>
+          </fo:block>
+          <fo:block id="block-4" break-before="page">
+            <!-- Special case: linefeed-treatment="preserve" (see Bugzilla 44328) -->
+            <fo:block>
+            Lorem ipsum dolor sit amet, consectetur
+            adipiscing elit. Cras placerat, lectus vel
+            iaculis euismod, ipsum enim dapibus
+            urna, eu pellentesque velit dolor ac 
+            purus. Maecenas vitae pulvinar turpis.
+            Duis venenatis tincidunt velit, fringilla
+            dignissim sapien faucibus vel. Quisque
+            placerat ornare consectetur. Aenean
+            dui tortor, tempor ut convallis in,
+            </fo:block>
+            <fo:block linefeed-treatment="preserve">Lorem ipsum
+            dolor sit amet,
+            consectetur
+            velit dolor</fo:block>
+          </fo:block>
+          <fo:block id="block-5" break-before="page" widows="1">
+            <!-- Last but not least, demonstrate peculiar side-effect in case
+                 of convoluted nesting...
+                 Even though widows would allow a break before the last line,
+                 all 10 last lines are moved to the next page due to stacked 
+                 orphans constraints
+              -->
+            <fo:block id="level-1">Lorem ipsum
+              <fo:block>Lorem ipsum</fo:block>
+              <fo:block id="level-2">Lorem ipsum
+                <fo:block id="level-3">Lorem ipsum
+                  <fo:block id="level-4">Lorem ipsum
+                    <fo:block id="level-5">Lorem ipsum
+                      <fo:block id="level-6">Lorem ipsum
+                        <fo:block id="level-7">Lorem ipsum
+                          <fo:block id="level-8">Lorem ipsum
+                            <fo:block id="level-9">Lorem ipsum
+                              <fo:block id="level-10">Lorem ipsum
+                                <fo:block id="level-11">
+                                Lorem ipsum
+                                </fo:block>
+                              </fo:block>
+                            </fo:block>
+                          </fo:block>
+                        </fo:block>
+                      </fo:block>
+                    </fo:block>
+                  </fo:block>
+                </fo:block>
+              </fo:block>
+            </fo:block>
+          </fo:block>
+        </fo:flow>
+      </fo:page-sequence>
+    </fo:root>
+  </fo>
+  <checks>
+    <eval expected="9" xpath="count((//page)[1]//lineArea)" />
+    <eval expected="4" xpath="count((//page)[2]//lineArea)" />
+    <eval expected="10" xpath="count((//page)[3]//lineArea)" />
+    <eval expected="3" xpath="count((//page)[4]//lineArea)" />
+    <eval expected="9" xpath="count((//page)[5]//lineArea)" />
+    <eval expected="4" xpath="count((//page)[6]//lineArea)" />
+    <eval expected="9" xpath="count((//page)[7]//lineArea)" />
+    <eval expected="4" xpath="count((//page)[8]//lineArea)" />
+    <eval expected="2" xpath="count((//page)[9]//lineArea)" />
+    <eval expected="10" xpath="count((//page)[10]//lineArea)" />
+  </checks>
+</testcase>
Index: src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java
===================================================================
--- src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java	(revision 1073116)
+++ src/java/org/apache/fop/layoutmgr/BlockLayoutManager.java	(revision )
@@ -66,6 +66,9 @@
     private MinOptMax effSpaceBefore;
     private MinOptMax effSpaceAfter;
 
+    private int orphans = 2;
+    private int widows = 2;
+
     /**
      * Creates a new BlockLayoutManager.
      * @param inBlock the block FO object to create the layout manager for.
@@ -97,6 +100,8 @@
                                     .getOptimum(this).getLength().getValue(this);
         adjustedSpaceAfter = fo.getCommonMarginBlock().spaceAfter.getSpace()
                                     .getOptimum(this).getLength().getValue(this);
+        orphans = fo.getOrphans();
+        widows = fo.getWidows();
     }
 
     /** {@inheritDoc} */
@@ -110,10 +115,42 @@
     public List getNextKnuthElements(LayoutContext context, int alignment, Stack lmStack,
             Position restartPosition, LayoutManager restartAtLM) {
         resetSpaces();
-        return super.getNextKnuthElements(
+
+        List<ListElement> contentList = super.getNextKnuthElements(
                 context, alignment, lmStack, restartPosition, restartAtLM);
+
+        if (!this.hasNextChildLM()) {
+            // handle widows
+            int lineCount = 0, boxCount = 0, index = contentList.size();
+            ListElement current;
+            for (ListIterator<ListElement> it = contentList.listIterator(contentList.size());
+                    it.hasPrevious();) {
+                current = it.previous();
+                index--;
+                if (current.isBox() && !((KnuthBox) current).isAuxiliary()) {
+                    boxCount++;
+                    // non-auxiliary box => increase lineCount
+                    if (current instanceof KnuthBlockBox) {
+                        lineCount += ((KnuthBlockBox) current).getLineCount();
+                    } else {
+                        // assume one line
+                        lineCount++;
-    }
+                    }
+                    if (lineCount >= widows) {
+                        break;
+                    }
+                }
+            }
+            // if the sublist only consists of boxes, nothing to remove
+            if (index <= (contentList.size() - boxCount)) {
+                ElementListUtils.removeLegalBreaks(
+                        contentList.subList(index, contentList.size()));
+            }
+        }
 
+        return contentList;
+    }
+
     /**
      * Overridden to take into account that the childLM may be the block's
      * {@link LineLayoutManager}.
@@ -132,25 +169,77 @@
             // nop; will have been properly set by makeChildLayoutContext()
         }
 
-        if (childLM == this.childLMs.get(0)) {
+        boolean isFirst = childLM == this.childLMs.get(0);
+        if (isFirst) {
             childLC.setFlags(LayoutContext.SUPPRESS_BREAK_BEFORE);
             //Handled already by the parent (break collapsing, see above)
         }
 
+        List<ListElement> childElements;
         if (lmStack == null) {
-            return childLM.getNextKnuthElements(childLC, alignment);
+            childElements = childLM.getNextKnuthElements(childLC, alignment);
         } else {
             if (childLM instanceof LineLayoutManager) {
                 assert (restartPosition instanceof LeafPosition);
-                return ((LineLayoutManager) childLM).getNextKnuthElements(childLC, alignment,
+                childElements
+                        = ((LineLayoutManager) childLM).getNextKnuthElements(childLC, alignment,
-                        (LeafPosition) restartPosition);
+                            (LeafPosition) restartPosition);
             } else {
-                return childLM.getNextKnuthElements(childLC, alignment,
+                childElements = childLM.getNextKnuthElements(childLC, alignment,
                         lmStack, restartPosition, restartAtLM);
             }
         }
+
+        if (isFirst) {
+            // handle orphans
+            int lineCount = 0, boxCount = 0, endIndex = 0;
+            ListElement current;
+            for (ListIterator<ListElement> it = childElements.listIterator(); it.hasNext();) {
+                current = it.next();
+                endIndex++;
+                if (current.isBox() && !((KnuthBox) current).isAuxiliary()) {
+                    boxCount++;
+                    // non-auxiliary box => increase lineCount
+                    if (current instanceof KnuthBlockBox) {
+                        lineCount += ((KnuthBlockBox) current).getLineCount();
+                    } else {
+                        // assume one line
+                        lineCount++;
-    }
+                    }
+                    if (lineCount >= orphans) {
+                        break;
+                    }
+                }
+            }
+            // if the sublist only consists of boxes, nothing to remove
+            if (endIndex > boxCount) {
+                ElementListUtils.removeLegalBreaks(childElements.subList(0, endIndex));
+            }
+        }
 
+        return childElements;
+    }
+
+    /**
+     * Overridden to deal with a special case for the "orphans" property.
+     * {@inheritDoc}
+     */
+    @Override
+    protected void addInBetweenBreak(List<ListElement> contentList,
+                                     LayoutContext parentLC, LayoutContext childLC) {
+
+        if (this.childLMs.size() > 1
+                && this.curChildLM == this.childLMs.get(1)) {
+            // special case: second childLM; if the first childLM did not produce enough
+            // lines to satisfy this LM's orphans constraint, avoid adding a break possibility
+            if (ElementListUtils.getLineCount(contentList) < orphans) {
+                return;
+            }
+        }
+
+        super.addInBetweenBreak(contentList, parentLC, childLC);
+    }
+
     private void resetSpaces() {
         this.discardBorderBefore = false;
         this.discardBorderAfter = false;
Index: src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java
===================================================================
--- src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java	(revision 1088079)
+++ src/java/org/apache/fop/layoutmgr/inline/LineLayoutManager.java	(revision )
@@ -918,10 +918,7 @@
                 for (int i = 0;
                         i < llPoss.getChosenLineCount();
                         i++) {
-                    if (returnList.size() > 0
-                            && i > 0 //if i==0 break generated above already
-                            && i >= fobj.getOrphans()
-                            && i <= llPoss.getChosenLineCount() - fobj.getWidows()) {
+                    if (returnList.size() > 0 && i > 0) {
                         // penalty allowing a page break between lines
                         Keep keep = getKeepTogether();
                         returnList.add(new BreakElement(
Index: src/java/org/apache/fop/layoutmgr/table/TableStepper.java
===================================================================
--- src/java/org/apache/fop/layoutmgr/table/TableStepper.java	(revision 1083863)
+++ src/java/org/apache/fop/layoutmgr/table/TableStepper.java	(revision )
@@ -181,6 +181,7 @@
         TableContentPosition lastTCPos = null;
         LinkedList returnList = new LinkedList();
         int laststep = 0;
+        int stepLines;
         int step = getFirstStep();
         do {
             int maxRemainingHeight = getMaxRemainingHeight();
@@ -201,10 +202,15 @@
             LinkedList footnoteList = new LinkedList();
             //Put all involved grid units into a list
             List cellParts = new java.util.ArrayList(columnCount);
+            stepLines = 0;
             for (Iterator iter = activeCells.iterator(); iter.hasNext();) {
                 ActiveCell activeCell = (ActiveCell) iter.next();
                 CellPart part = activeCell.createCellPart();
                 cellParts.add(part);
+                int partLines = part.getLineCount();
+                if (partLines > stepLines) {
+                    stepLines = partLines;
+                }
                 activeCell.addFootnotes(footnoteList);
             }
 
@@ -219,12 +225,15 @@
             }
             lastTCPos = tcpos;
 
+            KnuthBlockBox newBox;
             // TODO TableStepper should remain as footnote-agnostic as possible
             if (footnoteList.isEmpty()) {
-                returnList.add(new KnuthBox(boxLen, tcpos, false));
+                newBox = new KnuthBlockBox(boxLen, tcpos, false);
             } else {
-                returnList.add(new KnuthBlockBox(boxLen, footnoteList, tcpos, false));
+                newBox = new KnuthBlockBox(boxLen, footnoteList, tcpos, false);
             }
+            newBox.setLineCount(stepLines);
+            returnList.add(newBox);
 
             int effPenaltyLen = Math.max(0, penaltyOrGlueLen);
             TableHFPenaltyPosition penaltyPos = new TableHFPenaltyPosition(getTableLM());
Index: src/java/org/apache/fop/layoutmgr/KnuthBlockBox.java
===================================================================
--- src/java/org/apache/fop/layoutmgr/KnuthBlockBox.java	(revision 893238)
+++ src/java/org/apache/fop/layoutmgr/KnuthBlockBox.java	(revision )
@@ -19,6 +19,7 @@
 
 package org.apache.fop.layoutmgr;
 
+import java.util.Collections;
 import java.util.LinkedList;
 import java.util.List;
 
@@ -35,54 +36,66 @@
      * it isn't possible to get the opt value stored in a MinOptMax object.
      */
     private int bpd;
-    private List footnoteList;
+    private List<FootnoteBodyLayoutManager> footnoteList;
     /** List of Knuth elements. This is a list of LinkedList elements. */
-    private List elementLists = null;
+    private List<List<ListElement>> elementLists;
+    private int lineCount;
 
     /**
      * Creates a new box.
      *
      * @param width     block progression dimension of this box
+     * @param pos       the Position stored in this box
+     * @param auxiliary is this box auxiliary?
+     */
+    public KnuthBlockBox(int width, Position pos, boolean auxiliary) {
+        super(width, pos, auxiliary);
+        // assume one line by default, if the box is not auxiliary
+        this.lineCount = (auxiliary ? 0 : 1);
+    }
+
+    /**
+     * Creates a new box.
+     *
+     * @param width     block progression dimension of this box
      * @param range     min, opt, max inline progression dimension of this box
      * @param bpdim     natural width of the line represented by this box.
      * @param pos       the Position stored in this box
      * @param auxiliary is this box auxiliary?
      */
     public KnuthBlockBox(int width, MinOptMax range, int bpdim, Position pos, boolean auxiliary) {
-        super(width, pos, auxiliary);
-        ipdRange = range;
-        bpd = bpdim;
-        footnoteList = new LinkedList();
+        this(width, pos, auxiliary);
+        this.ipdRange = range;
+        this.bpd = bpdim;
     }
 
     /**
      * Creates a new box.
      *
      * @param width     block progression dimension of this box
-     * @param list      footnotes cited by elements in this box. The list contains the corresponding
-     *                  FootnoteBodyLayoutManagers
+     * @param footnoteList      footnotes cited by elements in this box.
+     *                  The list contains the corresponding FootnoteBodyLayoutManagers
      * @param pos       the Position stored in this box
      * @param auxiliary is this box auxiliary?
      */
-    public KnuthBlockBox(int width, List list, Position pos, boolean auxiliary) {
-        super(width, pos, auxiliary);
-        ipdRange = MinOptMax.ZERO;
-        bpd = 0;
-        footnoteList = new LinkedList(list);
+    public KnuthBlockBox(int width, List footnoteList, Position pos, boolean auxiliary) {
+        this(width, MinOptMax.ZERO, 0, pos, auxiliary);
+        this.footnoteList = new LinkedList<FootnoteBodyLayoutManager>(footnoteList);
     }
 
     /**
      * @return the LMs for the footnotes cited in this box.
      */
-    public List getFootnoteBodyLMs() {
-        return footnoteList;
+    public List<FootnoteBodyLayoutManager> getFootnoteBodyLMs() {
+        return (footnoteList == null
+                ? Collections.<FootnoteBodyLayoutManager>emptyList() : footnoteList);
     }
 
     /**
      * @return true if this box contains footnote citations.
      */
     public boolean hasAnchors() {
-        return (footnoteList.size() > 0);
+        return (footnoteList != null && footnoteList.size() > 0);
     }
 
     /**
@@ -92,7 +105,7 @@
      */
     public void addElementList(List list) {
         if (elementLists == null) {
-            elementLists = new LinkedList();
+            elementLists = new LinkedList<List<ListElement>>();
         }
         elementLists.add(list);
     }
@@ -122,4 +135,21 @@
     public int getBPD() {
         return bpd;
     }
+
+    /**
+     * Returns the (maximum) number of lines in this box.
+     * @return the maximum number of lines contained in this box.
+     */
+    public int getLineCount() {
+        return lineCount;
-}
+    }
+
+    /**
+     * Sets the maximum number of lines in this box.
+     * @param lineCount the number of lines
+     */
+    public void setLineCount(int lineCount) {
+        this.lineCount = lineCount;
+    }
+
+}
Index: src/java/org/apache/fop/layoutmgr/table/CellPart.java
===================================================================
--- src/java/org/apache/fop/layoutmgr/table/CellPart.java	(revision 990144)
+++ src/java/org/apache/fop/layoutmgr/table/CellPart.java	(revision )
@@ -20,6 +20,7 @@
 package org.apache.fop.layoutmgr.table;
 
 import org.apache.fop.fo.flow.table.PrimaryGridUnit;
+import org.apache.fop.layoutmgr.ElementListUtils;
 
 /**
  * Represents a non-divisible part of a grid unit. Used by the table stepper.
@@ -117,6 +118,10 @@
         return condAfterContentLength;
     }
 
+    int getLineCount() {
+        return ElementListUtils.getLineCount(pgu.getElements().subList(start, end + 1));
+    }
+
     /** {@inheritDoc} */
     public String toString() {
         StringBuffer sb = new StringBuffer("Part: ");
Index: src/java/org/apache/fop/layoutmgr/list/ListItemLayoutManager.java
===================================================================
--- src/java/org/apache/fop/layoutmgr/list/ListItemLayoutManager.java	(revision 1069941)
+++ src/java/org/apache/fop/layoutmgr/list/ListItemLayoutManager.java	(revision )
@@ -316,6 +316,7 @@
             // footnote-agnostic as possible
             LinkedList<FootnoteBodyLayoutManager> footnoteList = null;
             ListElement el;
+            int stepLines = 0;
             for (int i = 0; i < elementLists.length; i++) {
                 for (int j = start[i]; j <= end[i]; j++) {
                     el = (ListElement) elementLists[i].get(j);
@@ -326,17 +327,25 @@
                         footnoteList.addAll(((KnuthBlockBox) el).getFootnoteBodyLMs());
                     }
                 }
+                int lineCount = ElementListUtils.getLineCount(
+                        elementLists[i].subList(start[i], end[i] + 1));
+                if (lineCount > stepLines) {
+                    stepLines = lineCount;
-            }
+                }
+            }
 
             // add the new elements
             addedBoxHeight += boxHeight;
             ListItemPosition stepPosition = new ListItemPosition(this,
                     start[0], end[0], start[1], end[1]);
+            KnuthBlockBox newBox;
             if (footnoteList == null) {
-                returnList.add(new KnuthBox(boxHeight, stepPosition, false));
+                newBox = new KnuthBlockBox(boxHeight, stepPosition, false);
             } else {
-                returnList.add(new KnuthBlockBox(boxHeight, footnoteList, stepPosition, false));
+                newBox = new KnuthBlockBox(boxHeight, footnoteList, stepPosition, false);
             }
+            newBox.setLineCount(stepLines);
+            returnList.add(newBox);
 
             if (addedBoxHeight < totalHeight) {
                 Keep keep = keepWithNextActive.compare(getKeepTogether());
@@ -694,6 +703,5 @@
         body.reset();
     }
 
-
 }
 
Index: src/java/org/apache/fop/layoutmgr/KnuthPenalty.java
===================================================================
--- src/java/org/apache/fop/layoutmgr/KnuthPenalty.java	(revision 1079013)
+++ src/java/org/apache/fop/layoutmgr/KnuthPenalty.java	(revision )
@@ -46,6 +46,9 @@
     /** Dummy, zero-width penalty */
     public static final KnuthPenalty DUMMY_ZERO_PENALTY
             = new KnuthPenalty(0, 0, false, null, true);
+    /** Dummy break inhibitor */
+    public static final KnuthPenalty DUMMY_INFINITE_PENALTY
+            = new KnuthPenalty(0, KnuthElement.INFINITE, false, null, true);
 
     private int penalty;
     private boolean penaltyFlagged;
Index: src/java/org/apache/fop/layoutmgr/ElementListUtils.java
===================================================================
--- src/java/org/apache/fop/layoutmgr/ElementListUtils.java	(revision 1056513)
+++ src/java/org/apache/fop/layoutmgr/ElementListUtils.java	(revision )
@@ -133,6 +133,87 @@
     }
 
     /**
+     * Removes all legal break points from the given {@code List<ListElement>}.
+     * That is, this method:<br/>
+     * <ul>
+     *   <li>removes penalties in between two boxes</li>
+     *   <li>converts other penalties to inhibit breaks</li>
+     *   <li>converts glues following a box into auxiliary boxes
+     *       or penalty-glue sequences</li>
+     * </ul>
+     * <br/>
+     * <em>Note: leading glues will not be treated, as it is assumed nothing precedes
+     * the first element of the given list. Similarly, trailing penalties would just be set
+     * to {@link KnuthElement#INFINITE}, as there is never a following box.<br/>
+     * Care should be taken to provide as much context elements as required. Ideally, the
+     * list should start with a box and end with a box or glue.</em>
+     *
+     * @param elements  the element list from which the breaks will be removed
+     */
+    public static void removeLegalBreaks(List<ListElement> elements) {
+
+        ListElement current;
+        boolean previousIsBox = false;
+
+        for (ListIterator<ListElement> it = elements.listIterator(); it.hasNext();) {
+
+            current = it.next();
+
+            if (current.isBox()) {
+                previousIsBox = true;
+                continue;
+            } else if (current.isGlue() && previousIsBox) {
+                KnuthGlue glue = (KnuthGlue)current;
+                if (glue.getStretch() == 0 && glue.getShrink() == 0) {
+                    // non-stretchable glue => replace with a box of the same width
+                    it.set(new KnuthBox(glue.getWidth(), glue.getPosition(), true));
+                } else {
+                    // stretchable glue => add break-inhibitor
+                    it.previous();
+                    it.add(KnuthPenalty.DUMMY_INFINITE_PENALTY);
+                    it.next();
+                }
+            } else if (current.isPenalty() || current instanceof BreakElement
+                        && !current.isForcedBreak()) {
+                boolean nextIsBox = (it.hasNext() && it.next().isBox());
+                it.previous();
+                if (previousIsBox && nextIsBox) {
+                    // penalty or BreakElement in between boxes => remove
+                    it.previous();
+                    it.remove();
+                } else {
+                    if (current.isPenalty()) {
+                        ((KnuthPenalty)current).setPenalty(KnuthElement.INFINITE);
+                    } else {
+                        ((BreakElement)current).setPenaltyValue(KnuthElement.INFINITE);
+                    }
+                }
+            }
+            previousIsBox = false;
+        }
+    }
+
+    /**
+     * Obtains the (maximum) number of lines in the given list.
+     * @param elements  the list to count the lines for
+     * @return  the number of lines
+     */
+    public static int getLineCount(List<ListElement> elements) {
+        int lineCount = 0;
+        for (ListElement current : elements) {
+            if (current.isBox() && !((KnuthBox) current).isAuxiliary()) {
+                if (current instanceof KnuthBlockBox) {
+                    lineCount += ((KnuthBlockBox) current).getLineCount();
+                } else {
+                    // assume one line
+                    lineCount++;
+                }
+            }
+        }
+        return lineCount;
+    }
+
+    /**
      * Calculates the content length of the given element list. Warning: It doesn't take any
      * stretch and shrink possibilities into account.
      * @param elems the element list
