]> source.dussan.org Git - xmlgraphics-fop.git/commitdiff
Implemented limited support for extension properties through new methods on ElementMa...
authorJeremias Maerki <jeremias@apache.org>
Mon, 11 Sep 2006 18:24:35 +0000 (18:24 +0000)
committerJeremias Maerki <jeremias@apache.org>
Mon, 11 Sep 2006 18:24:35 +0000 (18:24 +0000)
Moved block-progression-unit into the fox: namespace.
Implemented new extension properties: fox:orphan-content-limit and fox:widow-content-limit for fo:table and fo:list-block. See documentation for details.
Bugfix in ElementListUtils.removeLegalBreaks (concerning box/glue combinations). Added a unit test to cover the problem.

git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@442282 13f79535-47bb-0310-9956-ffa450edef68

22 files changed:
src/documentation/content/xdocs/trunk/extensions.xml
src/java/org/apache/fop/fo/Constants.java
src/java/org/apache/fop/fo/ElementMapping.java
src/java/org/apache/fop/fo/ElementMappingRegistry.java
src/java/org/apache/fop/fo/FOElementMapping.java
src/java/org/apache/fop/fo/FOPropertyMapping.java
src/java/org/apache/fop/fo/FObj.java
src/java/org/apache/fop/fo/PropertyList.java
src/java/org/apache/fop/fo/extensions/ExtensionElementMapping.java
src/java/org/apache/fop/fo/extensions/svg/SVGElementMapping.java
src/java/org/apache/fop/fo/flow/ListBlock.java
src/java/org/apache/fop/fo/flow/Table.java
src/java/org/apache/fop/layoutmgr/ElementListUtils.java
src/java/org/apache/fop/layoutmgr/list/ListBlockLayoutManager.java
src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java
status.xml
test/java/org/apache/fop/util/ElementListUtilsTestCase.java [new file with mode: 0644]
test/layoutengine/standard-testcases/list-block_fox_orphan-content-limit_1.xml [new file with mode: 0644]
test/layoutengine/standard-testcases/list-block_fox_widow-content-limit_1.xml [new file with mode: 0644]
test/layoutengine/standard-testcases/table_fox_orphan-content-limit_1.xml [new file with mode: 0644]
test/layoutengine/standard-testcases/table_fox_widow-content-limit_1.xml [new file with mode: 0644]
test/layoutengine/standard-testcases/table_fox_widow-content-limit_2.xml [new file with mode: 0644]

index e2d19eca8b1325a3e02d134670da1305e904357b..0c22ca12375e656293ec65382f36b9bfcd704e9e 100644 (file)
           <code>http://xml.apache.org/fop/extensions</code> to the root element:
         </p>
         <source><![CDATA[<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"
-               xmlns:fox="http://xml.apache.org/fop/extensions">]]></source>
-        <note>Currently, no extensions are implemented in FOP Trunk which use the FOP extension namespace.</note>
+               xmlns:fox="http://xmlgraphics.apache.org/fop/extensions">]]></source>
+        <note>
+          Currently, no extension elements are implemented in FOP Trunk which use the 
+          FOP extension namespace.
+        </note>
       </section>
       <section id="bookmarks">
         <title>PDF Bookmarks</title>
@@ -101,6 +104,21 @@ to following pages. Here is an example of FO code creating such a table-header:<
   </fo:table-row>
 </fo:table-header>]]></source-->
       </section>
+      <section id="widow-orphan-content-limit">
+        <title>fox:orphan-content-limit and fox:widow-content-limit</title>
+        <p>
+          The two proprietary extension properties, fox:orphan-content-limit and
+          fox:widow-content-limit, are used to improve the layout of list-blocks and tables.
+          If you have a table with many entries, you don't want a single row to be left over
+          on a page. You will want to make sure that at least two or three lines are kept
+          together. The properties take an absolute length which specifies the area at the
+          beginning (fox:widow-content-limit) or at the end (fox:orphan-content-limit) of a
+          table or list-block. The properties are inherited and only have an effect on fo:table
+          and fo:list-block. An example: fox:widow-content-limit="3 * 1.2em" would make sure
+          the you'll have at least three lines (assuming line-height="1.2") together on a table
+          or list-block.
+        </p>
+      </section>
     </section>
   </body>
 </document>
index 0e91b4efd81468e711f4395f70b7433e3cb1c61f..92cbe54da5f86578d3dda3b0dd9c1a8c73fd9f76 100644 (file)
@@ -682,10 +682,14 @@ public interface Constants {
     int PR_INDEX_CLASS = 249;
     /** Property constant - XSL 1.1 */
     int PR_INDEX_KEY = 250;
-    /** Property constant - Custom extension */
+    /** Property constant - FOP proprietary: Custom extension for line alignment */
     int PR_X_BLOCK_PROGRESSION_UNIT = 251;
+    /** Property constant - FOP proprietary: limit for widow content in lists and tables */
+    int PR_X_WIDOW_CONTENT_LIMIT = 252;
+    /** Property constant - FOP proprietary: limit for orphan content in lists and tables */
+    int PR_X_ORPHAN_CONTENT_LIMIT = 253;
     /** Number of property constants defined */
-    int PROPERTY_COUNT = 251;
+    int PROPERTY_COUNT = 253;
 
     // compound property constants
 
index 06ed58201a7d22211dd125f994b6c8130ebde6cd..0f436ae28322c1197906db158f95e4fbe046b785 100644 (file)
@@ -24,6 +24,7 @@ import java.util.HashMap;
 import javax.xml.parsers.DocumentBuilderFactory;
 import javax.xml.parsers.ParserConfigurationException;
 
+import org.apache.fop.util.QName;
 import org.w3c.dom.DOMImplementation;
 
 /**
@@ -88,6 +89,21 @@ public abstract class ElementMapping {
                     "Cannot return default DOM implementation: " + e.getMessage());
         }
     }
+
+    /** @return the standard namespace prefix for this namespace or null if it is not known. */
+    public String getStandardPrefix() {
+        return null;
+    }
+    
+    /**
+     * Indicates whether a particular attribute of the namespace is a property, i.e. the attribute
+     * value should be converted to a property value.
+     * @param attributeName the attribute name
+     * @return true if the attribute should be converted to a property
+     */
+    public boolean isAttributeProperty(QName attributeName) {
+        return false;
+    }
     
     /**
      * Initializes the set of maker objects associated with this ElementMapping
index 5cfa50ccbbd260384ad7abbe15d59ee47ab63015..105a956a29094cf807016a5ff2649a741a71fb5a 100644 (file)
@@ -168,6 +168,16 @@ public class ElementMappingRegistry {
         }
     }
     
+    /**
+     * Returns an ElementMapping class for a namespace URI if there is one.
+     * @param namespaceURI the namespace URI
+     * @return the requested ElementMapping or null, if no ElementMapping for the namespace is
+     *         available.
+     */
+    public ElementMapping getElementMapping(String namespaceURI) {
+        return (ElementMapping)this.namespaces.get(namespaceURI);
+    }
+    
     /**
      * Indicates whether a namespace is known to FOP.
      * @param namespaceURI the namespace URI
index 015ff6f697f66983d1bea12f3dd779d32abaa624..c3b99f6e45427054d3566b795c395c0d68487c60 100644 (file)
@@ -22,6 +22,8 @@ package org.apache.fop.fo;
 // Java
 import java.util.HashMap;
 
+import org.apache.fop.util.QName;
+
 /**
  * Element mapping class for all XSL-FO elements.
  */
@@ -136,6 +138,16 @@ public class FOElementMapping extends ElementMapping {
         }
     }
 
+    /** @see org.apache.fop.fo.ElementMapping#getStandardPrefix() */
+    public String getStandardPrefix() {
+        return "fo";
+    }
+    
+    /** @see org.apache.fop.fo.ElementMapping#isAttributeProperty(org.apache.fop.util.QName) */
+    public boolean isAttributeProperty(QName attributeName) {
+        return true; //All XSL-FO attributes are to be converted to properties.
+    }
+    
     static class RootMaker extends ElementMapping.Maker {
         public FONode make(FONode parent) {
             return new org.apache.fop.fo.pagination.Root(parent);
index 8fce870835f55efbc8432e2a97f075f5dc64bf88..2cb2da653e0db4dd3ee64d6cb82e7bc20381ca9b 100644 (file)
@@ -1456,11 +1456,11 @@ public final class FOPropertyMapping implements Constants {
         l.setDefault("auto");
         addPropertyMaker("width", l);
 
-/*LF*/  // block-progression-unit (**CUSTOM EXTENSION**)
-/*LF*/  l  = new LengthProperty.Maker(PR_X_BLOCK_PROGRESSION_UNIT);
-/*LF*/  l.setInherited(false);
-/*LF*/  l.setDefault("0pt");
-/*LF*/  addPropertyMaker("block-progression-unit", l);
+        // fox:block-progression-unit (**CUSTOM EXTENSION**)
+        l  = new LengthProperty.Maker(PR_X_BLOCK_PROGRESSION_UNIT);
+        l.setInherited(false);
+        l.setDefault("0pt");
+        addPropertyMaker("fox:block-progression-unit", l);
     }
 
     private void createBlockAndLineProperties() {
@@ -1828,6 +1828,18 @@ public final class FOPropertyMapping implements Constants {
         m.setInherited(true);
         m.setDefault("2");
         addPropertyMaker("widows", m);
+        
+        // fox:widow-content-limit
+        m  = new LengthProperty.Maker(PR_X_WIDOW_CONTENT_LIMIT);
+        m.setInherited(true);
+        m.setDefault("0pt");
+        addPropertyMaker("fox:widow-content-limit", m);
+
+        // fox:orphan-content-limit
+        m  = new LengthProperty.Maker(PR_X_ORPHAN_CONTENT_LIMIT);
+        m.setInherited(true);
+        m.setDefault("0pt");
+        addPropertyMaker("fox:orphan-content-limit", m);
     }
 
     private void createLayoutProperties() {
index 69eb2f38b725b68b4e79adfde90fa8be77c8e29d..0d5b1fe657b33e0e7492caf2fd28b6d986bf4b51 100644 (file)
@@ -513,29 +513,20 @@ public abstract class FObj extends FONode implements Constants {
 
     /**
      * Adds a foreign attribute to this FObj.
-     * @param uri the namespace URI
-     * @param qName the fully qualified name
+     * @param attributeName the attribute name as a QName instance
      * @param value the attribute value
      */
-    public void addForeignAttribute(String uri, 
-                        String qName, String value) {
+    public void addForeignAttribute(QName attributeName, String value) {
         /* TODO: Handle this over FOP's property mechanism so we can use 
          *       inheritance.
          */
-        if (qName == null) {
-            throw new NullPointerException("Parameter qName must not be null");
+        if (attributeName == null) {
+            throw new NullPointerException("Parameter attributeName must not be null");
         }
         if (foreignAttributes == null) {
             foreignAttributes = new java.util.HashMap();
         }
-        String localName = qName;
-        String prefix = null;
-        int p = localName.indexOf(':');
-        if (p > 0) {
-            prefix = localName.substring(0, p);
-            localName = localName.substring(p + 1);
-        }
-        foreignAttributes.put(new QName(uri, prefix, localName), value);
+        foreignAttributes.put(attributeName, value);
     }
     
     /** @return the map of foreign attributes */
index 0600601c75972db33059bcaf5801d15d91c8259f..8b7c67abd6c06b0548a2d71114a48c06672e29f1 100644 (file)
@@ -39,6 +39,7 @@ import org.apache.fop.fo.properties.CommonRelativePosition;
 import org.apache.fop.fo.properties.CommonTextDecoration;
 import org.apache.fop.fo.properties.Property;
 import org.apache.fop.fo.properties.PropertyMaker;
+import org.apache.fop.util.QName;
 
 /**
  * Class containing the collection of properties for a given FObj.
@@ -311,8 +312,18 @@ public abstract class PropertyList {
             if (attributeNS == null || attributeNS.length() == 0) {
                 convertAttributeToProperty(attributes, attributeName, attributeValue);
             } else if (!factory.isNamespaceIgnored(attributeNS)) {
-                if (factory.getElementMappingRegistry().isKnownNamespace(attributeNS)) {
-                    getFObj().addForeignAttribute(attributeNS, attributeName, attributeValue);
+                ElementMapping mapping = factory.getElementMappingRegistry().getElementMapping(
+                        attributeNS);
+                if (mapping != null) {
+                    QName attName = new QName(attributeNS, attributeName);
+                    if (mapping.isAttributeProperty(attName) 
+                            && mapping.getStandardPrefix() != null) {
+                        convertAttributeToProperty(attributes, 
+                                mapping.getStandardPrefix() + ":" + attName.getLocalName(), 
+                                attributeValue);
+                    } else {
+                        getFObj().addForeignAttribute(attName, attributeValue);
+                    }
                 } else {
                     handleInvalidProperty(
                             "Error processing foreign attribute: "
index 0fafb0ca0eed47681c4446d2d398eade1312e4a5..0b5ae827b283c59010362f0f771cd23a14720927 100644 (file)
@@ -21,8 +21,10 @@ package org.apache.fop.fo.extensions;
 
 import org.apache.fop.fo.ElementMapping;
 import org.apache.fop.fo.UnknownXMLObj;
+import org.apache.fop.util.QName;
 
 import java.util.HashMap;
+import java.util.Set;
 
 /**
  * Element mapping for FOP's proprietary extension to XSL-FO.
@@ -32,6 +34,15 @@ public class ExtensionElementMapping extends ElementMapping {
     /** The FOP extension namespace URI */
     public static final String URI = "http://xmlgraphics.apache.org/fop/extensions";
 
+    private static final Set propertyAttributes = new java.util.HashSet();
+    
+    static {
+        //These are FOP's standard extension properties (fox:*)
+        propertyAttributes.add("block-progression-unit");
+        propertyAttributes.add("widow-content-limit");
+        propertyAttributes.add("orphan-content-limit");
+    }
+    
     /**
      * Constructor.
      */
@@ -49,4 +60,18 @@ public class ExtensionElementMapping extends ElementMapping {
             foObjs.put("label", new UnknownXMLObj.Maker(URI));
         }
     }
+    
+    /** @see org.apache.fop.fo.ElementMapping#getStandardPrefix() */
+    public String getStandardPrefix() {
+        return "fox";
+    }
+    
+    /** @see org.apache.fop.fo.ElementMapping#isAttributeProperty(org.apache.fop.util.QName) */
+    public boolean isAttributeProperty(QName attributeName) {
+        if (!URI.equals(attributeName.getNamespaceURI())) {
+            throw new IllegalArgumentException("The namespace URIs don't match");
+        }
+        return propertyAttributes.contains(attributeName.getLocalName());
+    }
+    
 }
index a9b07bc0d05c94059fb281eb9572f4c57971fafe..7d2ca2f72dc16ba69def16563e8a6466426cc8c9 100644 (file)
@@ -86,6 +86,11 @@ public class SVGElementMapping extends ElementMapping {
         }
     }
 
+    /** @see org.apache.fop.fo.ElementMapping#getStandardPrefix() */
+    public String getStandardPrefix() {
+        return "svg";
+    }
+
     static class SVGMaker extends ElementMapping.Maker {
         public FONode make(FONode parent) {
             return new SVGObj(parent);
index 2051451c5f45b1dce98f7518bd6a7417ee74741d..2cbbb58ced70955512c5ed10dc2ed2dc16736fba 100644 (file)
@@ -55,6 +55,10 @@ public class ListBlock extends FObj {
     private Length provisionalLabelSeparation;
     // End of property values
 
+    /** extension properties */
+    private Length widowContentLimit;
+    private Length orphanContentLimit;
+    
     // used for child node validation
     private boolean hasListItem = false;
 
@@ -85,6 +89,10 @@ public class ListBlock extends FObj {
                 PR_PROVISIONAL_DISTANCE_BETWEEN_STARTS).getLength();
         provisionalLabelSeparation = pList.get(
                 PR_PROVISIONAL_LABEL_SEPARATION).getLength();
+
+        //Bind extension properties
+        widowContentLimit = pList.get(PR_X_WIDOW_CONTENT_LIMIT).getLength();
+        orphanContentLimit = pList.get(PR_X_ORPHAN_CONTENT_LIMIT).getLength();
     }
 
     /**
@@ -167,9 +175,17 @@ public class ListBlock extends FObj {
         return keepTogether;
     }
 
-    /**
-     * @return the "id" property.
-     */
+    /** @return the "fox:widow-content-limit" extension property */
+    public Length getWidowContentLimit() {
+        return widowContentLimit;
+    }
+
+    /** @return the "fox:orphan-content-limit" extension property */
+    public Length getOrphanContentLimit() {
+        return orphanContentLimit;
+    }
+
+    /** @return the "id" property. */
     public String getId() {
         return id;
     }
@@ -179,9 +195,7 @@ public class ListBlock extends FObj {
         return "list-block";
     }
     
-    /**
-     * @see org.apache.fop.fo.FObj#getNameId()
-     */
+    /** @see org.apache.fop.fo.FObj#getNameId() */
     public int getNameId() {
         return FO_LIST_BLOCK;
     }
index ac3fc95ee3f8a29cb8ec69cd8451a1caa326c91d..079909c7312993e64759c049a0ffb8701675cdc9 100644 (file)
@@ -67,6 +67,10 @@ public class Table extends TableFObj {
     private int tableOmitFooterAtBreak;
     private int tableOmitHeaderAtBreak;
     private int writingMode;
+    
+    /** extension properties */
+    private Length widowContentLimit;
+    private Length orphanContentLimit;
 
     private static final int MINCOLWIDTH = 10000; // 10pt
 
@@ -126,6 +130,10 @@ public class Table extends TableFObj {
         tableOmitHeaderAtBreak = pList.get(PR_TABLE_OMIT_HEADER_AT_BREAK).getEnum();
         writingMode = pList.get(PR_WRITING_MODE).getEnum();
         super.bind(pList);
+
+        //Bind extension properties
+        widowContentLimit = pList.get(PR_X_WIDOW_CONTENT_LIMIT).getLength();
+        orphanContentLimit = pList.get(PR_X_ORPHAN_CONTENT_LIMIT).getLength();
         
         if (borderCollapse != EN_SEPARATE) {
             //TODO Remove once the collapsing border is at least marginally working.
@@ -449,10 +457,18 @@ public class Table extends TableFObj {
     public LengthPairProperty getBorderSeparation() {
         return borderSeparation;
     }
+    
+    /** @return the "fox:widow-content-limit" extension property */
+    public Length getWidowContentLimit() {
+        return widowContentLimit;
+    }
 
-    /**
-     * @return the "id" property.
-     */
+    /** @return the "fox:orphan-content-limit" extension property */
+    public Length getOrphanContentLimit() {
+        return orphanContentLimit;
+    }
+
+    /** @return the "id" property. */
     public String getId() {
         return id;
     }
@@ -462,9 +478,7 @@ public class Table extends TableFObj {
         return "table";
     }
 
-    /**
-     * @see org.apache.fop.fo.FObj#getNameId()
-     */
+    /** @see org.apache.fop.fo.FObj#getNameId() */
     public int getNameId() {
         return FO_TABLE;
     }
index 261974d6b65c29f3d3b0039d4191b2bd9bbd554e..1166482a9cf32ae07bad9a599c96b753d041f2f7 100644 (file)
@@ -43,24 +43,20 @@ public class ElementListUtils {
                 //Convert all penalties no break inhibitors
                 if (breakPoss.getPenaltyValue() < KnuthPenalty.INFINITE) {
                     breakPoss.setPenaltyValue(KnuthPenalty.INFINITE);
-                    /*
-                    i.set(new KnuthPenalty(penalty.getW(), KnuthPenalty.INFINITE, 
-                            penalty.isFlagged(), penalty.getPosition(), penalty.isAuxiliary()));
-                    */
                 }
             } else if (el.isGlue()) {
                 i.previous();
                 if (el.isBox()) {
                     i.next();
                     i.add(new KnuthPenalty(0, KnuthPenalty.INFINITE, false, 
-                            /*new Position(getTableLM())*/null, false));
+                            null, false));
                 }
             }
         }
     }
     
     /**
-     * Removes all legal breaks in an element list. A constraint can be specified to limit the
+     * Removes legal breaks in an element list. A constraint can be specified to limit the
      * range in which the breaks are removed. Legal breaks occuring before at least 
      * constraint.opt space is filled will be removed.
      * @param elements the element list
@@ -68,29 +64,95 @@ public class ElementListUtils {
      * @return true if the opt constraint is bigger than the list contents
      */
     public static boolean removeLegalBreaks(LinkedList elements, MinOptMax constraint) {
+        return removeLegalBreaks(elements, constraint.opt);
+    }
+    
+    /**
+     * Removes legal breaks in an element list. A constraint can be specified to limit the
+     * range in which the breaks are removed. Legal breaks occuring before at least 
+     * constraint space is filled will be removed.
+     * @param elements the element list
+     * @param constraint value to restrict the range in which the breaks are removed.
+     * @return true if the constraint is bigger than the list contents
+     */
+    public static boolean removeLegalBreaks(LinkedList elements, int constraint) {
         int len = 0;
-        ListIterator i = elements.listIterator();
-        while (i.hasNext()) {
-            KnuthElement el = (KnuthElement)i.next();
+        ListIterator iter = elements.listIterator();
+        while (iter.hasNext()) {
+            ListElement el = (ListElement)iter.next();
             if (el.isPenalty()) {
                 KnuthPenalty penalty = (KnuthPenalty)el;
-                //Convert all penalties no break inhibitors
+                //Convert all penalties to break inhibitors
+                if (penalty.getP() < KnuthPenalty.INFINITE) {
+                    iter.set(new KnuthPenalty(penalty.getW(), KnuthPenalty.INFINITE, 
+                            penalty.isFlagged(), penalty.getPosition(), penalty.isAuxiliary()));
+                }
+            } else if (el.isGlue()) {
+                KnuthGlue glue = (KnuthGlue)el;
+                len += glue.getW();
+                iter.previous();
+                el = (ListElement)iter.previous();
+                iter.next();
+                if (el.isBox()) {
+                    iter.add(new KnuthPenalty(0, KnuthPenalty.INFINITE, false, 
+                            null, false));
+                }
+                iter.next();
+            } else if (el instanceof BreakElement) {
+                BreakElement breakEl = (BreakElement)el;
+                if (breakEl.getPenaltyValue() < KnuthPenalty.INFINITE) {
+                    breakEl.setPenaltyValue(KnuthPenalty.INFINITE);
+                }
+            } else {
+                KnuthElement kel = (KnuthElement)el;
+                len += kel.getW();
+            }
+            if (len >= constraint) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Removes legal breaks in an element list. A constraint can be specified to limit the
+     * range in which the breaks are removed. Legal breaks within the space specified through the
+     * constraint (starting from the end of the element list) will be removed.
+     * @param elements the element list
+     * @param constraint value to restrict the range in which the breaks are removed.
+     * @return true if the constraint is bigger than the list contents
+     */
+    public static boolean removeLegalBreaksFromEnd(LinkedList elements, int constraint) {
+        int len = 0;
+        ListIterator i = elements.listIterator(elements.size());
+        while (i.hasPrevious()) {
+            ListElement el = (ListElement)i.previous();
+            if (el.isPenalty()) {
+                KnuthPenalty penalty = (KnuthPenalty)el;
+                //Convert all penalties to break inhibitors
                 if (penalty.getP() < KnuthPenalty.INFINITE) {
                     i.set(new KnuthPenalty(penalty.getW(), KnuthPenalty.INFINITE, 
                             penalty.isFlagged(), penalty.getPosition(), penalty.isAuxiliary()));
                 }
             } else if (el.isGlue()) {
-                len += el.getW();
-                i.previous();
+                KnuthGlue glue = (KnuthGlue)el;
+                len += glue.getW();
+                el = (ListElement)i.previous();
+                i.next();
                 if (el.isBox()) {
-                    i.next();
                     i.add(new KnuthPenalty(0, KnuthPenalty.INFINITE, false, 
-                            /*new Position(getTableLM())*/null, false));
+                            null, false));
+                }
+            } else if (el instanceof BreakElement) {
+                BreakElement breakEl = (BreakElement)el;
+                if (breakEl.getPenaltyValue() < KnuthPenalty.INFINITE) {
+                    breakEl.setPenaltyValue(KnuthPenalty.INFINITE);
                 }
             } else {
-                len += el.getW();
+                KnuthElement kel = (KnuthElement)el;
+                len += kel.getW();
             }
-            if (len > constraint.opt) {
+            if (len >= constraint) {
                 return false;
             }
         }
index 709106dbca98fc73635b7be847392c2dc957d256..67e6096622f98558435e442791fcd8e0899ff251 100644 (file)
@@ -23,6 +23,7 @@ import org.apache.fop.fo.flow.ListBlock;
 import org.apache.fop.layoutmgr.BlockLevelLayoutManager;
 import org.apache.fop.layoutmgr.BlockStackingLayoutManager;
 import org.apache.fop.layoutmgr.ConditionalElementListener;
+import org.apache.fop.layoutmgr.ElementListUtils;
 import org.apache.fop.layoutmgr.LayoutManager;
 import org.apache.fop.layoutmgr.LayoutContext;
 import org.apache.fop.layoutmgr.PositionIterator;
@@ -70,15 +71,6 @@ public class ListBlockLayoutManager extends BlockStackingLayoutManager
         }
     }
 
-    /*
-    private class SectionPosition extends LeafPosition {
-        protected List list;
-        protected SectionPosition(LayoutManager lm, int pos, List l) {
-            super(lm, pos);
-            list = l;
-        }
-    }*/
-
     /**
      * Create a new list block layout manager.
      * @param node list-block to create the layout manager for
@@ -117,7 +109,21 @@ public class ListBlockLayoutManager extends BlockStackingLayoutManager
     /** @see org.apache.fop.layoutmgr.BlockStackingLayoutManager */
     public LinkedList getNextKnuthElements(LayoutContext context, int alignment) {
         resetSpaces(); 
-        return super.getNextKnuthElements(context, alignment);
+        LinkedList returnList = super.getNextKnuthElements(context, alignment);
+
+        //fox:widow-content-limit
+        int widowRowLimit = getListBlockFO().getWidowContentLimit().getValue(); 
+        if (widowRowLimit != 0) {
+            ElementListUtils.removeLegalBreaks(returnList, widowRowLimit);
+        }
+
+        //fox:orphan-content-limit
+        int orphanRowLimit = getListBlockFO().getOrphanContentLimit().getValue(); 
+        if (orphanRowLimit != 0) {
+            ElementListUtils.removeLegalBreaksFromEnd(returnList, orphanRowLimit);
+        }
+
+        return returnList;
     }
    
     /** @see org.apache.fop.layoutmgr.LayoutManager#getChangedKnuthElements(java.util.List, int) */
index 1c3045e52946be71f9041b7cb67805161a5beb15..8b07f6956a71219624097f3b39ee6a5a6e54a350 100644 (file)
@@ -223,8 +223,6 @@ public class TableContentLayoutManager implements PercentBaseContext {
                     }
                 } else {
                     if (!firstBreakBeforeServed) {
-                        //returnList.add(new KnuthPenalty(0, -KnuthPenalty.INFINITE, 
-                        //        false, rowFO.getBreakBefore(), new Position(getTableLM()), true));
                         returnList.add(new BreakElement(new Position(getTableLM()),
                                 0, -KnuthPenalty.INFINITE, rowFO.getBreakBefore(), context));
                         iter.backToPreviousRow();
@@ -291,6 +289,18 @@ public class TableContentLayoutManager implements PercentBaseContext {
                 }
             }
         }
+
+        //fox:widow-content-limit
+        int widowContentLimit = getTableLM().getTable().getWidowContentLimit().getValue(); 
+        if (widowContentLimit != 0 && bodyType == TableRowIterator.BODY) {
+            ElementListUtils.removeLegalBreaks(returnList, widowContentLimit);
+        }
+        //fox:orphan-content-limit
+        int orphanContentLimit = getTableLM().getTable().getOrphanContentLimit().getValue(); 
+        if (orphanContentLimit != 0 && bodyType == TableRowIterator.BODY) {
+            ElementListUtils.removeLegalBreaksFromEnd(returnList, orphanContentLimit);
+        }
+        
         return returnList;
     }
 
index 3e5bb48c266f6caf8325f65aabaac876fd3248e3..ac283f784db2b1798dfb8d228430d82e43008228 100644 (file)
 
   <changes>
     <release version="FOP Trunk">
+      <action context="Code" dev="JM" type="add">
+        Extension properties fox:orphan-content-limit and fox:widow-content-limit which
+        help with list-block and table layout. See the documentation for details.
+      </action>
       <action context="Code" dev="JM" type="add">
         Configuration option in the Java2D-based renderers that allows to disable the default
         white background in order to produce bitmap output with transparency.
diff --git a/test/java/org/apache/fop/util/ElementListUtilsTestCase.java b/test/java/org/apache/fop/util/ElementListUtilsTestCase.java
new file mode 100644 (file)
index 0000000..1ea0ac0
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * 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$ */
+
+package org.apache.fop.util;
+
+import java.util.LinkedList;
+
+import org.apache.fop.layoutmgr.ElementListUtils;
+import org.apache.fop.layoutmgr.KnuthBox;
+import org.apache.fop.layoutmgr.KnuthElement;
+import org.apache.fop.layoutmgr.KnuthGlue;
+import org.apache.fop.layoutmgr.KnuthPenalty;
+
+import junit.framework.TestCase;
+
+/**
+ * Test class for ElementListUtils.
+ */
+public class ElementListUtilsTestCase extends TestCase {
+
+    /**
+     * Tests ElementListUtils.removeLegalBreaks().
+     * @throws Exception if the test fails
+     */
+    public void testRemoveElementPenalty1() throws Exception {
+        LinkedList lst = new LinkedList();
+        lst.add(new KnuthBox(4000, null, false));
+        lst.add(new KnuthPenalty(0, 0, false, null, false));
+        lst.add(new KnuthBox(4000, null, false));
+        lst.add(new KnuthPenalty(0, 200, false, null, false));
+        lst.add(new KnuthBox(4000, null, false));
+        lst.add(new KnuthPenalty(0, 0, false, null, false));
+        lst.add(new KnuthBox(4000, null, false));
+        lst.add(new KnuthPenalty(0, KnuthElement.INFINITE, false, null, false));
+        lst.add(new KnuthGlue(0, Integer.MAX_VALUE, 0, null, false));
+        lst.add(new KnuthPenalty(0, -KnuthElement.INFINITE, false, null, false));
+        
+        boolean res = ElementListUtils.removeLegalBreaks(lst, 9000);
+        
+        assertFalse(res);
+
+        assertEquals(KnuthElement.INFINITE, ((KnuthPenalty)lst.get(1)).getP());
+        assertEquals(KnuthElement.INFINITE, ((KnuthPenalty)lst.get(3)).getP());
+        assertEquals(0, ((KnuthPenalty)lst.get(5)).getP());
+    }
+    
+    /**
+     * Tests ElementListUtils.removeLegalBreaks().
+     * @throws Exception if the test fails
+     */
+    public void testRemoveElementPenalty2() throws Exception {
+        LinkedList lst = new LinkedList();
+        lst.add(new KnuthBox(4000, null, false));
+        lst.add(new KnuthGlue(0, 0, 0, null, false));
+        lst.add(new KnuthBox(4000, null, false));
+        lst.add(new KnuthGlue(0, 0, 0, null, false));
+        lst.add(new KnuthBox(4000, null, false));
+        lst.add(new KnuthGlue(0, 0, 0, null, false));
+        lst.add(new KnuthBox(4000, null, false));
+        lst.add(new KnuthPenalty(0, KnuthElement.INFINITE, false, null, false));
+        lst.add(new KnuthGlue(0, Integer.MAX_VALUE, 0, null, false));
+        lst.add(new KnuthPenalty(0, -KnuthElement.INFINITE, false, null, false));
+        
+        boolean res = ElementListUtils.removeLegalBreaks(lst, 9000);
+        
+        assertFalse(res);
+        
+        //Must insert an INFINITE penalty
+        assertEquals(KnuthElement.INFINITE, ((KnuthPenalty)lst.get(1)).getP());
+        assertEquals(0, ((KnuthGlue)lst.get(2)).getW());
+        assertEquals(KnuthElement.INFINITE, ((KnuthPenalty)lst.get(4)).getP());
+        assertEquals(0, ((KnuthGlue)lst.get(5)).getW());
+        assertEquals(0, ((KnuthGlue)lst.get(7)).getW());
+    }
+    
+    /**
+     * Tests ElementListUtils.removeLegalBreaksFromEnd().
+     * @throws Exception if the test fails
+     */
+    public void testRemoveElementFromEndPenalty1() throws Exception {
+        LinkedList lst = new LinkedList();
+        lst.add(new KnuthBox(4000, null, false));
+        lst.add(new KnuthPenalty(0, 0, false, null, false));
+        lst.add(new KnuthBox(4000, null, false));
+        lst.add(new KnuthPenalty(0, 200, false, null, false));
+        lst.add(new KnuthBox(4000, null, false));
+        lst.add(new KnuthPenalty(0, 0, false, null, false));
+        lst.add(new KnuthBox(4000, null, false));
+        lst.add(new KnuthPenalty(0, KnuthElement.INFINITE, false, null, false));
+        lst.add(new KnuthGlue(0, Integer.MAX_VALUE, 0, null, false));
+        lst.add(new KnuthPenalty(0, -KnuthElement.INFINITE, false, null, false));
+        
+        boolean res = ElementListUtils.removeLegalBreaksFromEnd(lst, 9000);
+        
+        assertFalse(res);
+
+        assertEquals(0, ((KnuthPenalty)lst.get(1)).getP());
+        assertEquals(KnuthElement.INFINITE, ((KnuthPenalty)lst.get(3)).getP());
+        assertEquals(KnuthElement.INFINITE, ((KnuthPenalty)lst.get(5)).getP());
+    }
+    
+    /**
+     * Tests ElementListUtils.removeLegalBreaksFromEnd().
+     * @throws Exception if the test fails
+     */
+    public void testRemoveElementFromEndPenalty2() throws Exception {
+        LinkedList lst = new LinkedList();
+        lst.add(new KnuthBox(4000, null, false));
+        lst.add(new KnuthPenalty(0, 0, false, null, false));
+        lst.add(new KnuthBox(4000, null, false));
+        lst.add(new KnuthPenalty(0, 200, false, null, false));
+        lst.add(new KnuthBox(4000, null, false));
+        lst.add(new KnuthGlue(0, 0, 0, null, false));
+        lst.add(new KnuthBox(4000, null, false));
+        lst.add(new KnuthPenalty(0, KnuthElement.INFINITE, false, null, false));
+        lst.add(new KnuthGlue(0, Integer.MAX_VALUE, 0, null, false));
+        lst.add(new KnuthPenalty(0, -KnuthElement.INFINITE, false, null, false));
+        
+        boolean res = ElementListUtils.removeLegalBreaksFromEnd(lst, 9000);
+        
+        assertFalse(res);
+
+        //Must insert an INFINITE penalty
+        assertEquals(0, ((KnuthPenalty)lst.get(1)).getP());
+        assertEquals(KnuthElement.INFINITE, ((KnuthPenalty)lst.get(3)).getP());
+        assertEquals(KnuthElement.INFINITE, ((KnuthPenalty)lst.get(5)).getP());
+        assertEquals(0, ((KnuthGlue)lst.get(6)).getW());
+    }
+    
+    
+}
\ No newline at end of file
diff --git a/test/layoutengine/standard-testcases/list-block_fox_orphan-content-limit_1.xml b/test/layoutengine/standard-testcases/list-block_fox_orphan-content-limit_1.xml
new file mode 100644 (file)
index 0000000..bf4021b
--- /dev/null
@@ -0,0 +1,123 @@
+<?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 effect of the proprietary fox:orphan-content-limit property.
+    </p>
+  </info>
+  <fo>
+    <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:svg="http://www.w3.org/2000/svg"
+        xmlns:fox="http://xmlgraphics.apache.org/fop/extensions">
+      <fo:layout-master-set>
+        <fo:simple-page-master master-name="normal" page-width="5in" page-height="5in">
+          <fo:region-body/>
+        </fo:simple-page-master>
+      </fo:layout-master-set>
+      <fo:page-sequence master-reference="normal" white-space-collapse="true" widows="0" orphans="0">
+        <fo:flow flow-name="xsl-region-body">
+          <fo:block space-before="5in - (4 * 1.2em)" space-before.conditionality="retain"/>
+          <fo:list-block 
+              provisional-distance-between-starts="12pt" provisional-label-separation="5pt"
+              fox:orphan-content-limit="3 * 1.2em">
+            <fo:list-item>
+              <fo:list-item-label end-indent="label-end()">
+                <fo:block>•</fo:block>
+              </fo:list-item-label>
+              <fo:list-item-body start-indent="body-start()">
+                <fo:block>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Donec felis ipsum, viverra ut, aliquam porttitor, convallis id, risus. Fusce malesuada nunc nec orci.</fo:block>
+              </fo:list-item-body>
+            </fo:list-item>
+            <fo:list-item>
+              <fo:list-item-label end-indent="label-end()">
+                <fo:block>•</fo:block>
+              </fo:list-item-label>
+              <fo:list-item-body start-indent="body-start()">
+                <fo:block>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Donec felis ipsum.</fo:block>
+              </fo:list-item-body>
+            </fo:list-item>
+          </fo:list-block>
+        </fo:flow>
+      </fo:page-sequence>
+      <!-- the second page-sequence is without the extension property and just for reference. -->
+      <fo:page-sequence master-reference="normal" white-space-collapse="true" widows="0" orphans="0">
+        <fo:flow flow-name="xsl-region-body">
+          <fo:block space-before="5in - (4 * 1.2em)" space-before.conditionality="retain"/>
+          <fo:list-block 
+              provisional-distance-between-starts="12pt" provisional-label-separation="5pt">
+            <fo:list-item>
+              <fo:list-item-label end-indent="label-end()">
+                <fo:block>•</fo:block>
+              </fo:list-item-label>
+              <fo:list-item-body start-indent="body-start()">
+                <fo:block>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Donec felis ipsum, viverra ut, aliquam porttitor, convallis id, risus. Fusce malesuada nunc nec orci.</fo:block>
+              </fo:list-item-body>
+            </fo:list-item>
+            <fo:list-item>
+              <fo:list-item-label end-indent="label-end()">
+                <fo:block>•</fo:block>
+              </fo:list-item-label>
+              <fo:list-item-body start-indent="body-start()">
+                <fo:block>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Donec felis ipsum.</fo:block>
+              </fo:list-item-body>
+            </fo:list-item>
+          </fo:list-block>
+        </fo:flow>
+      </fo:page-sequence>
+    </fo:root>
+  </fo>
+  <checks>
+    <element-list category="breaker" index="0">
+      <box w="0"/>
+      <penalty w="0" p="INF"/>
+      <glue w="302400" y="0" z="0"/>
+      <box w="0"/>
+      <penalty w="0" p="0"/>
+      <box w="14400"/>
+      <penalty w="0" p="0"/>
+      <box w="14400"/>
+      <penalty w="0" p="0"/>
+      <box w="14400"/>
+      <penalty w="0" p="INF"/>
+      <box w="14400"/>
+      <penalty w="0" p="INF"/>
+      <box w="14400"/>
+
+      <skip>3</skip>
+    </element-list>
+    <element-list category="breaker" index="1">
+      <box w="0"/>
+      <penalty w="0" p="INF"/>
+      <glue w="302400" y="0" z="0"/>
+      <box w="0"/>
+      <penalty w="0" p="0"/>
+      <box w="14400"/>
+      <penalty w="0" p="0"/>
+      <box w="14400"/>
+      <penalty w="0" p="0"/>
+      <box w="14400"/>
+      <penalty w="0" p="0"/>
+      <box w="14400"/>
+      <penalty w="0" p="0"/>
+      <box w="14400"/>
+
+      <skip>3</skip>
+    </element-list>
+  </checks>
+</testcase>
diff --git a/test/layoutengine/standard-testcases/list-block_fox_widow-content-limit_1.xml b/test/layoutengine/standard-testcases/list-block_fox_widow-content-limit_1.xml
new file mode 100644 (file)
index 0000000..d635ead
--- /dev/null
@@ -0,0 +1,123 @@
+<?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 effect of the proprietary fox:widow-content-limit property.
+    </p>
+  </info>
+  <fo>
+    <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:svg="http://www.w3.org/2000/svg"
+        xmlns:fox="http://xmlgraphics.apache.org/fop/extensions">
+      <fo:layout-master-set>
+        <fo:simple-page-master master-name="normal" page-width="5in" page-height="5in">
+          <fo:region-body/>
+        </fo:simple-page-master>
+      </fo:layout-master-set>
+      <fo:page-sequence master-reference="normal" white-space-collapse="true" widows="0" orphans="0">
+        <fo:flow flow-name="xsl-region-body">
+          <fo:block space-before="5in - (2 * 1.2em)" space-before.conditionality="retain"/>
+          <fo:list-block 
+              provisional-distance-between-starts="12pt" provisional-label-separation="5pt"
+              fox:widow-content-limit="3 * 1.2em">
+            <fo:list-item>
+              <fo:list-item-label end-indent="label-end()">
+                <fo:block>•</fo:block>
+              </fo:list-item-label>
+              <fo:list-item-body start-indent="body-start()">
+                <fo:block>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Donec felis ipsum.</fo:block>
+              </fo:list-item-body>
+            </fo:list-item>
+            <fo:list-item>
+              <fo:list-item-label end-indent="label-end()">
+                <fo:block>•</fo:block>
+              </fo:list-item-label>
+              <fo:list-item-body start-indent="body-start()">
+                <fo:block>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Donec felis ipsum, viverra ut, aliquam porttitor, convallis id, risus. Fusce malesuada nunc nec orci.</fo:block>
+              </fo:list-item-body>
+            </fo:list-item>
+          </fo:list-block>
+        </fo:flow>
+      </fo:page-sequence>
+      <!-- the second page-sequence is without the extension property and just for reference. -->
+      <fo:page-sequence master-reference="normal" white-space-collapse="true" widows="0" orphans="0">
+        <fo:flow flow-name="xsl-region-body">
+          <fo:block space-before="5in - (2 * 1.2em)" space-before.conditionality="retain"/>
+          <fo:list-block 
+              provisional-distance-between-starts="12pt" provisional-label-separation="5pt">
+            <fo:list-item>
+              <fo:list-item-label end-indent="label-end()">
+                <fo:block>•</fo:block>
+              </fo:list-item-label>
+              <fo:list-item-body start-indent="body-start()">
+                <fo:block>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Donec felis ipsum.</fo:block>
+              </fo:list-item-body>
+            </fo:list-item>
+            <fo:list-item>
+              <fo:list-item-label end-indent="label-end()">
+                <fo:block>•</fo:block>
+              </fo:list-item-label>
+              <fo:list-item-body start-indent="body-start()">
+                <fo:block>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Donec felis ipsum, viverra ut, aliquam porttitor, convallis id, risus. Fusce malesuada nunc nec orci.</fo:block>
+              </fo:list-item-body>
+            </fo:list-item>
+          </fo:list-block>
+        </fo:flow>
+      </fo:page-sequence>
+    </fo:root>
+  </fo>
+  <checks>
+    <element-list category="breaker" index="0">
+      <box w="0"/>
+      <penalty w="0" p="INF"/>
+      <glue w="331200" y="0" z="0"/>
+      <box w="0"/>
+      <penalty w="0" p="0"/>
+      <box w="14400"/>
+      <penalty w="0" p="INF"/>
+      <box w="14400"/>
+      <penalty w="0" p="INF"/>
+      <box w="14400"/>
+      <penalty w="0" p="0"/>
+      <box w="14400"/>
+      <penalty w="0" p="0"/>
+      <box w="14400"/>
+
+      <skip>3</skip>
+    </element-list>
+    <element-list category="breaker" index="1">
+      <box w="0"/>
+      <penalty w="0" p="INF"/>
+      <glue w="331200" y="0" z="0"/>
+      <box w="0"/>
+      <penalty w="0" p="0"/>
+      <box w="14400"/>
+      <penalty w="0" p="0"/>
+      <box w="14400"/>
+      <penalty w="0" p="0"/>
+      <box w="14400"/>
+      <penalty w="0" p="0"/>
+      <box w="14400"/>
+      <penalty w="0" p="0"/>
+      <box w="14400"/>
+
+      <skip>3</skip>
+    </element-list>
+  </checks>
+</testcase>
diff --git a/test/layoutengine/standard-testcases/table_fox_orphan-content-limit_1.xml b/test/layoutengine/standard-testcases/table_fox_orphan-content-limit_1.xml
new file mode 100644 (file)
index 0000000..8314299
--- /dev/null
@@ -0,0 +1,133 @@
+<?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 effect of the proprietary fox:orphan-content-limit property.
+    </p>
+  </info>
+  <fo>
+    <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:svg="http://www.w3.org/2000/svg"
+        xmlns:fox="http://xmlgraphics.apache.org/fop/extensions">
+      <fo:layout-master-set>
+        <fo:simple-page-master master-name="normal" page-width="5in" page-height="5in">
+          <fo:region-body/>
+        </fo:simple-page-master>
+      </fo:layout-master-set>
+      <fo:page-sequence master-reference="normal" white-space-collapse="true" widows="0" orphans="0">
+        <fo:flow flow-name="xsl-region-body">
+          <fo:block space-before="5in - (4 * 1.2em)" space-before.conditionality="retain"/>
+          <fo:table table-layout="fixed" width="100%" border-collapse="separate" 
+                fox:orphan-content-limit="3 * 1.2em">
+            <fo:table-column column-width="proportional-column-width(1)"/>
+            <fo:table-column column-width="proportional-column-width(3)"/>
+            <fo:table-body>
+              <fo:table-row>
+                <fo:table-cell>
+                  <fo:block>row 1</fo:block>
+                </fo:table-cell>
+                <fo:table-cell>
+                  <fo:block>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Donec felis ipsum, viverra ut, aliquam porttitor, convallis id, risus. Fusce malesuada nunc nec orci.</fo:block>
+                </fo:table-cell>
+              </fo:table-row>
+              <fo:table-row>
+                <fo:table-cell>
+                  <fo:block>row 2</fo:block>
+                </fo:table-cell>
+                <fo:table-cell>
+                  <fo:block>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</fo:block>
+                </fo:table-cell>
+              </fo:table-row>
+            </fo:table-body>
+          </fo:table>
+        </fo:flow>
+      </fo:page-sequence>
+      <!-- the second page-sequence is without the extension property and just for reference. -->
+      <fo:page-sequence master-reference="normal" white-space-collapse="true" widows="0" orphans="0">
+        <fo:flow flow-name="xsl-region-body">
+          <fo:block space-before="5in - (4 * 1.2em)" space-before.conditionality="retain"/>
+          <fo:table table-layout="fixed" width="100%" border-collapse="separate">
+            <fo:table-column column-width="proportional-column-width(1)"/>
+            <fo:table-column column-width="proportional-column-width(3)"/>
+            <fo:table-body>
+              <fo:table-row>
+                <fo:table-cell>
+                  <fo:block>row 1</fo:block>
+                </fo:table-cell>
+                <fo:table-cell>
+                  <fo:block>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Donec felis ipsum, viverra ut, aliquam porttitor, convallis id, risus. Fusce malesuada nunc nec orci.</fo:block>
+                </fo:table-cell>
+              </fo:table-row>
+              <fo:table-row>
+                <fo:table-cell>
+                  <fo:block>row 2</fo:block>
+                </fo:table-cell>
+                <fo:table-cell>
+                  <fo:block>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</fo:block>
+                </fo:table-cell>
+              </fo:table-row>
+            </fo:table-body>
+          </fo:table>
+        </fo:flow>
+      </fo:page-sequence>
+    </fo:root>
+  </fo>
+  <checks>
+    <element-list category="breaker" index="0">
+      <box w="0"/>
+      <penalty w="0" p="INF"/>
+      <glue w="302400" y="0" z="0"/>
+      <box w="0"/>
+      <penalty w="0" p="0"/>
+      <box w="14400"/>
+      <penalty w="0" p="0"/>
+      <box w="14400"/>
+      <penalty w="0" p="0"/>
+      <box w="14400"/>
+      <penalty w="0" p="0"/>
+      <box w="14400"/>
+      <penalty w="0" p="INF"/>
+      <box w="14400"/>
+      <penalty w="0" p="INF"/>
+      <box w="14400"/>
+
+      <skip>3</skip>
+    </element-list>
+    <element-list category="breaker" index="1">
+      <box w="0"/>
+      <penalty w="0" p="INF"/>
+      <glue w="302400" y="0" z="0"/>
+      <box w="0"/>
+      <penalty w="0" p="0"/>
+      <box w="14400"/>
+      <penalty w="0" p="0"/>
+      <box w="14400"/>
+      <penalty w="0" p="0"/>
+      <box w="14400"/>
+      <penalty w="0" p="0"/>
+      <box w="14400"/>
+      <penalty w="0" p="0"/>
+      <box w="14400"/>
+      <penalty w="0" p="0"/>
+      <box w="14400"/>
+
+      <skip>3</skip>
+    </element-list>
+  </checks>
+</testcase>
diff --git a/test/layoutengine/standard-testcases/table_fox_widow-content-limit_1.xml b/test/layoutengine/standard-testcases/table_fox_widow-content-limit_1.xml
new file mode 100644 (file)
index 0000000..c41daab
--- /dev/null
@@ -0,0 +1,133 @@
+<?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 effect of the proprietary fox:widow-content-limit property.
+    </p>
+  </info>
+  <fo>
+    <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:svg="http://www.w3.org/2000/svg"
+        xmlns:fox="http://xmlgraphics.apache.org/fop/extensions">
+      <fo:layout-master-set>
+        <fo:simple-page-master master-name="normal" page-width="5in" page-height="5in">
+          <fo:region-body/>
+        </fo:simple-page-master>
+      </fo:layout-master-set>
+      <fo:page-sequence master-reference="normal" white-space-collapse="true" widows="0" orphans="0">
+        <fo:flow flow-name="xsl-region-body">
+          <fo:block space-before="5in - (2 * 1.2em)" space-before.conditionality="retain"/>
+          <fo:table table-layout="fixed" width="100%" border-collapse="separate" 
+                fox:widow-content-limit="3 * 1.2em">
+            <fo:table-column column-width="proportional-column-width(1)"/>
+            <fo:table-column column-width="proportional-column-width(3)"/>
+            <fo:table-body>
+              <fo:table-row>
+                <fo:table-cell>
+                  <fo:block>row 1</fo:block>
+                </fo:table-cell>
+                <fo:table-cell>
+                  <fo:block>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</fo:block>
+                </fo:table-cell>
+              </fo:table-row>
+              <fo:table-row>
+                <fo:table-cell>
+                  <fo:block>row 2</fo:block>
+                </fo:table-cell>
+                <fo:table-cell>
+                  <fo:block>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Donec felis ipsum, viverra ut, aliquam porttitor, convallis id, risus. Fusce malesuada nunc nec orci.</fo:block>
+                </fo:table-cell>
+              </fo:table-row>
+            </fo:table-body>
+          </fo:table>
+        </fo:flow>
+      </fo:page-sequence>
+      <!-- the second page-sequence is without the extension property and just for reference. -->
+      <fo:page-sequence master-reference="normal" white-space-collapse="true" widows="0" orphans="0">
+        <fo:flow flow-name="xsl-region-body">
+          <fo:block space-before="5in - (2 * 1.2em)" space-before.conditionality="retain"/>
+          <fo:table table-layout="fixed" width="100%" border-collapse="separate">
+            <fo:table-column column-width="proportional-column-width(1)"/>
+            <fo:table-column column-width="proportional-column-width(3)"/>
+            <fo:table-body>
+              <fo:table-row>
+                <fo:table-cell>
+                  <fo:block>row 1</fo:block>
+                </fo:table-cell>
+                <fo:table-cell>
+                  <fo:block>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</fo:block>
+                </fo:table-cell>
+              </fo:table-row>
+              <fo:table-row>
+                <fo:table-cell>
+                  <fo:block>row 2</fo:block>
+                </fo:table-cell>
+                <fo:table-cell>
+                  <fo:block>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Donec felis ipsum, viverra ut, aliquam porttitor, convallis id, risus. Fusce malesuada nunc nec orci.</fo:block>
+                </fo:table-cell>
+              </fo:table-row>
+            </fo:table-body>
+          </fo:table>
+        </fo:flow>
+      </fo:page-sequence>
+    </fo:root>
+  </fo>
+  <checks>
+    <element-list category="breaker" index="0">
+      <box w="0"/>
+      <penalty w="0" p="INF"/>
+      <glue w="331200" y="0" z="0"/>
+      <box w="0"/>
+      <penalty w="0" p="0"/>
+      <box w="14400"/>
+      <penalty w="0" p="INF"/>
+      <box w="14400"/>
+      <penalty w="0" p="INF"/>
+      <box w="14400"/>
+      <penalty w="0" p="0"/>
+      <box w="14400"/>
+      <penalty w="0" p="0"/>
+      <box w="14400"/>
+      <penalty w="0" p="0"/>
+      <box w="14400"/>
+
+      <skip>3</skip>
+    </element-list>
+    <element-list category="breaker" index="1">
+      <box w="0"/>
+      <penalty w="0" p="INF"/>
+      <glue w="331200" y="0" z="0"/>
+      <box w="0"/>
+      <penalty w="0" p="0"/>
+      <box w="14400"/>
+      <penalty w="0" p="0"/>
+      <box w="14400"/>
+      <penalty w="0" p="0"/>
+      <box w="14400"/>
+      <penalty w="0" p="0"/>
+      <box w="14400"/>
+      <penalty w="0" p="0"/>
+      <box w="14400"/>
+      <penalty w="0" p="0"/>
+      <box w="14400"/>
+
+      <skip>3</skip>
+    </element-list>
+  </checks>
+</testcase>
diff --git a/test/layoutengine/standard-testcases/table_fox_widow-content-limit_2.xml b/test/layoutengine/standard-testcases/table_fox_widow-content-limit_2.xml
new file mode 100644 (file)
index 0000000..2684d75
--- /dev/null
@@ -0,0 +1,97 @@
+<?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 effect of the proprietary fox:widow-content-limit property.
+    </p>
+  </info>
+  <fo>
+    <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:svg="http://www.w3.org/2000/svg"
+        xmlns:fox="http://xmlgraphics.apache.org/fop/extensions">
+      <fo:layout-master-set>
+        <fo:simple-page-master master-name="normal" page-width="5in" page-height="5in">
+          <fo:region-body/>
+        </fo:simple-page-master>
+      </fo:layout-master-set>
+      <fo:page-sequence master-reference="normal" white-space-collapse="true" widows="0" orphans="0">
+        <fo:flow flow-name="xsl-region-body">
+          <fo:block space-before="5in - (2 * 1.2em)" space-before.conditionality="retain"/>
+          <fo:table table-layout="fixed" width="100%" border-collapse="separate" 
+                fox:widow-content-limit="3 * 1.2em">
+            <fo:table-column column-width="proportional-column-width(1)"/>
+            <fo:table-column column-width="proportional-column-width(3)"/>
+            <fo:table-body>
+              <fo:table-row>
+                <fo:table-cell>
+                  <fo:block>row 1</fo:block>
+                </fo:table-cell>
+                <fo:table-cell>
+                  <fo:block>Lorem ipsum dolor sit amet.</fo:block>
+                </fo:table-cell>
+              </fo:table-row>
+              <fo:table-row>
+                <fo:table-cell>
+                  <fo:block>row 2</fo:block>
+                </fo:table-cell>
+                <fo:table-cell>
+                  <fo:block>Lorem ipsum dolor sit amet.</fo:block>
+                </fo:table-cell>
+              </fo:table-row>
+              <fo:table-row>
+                <fo:table-cell>
+                  <fo:block>row 3</fo:block>
+                </fo:table-cell>
+                <fo:table-cell>
+                  <fo:block>Lorem ipsum dolor sit amet.</fo:block>
+                </fo:table-cell>
+              </fo:table-row>
+              <fo:table-row>
+                <fo:table-cell>
+                  <fo:block>row 4</fo:block>
+                </fo:table-cell>
+                <fo:table-cell>
+                  <fo:block>Lorem ipsum dolor sit amet.</fo:block>
+                </fo:table-cell>
+              </fo:table-row>
+            </fo:table-body>
+          </fo:table>
+        </fo:flow>
+      </fo:page-sequence>
+    </fo:root>
+  </fo>
+  <checks>
+    <element-list category="breaker">
+      <box w="0"/>
+      <penalty w="0" p="INF"/>
+      <glue w="331200" y="0" z="0"/>
+      <box w="0"/>
+      <penalty w="0" p="0"/>
+      <box w="14400"/>
+      <penalty w="0" p="INF"/>
+      <box w="14400"/>
+      <penalty w="0" p="INF"/>
+      <box w="14400"/>
+      <penalty w="0" p="0"/>
+      <box w="14400"/>
+
+      <skip>3</skip>
+    </element-list>
+  </checks>
+</testcase>