You are viewing a plain text version of this content. The canonical link for it is here.
Posted to fop-commits@xmlgraphics.apache.org by vh...@apache.org on 2007/12/13 17:10:34 UTC

svn commit: r603945 - in /xmlgraphics/fop/trunk/src/java/org/apache/fop: fo/ fo/flow/table/ fo/properties/ layoutmgr/table/

Author: vhennebert
Date: Thu Dec 13 08:10:32 2007
New Revision: 603945

URL: http://svn.apache.org/viewvc?rev=603945&view=rev
Log:
Implemented the resolution of collapsing borders in the FO tree, for every situation (normal, cell at the top of a page, cell broken), taking conditionality, headers and footers into account.

Added:
    xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/flow/table/ConditionalBorder.java   (with props)
Modified:
    xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/FOPropertyMapping.java
    xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/flow/table/BorderSpecification.java
    xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/flow/table/CollapsingBorderResolver.java
    xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/flow/table/EmptyGridUnit.java
    xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/flow/table/GridUnit.java
    xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/flow/table/TableBody.java
    xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/flow/table/TableFObj.java
    xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/flow/table/TableHeader.java
    xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/properties/CommonBorderPaddingBackground.java
    xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/table/CollapsingBorderModel.java
    xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/table/CollapsingBorderModelEyeCatching.java

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/FOPropertyMapping.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/FOPropertyMapping.java?rev=603945&r1=603944&r2=603945&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/FOPropertyMapping.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/FOPropertyMapping.java Thu Dec 13 08:10:32 2007
@@ -1141,7 +1141,7 @@
         m.useGeneric(genericSpace);
         corr = new SpacePropertyMaker(m);
         corr.setCorresponding(PR_MARGIN_TOP, PR_MARGIN_TOP, PR_MARGIN_RIGHT);
-        corr.setUseParent(true);
+        corr.setUseParent(false);
         corr.setRelative(true);
         addPropertyMaker("space-before", m);
 

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/flow/table/BorderSpecification.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/flow/table/BorderSpecification.java?rev=603945&r1=603944&r2=603945&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/flow/table/BorderSpecification.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/flow/table/BorderSpecification.java Thu Dec 13 08:10:32 2007
@@ -20,6 +20,7 @@
 package org.apache.fop.fo.flow.table;
 
 import org.apache.fop.fo.Constants;
+import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
 import org.apache.fop.fo.properties.CommonBorderPaddingBackground.BorderInfo;
 
 /**
@@ -28,6 +29,8 @@
  */
 public/*TODO*/ class BorderSpecification {
 
+    private static BorderSpecification defaultBorder;
+
     private BorderInfo borderInfo;
 
     private int holder;
@@ -43,6 +46,14 @@
         this.holder = holder;
     }
 
+    static synchronized BorderSpecification getDefaultBorder() {
+        if (defaultBorder == null) {
+            defaultBorder = new BorderSpecification(CommonBorderPaddingBackground
+                    .getDefaultBorderInfo(), Constants.FO_TABLE_CELL);
+        }
+        return defaultBorder;
+    }
+
     /**
      * Returns this border's informations.
      * 
@@ -66,6 +77,17 @@
 
     /** {@inheritDoc} */
     public String toString() {
-        return "{" + borderInfo + ", " + holder + "}";
+        String holderName = "";
+        switch (holder) {
+        case Constants.FO_TABLE: holderName = "table"; break;
+        case Constants.FO_TABLE_COLUMN: holderName = "table-column"; break;
+        case Constants.FO_TABLE_HEADER: holderName = "table-header"; break;
+        case Constants.FO_TABLE_FOOTER: holderName = "table-footer"; break;
+        case Constants.FO_TABLE_BODY: holderName = "table-body"; break;
+        case Constants.FO_TABLE_ROW: holderName = "table-row"; break;
+        case Constants.FO_TABLE_CELL: holderName = "table-cell"; break;
+        default: assert false;
+        }
+        return "{" + borderInfo + ", " + holderName + "}";
     }
 }

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/flow/table/CollapsingBorderResolver.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/flow/table/CollapsingBorderResolver.java?rev=603945&r1=603944&r2=603945&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/flow/table/CollapsingBorderResolver.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/flow/table/CollapsingBorderResolver.java Thu Dec 13 08:10:32 2007
@@ -19,6 +19,7 @@
 
 package org.apache.fop.fo.flow.table;
 
+import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
 
@@ -31,138 +32,366 @@
 
     private Table table;
 
-    private List previousRow;
-
     /**
-     * The flow of rows is interrupted by the table-footer. Save the header's last row (if
-     * any) for resolution between it and the body's first row.
+     * The previously registered row, either in the header or the body(-ies), but not in
+     * the footer (handled separately).
      */
-    private List previousRowSave;
-
-    private TableBody currentTablePart;
+    private List/*<GridUnit>*/ previousRow;
 
     private boolean firstInTable;
 
-    private boolean firstInPart;
+    private List/*<GridUnit>*/ footerFirstRow;
 
-    private List footerFirstRow;
+    /** The last currently registered footer row. */
+    private List/*<GridUnit>*/ footerLastRow;
 
-    private List footerLastRow;
+    private Resolver delegate;
 
-    private boolean inFooter;
+    private Resolver resolverInFooter;
 
-    CollapsingBorderResolver(Table table) {
-        this.table = table;
-        firstInTable = true;
-    }
+    private List/*<ConditionalBorder>*/ leadingBorders;
 
-    /** {@inheritDoc} */
-    public void endRow(List row, TableCellContainer container) {
-        // Resolve before- and after-borders for the table-row
-        if (container instanceof TableRow) {
-            TableRow tableRow = (TableRow) container;
-            for (Iterator iter = row.iterator(); iter.hasNext();) {
-                GridUnit gu = (GridUnit) iter.next();
+    private List/*<ConditionalBorder>*/ trailingBorders;
+
+    /**
+     * Base class for delegate resolvers. Implementation of the State design pattern: the
+     * treatment differs slightly whether we are in the table's header, footer or body. To
+     * avoid complicated if statements, specialised delegate resolvers will be used
+     * instead.
+     */
+    private abstract class Resolver {
+
+        protected TableBody tablePart;
+
+        protected boolean firstInPart;
+
+        /**
+         * Integrates border-before specified on the table and its column.
+         * 
+         * @param row the first row of the table (in the header, or in the body if the
+         * table has no header)
+         * @param withLeadingTrailing
+         * @param withNonLeadingTrailing
+         * @param withRest
+         */
+        void resolveBordersFirstRowInTable(List/*<GridUnit>*/ row, boolean withLeadingTrailing,
+                boolean withNonLeadingTrailing, boolean withRest) {
+            assert firstInTable;
+            for (int i = 0; i < row.size(); i++) {
+                TableColumn column = table.getColumn(i);
+                ((GridUnit) row.get(i)).integrateBorderSegment(
+                        CommonBorderPaddingBackground.BEFORE, column, withLeadingTrailing,
+                        withNonLeadingTrailing, withRest);
+            }
+            firstInTable = false;
+        }
+
+        /**
+         * Resolves border-after for the first row, border-before for the second one.
+         * 
+         * @param rowBefore
+         * @param rowAfter
+         */
+        void resolveBordersBetweenRows(List/*<GridUnit>*/ rowBefore, List/*<GridUnit>*/ rowAfter) {
+            assert rowBefore != null && rowAfter != null;
+            for (int i = 0; i < rowAfter.size(); i++) {
+                GridUnit gu = (GridUnit) rowAfter.get(i);
                 if (gu.getRowSpanIndex() == 0) {
-                    gu.resolveBorder(CommonBorderPaddingBackground.BEFORE, tableRow);
-                }
-                if (gu.isLastGridUnitRowSpan()) {
-                    gu.resolveBorder(CommonBorderPaddingBackground.AFTER, tableRow);
+                    GridUnit beforeGU = (GridUnit) rowBefore.get(i);
+                    gu.resolveBorder(beforeGU, CommonBorderPaddingBackground.BEFORE);
                 }
             }
         }
-        if (inFooter) {
-            if (footerFirstRow == null) {
-                footerFirstRow = row;
+
+        /** Integrates the border-after of the part. */
+        void resolveBordersLastRowInPart(List/*<GridUnit>*/ row, boolean withLeadingTrailing,
+                boolean withNonLeadingTrailing, boolean withRest) {
+            for (int i = 0; i < row.size(); i++) {
+                ((GridUnit) row.get(i)).integrateBorderSegment(CommonBorderPaddingBackground.AFTER,
+                        tablePart, withLeadingTrailing, withNonLeadingTrailing, withRest);
             }
-            footerLastRow = row;
-        } else if (firstInTable) {
-            // Resolve border-before for the first row in the table
+        }
+
+        /**
+         * Integrates border-after specified on the table and its columns.
+         * 
+         * @param row the last row of the footer, or of the last body if the table has no
+         * footer
+         * @param withLeadingTrailing
+         * @param withNonLeadingTrailing
+         * @param withRest
+         */
+        void resolveBordersLastRowInTable(List/*<GridUnit>*/ row, boolean withLeadingTrailing,
+                boolean withNonLeadingTrailing, boolean withRest) {
             for (int i = 0; i < row.size(); i++) {
                 TableColumn column = table.getColumn(i);
-                ((GridUnit) row.get(i)).resolveBorder(CommonBorderPaddingBackground.BEFORE, column);
+                ((GridUnit) row.get(i)).integrateBorderSegment(CommonBorderPaddingBackground.AFTER,
+                        column, withLeadingTrailing, withNonLeadingTrailing, withRest);
             }
-            firstInTable = false;
         }
-        if (firstInPart) {
-            // Resolve border-before for the first row in the part
-            for (int i = 0; i < row.size(); i++) {
-                ((GridUnit) row.get(i)).resolveBorder(CommonBorderPaddingBackground.BEFORE,
-                        currentTablePart);
+
+        /**
+         * Integrates either border-before specified on the table and its columns if the
+         * table has no header, or border-after specified on the cells of the header's
+         * last row. For the case the grid unit are at the top of a page.
+         * 
+         * @param row
+         */
+        void integrateLeadingBorders(List/*<GridUnit>*/ row) {
+            for (int i = 0; i < table.getNumberOfColumns(); i++) {
+                GridUnit gu = (GridUnit) row.get(i);
+                ConditionalBorder border = (ConditionalBorder) leadingBorders.get(i);
+                gu.integrateCompetingBorder(CommonBorderPaddingBackground.BEFORE, border,
+                        true, false, true);
             }
-            firstInPart = false;
         }
-        if (previousRow != null) {
-            // Resolve after/before borders between rows
-            for (int i = 0; i < row.size(); i++) {
+
+        /**
+         * Integrates either border-after specified on the table and its columns if the
+         * table has no footer, or border-before specified on the cells of the footer's
+         * first row. For the case the grid unit are at the bottom of a page.
+         * 
+         * @param row
+         */
+        void integrateTrailingBorders(List/*<GridUnit>*/ row) {
+            for (int i = 0; i < table.getNumberOfColumns(); i++) {
                 GridUnit gu = (GridUnit) row.get(i);
-                if (gu.getRowSpanIndex() == 0) {
-                    GridUnit beforeGU = (GridUnit) previousRow.get(i);
-                    gu.resolveBorder(beforeGU, CommonBorderPaddingBackground.BEFORE);
+                ConditionalBorder border = (ConditionalBorder) trailingBorders.get(i);
+                gu.integrateCompetingBorder(CommonBorderPaddingBackground.AFTER, border,
+                        true, false, true);
+            }
+        }
+
+        void startPart(TableBody part) {
+            tablePart = part;
+            firstInPart = true;
+        }
+
+        /**
+         * Resolves the applicable borders for the given row.
+         * <ul>
+         * <li>Integrates the border-before/after of the containing table-row if any;</li>
+         * <li>Integrates the border-before of the containing part, if first row;</li>
+         * <li>Resolves border-start/end between grid units.</li>
+         * </ul>
+         * 
+         * @param row the row being finished
+         * @param container the containing element
+         */
+        void endRow(List/*<GridUnit>*/ row, TableCellContainer container) {
+            // Resolve before- and after-borders for the table-row
+            if (container instanceof TableRow) {
+                TableRow tableRow = (TableRow) container;
+                for (Iterator iter = row.iterator(); iter.hasNext();) {
+                    GridUnit gu = (GridUnit) iter.next();
+                    if (gu.getRowSpanIndex() == 0) {
+                        gu.integrateBorderSegment(CommonBorderPaddingBackground.BEFORE, tableRow,
+                                true, true, true);
+                    }
+                    if (gu.isLastGridUnitRowSpan()) {
+                        gu.integrateBorderSegment(CommonBorderPaddingBackground.AFTER, tableRow,
+                                true, true, true);
+                    }
+                }
+            }
+            if (firstInPart) {
+                // Integrate the border-before of the part
+                for (int i = 0; i < row.size(); i++) {
+                    ((GridUnit) row.get(i)).integrateBorderSegment(
+                            CommonBorderPaddingBackground.BEFORE, tablePart, true, true, true);
                 }
+                firstInPart = false;
             }
+            // Resolve start/end borders in the row
+            Iterator guIter = row.iterator();
+            GridUnit gu = (GridUnit) guIter.next();
+            gu.integrateBorderSegment(CommonBorderPaddingBackground.START, container);
+            while (guIter.hasNext()) {
+                GridUnit guEnd = (GridUnit) guIter.next();
+                if (gu.isLastGridUnitColSpan()) {
+                    gu.resolveBorder(guEnd, CommonBorderPaddingBackground.END);
+                }
+                gu = guEnd;
+            }
+            gu.integrateBorderSegment(CommonBorderPaddingBackground.END, container);
+        }
+
+        void endPart() {
+            resolveBordersLastRowInPart(previousRow, true, true, true);
         }
-        // Resolve start/end borders in the row
-        Iterator guIter = row.iterator();
-        GridUnit gu = (GridUnit) guIter.next();
-        gu.resolveBorder(CommonBorderPaddingBackground.START, container);
-        while (guIter.hasNext()) {
-            GridUnit guEnd = (GridUnit) guIter.next();
-            if (gu.isLastGridUnitColSpan()) {
-                gu.resolveBorder(guEnd, CommonBorderPaddingBackground.END);
+
+        abstract void endTable();
+    }
+
+    private class ResolverInHeader extends Resolver {
+
+        void endRow(List/*<GridUnit>*/ row, TableCellContainer container) {
+            super.endRow(row, container);
+            if (previousRow != null) {
+                resolveBordersBetweenRows(previousRow, row);
+            } else {
+                /*
+                 * This is a bit hacky...
+                 * The two only sensible values for border-before on the header's first row are:
+                 * - at the beginning of the table (normal case)
+                 * - if the header is repeated after each page break
+                 * To represent those values we (ab)use the nonLeadingTrailing and the rest
+                 * fields of ConditionalBorder. But strictly speaking this is not their
+                 * purposes.
+                 */
+                for (Iterator guIter = row.iterator(); guIter.hasNext();) {
+                    ConditionalBorder borderBefore = ((GridUnit) guIter.next()).borderBefore;
+                    borderBefore.leadingTrailing = null;
+                    borderBefore.rest = borderBefore.nonLeadingTrailing;
+                }
+                resolveBordersFirstRowInTable(row, false, true, true);
             }
-            gu = guEnd;
+            previousRow = row;
         }
-        gu.resolveBorder(CommonBorderPaddingBackground.END, container);
 
-        previousRow = row;
+        void endPart() {
+            super.endPart();
+            leadingBorders = new ArrayList(table.getNumberOfColumns());
+            /*
+             * Another hack...
+             * The border-after of a header is always the same. Leading and rest don't
+             * apply to cells in the header since they are never broken. To ease
+             * resolution we override the (normally unused) leadingTrailing and rest
+             * fields of ConditionalBorder with the only sensible nonLeadingTrailing
+             * field. That way grid units from the body will always resolve against the
+             * same, normal header border.
+             */
+            for (Iterator guIter = previousRow.iterator(); guIter.hasNext();) {
+                ConditionalBorder borderAfter = ((GridUnit) guIter.next()).borderAfter;
+                borderAfter.leadingTrailing = borderAfter.nonLeadingTrailing;
+                borderAfter.rest = borderAfter.nonLeadingTrailing;
+                leadingBorders.add(borderAfter);
+            }
+        }
+
+        void endTable() {
+            throw new IllegalStateException();
+        }
+    }
+
+    private class ResolverInFooter extends Resolver {
+
+        void endRow(List/*<GridUnit>*/ row, TableCellContainer container) {
+            super.endRow(row, container);
+            if (footerFirstRow == null) {
+                footerFirstRow = row;
+            } else {
+                // There is a previous row
+                resolveBordersBetweenRows(footerLastRow, row);
+            }
+            footerLastRow = row;
+        }
+
+        void endPart() {
+            resolveBordersLastRowInPart(footerLastRow, true, true, true);
+            trailingBorders = new ArrayList(table.getNumberOfColumns());
+            // See same method in ResolverInHeader for an explanation of the hack
+            for (Iterator guIter = footerFirstRow.iterator(); guIter.hasNext();) {
+                ConditionalBorder borderBefore = ((GridUnit) guIter.next()).borderBefore;
+                borderBefore.leadingTrailing = borderBefore.nonLeadingTrailing;
+                borderBefore.rest = borderBefore.nonLeadingTrailing;
+                trailingBorders.add(borderBefore);
+            }
+        }
+
+        void endTable() {
+            // Resolve after/before border between the last row of table-body and the
+            // first row of table-footer
+            resolveBordersBetweenRows(previousRow, footerFirstRow);
+            // See endRow method in ResolverInHeader for an explanation of the hack
+            for (Iterator guIter = footerLastRow.iterator(); guIter.hasNext();) {
+                ConditionalBorder borderAfter = ((GridUnit) guIter.next()).borderAfter;
+                borderAfter.leadingTrailing = null;
+                borderAfter.rest = borderAfter.nonLeadingTrailing;
+            }
+            resolveBordersLastRowInTable(footerLastRow, false, true, true);
+        }
+    }
+
+    private class ResolverInBody extends Resolver {
+
+        void endRow(List/*<GridUnit>*/ row, TableCellContainer container) {
+            super.endRow(row, container);
+            if (firstInTable) {
+                resolveBordersFirstRowInTable(row, true, true, true);
+            } else {
+                // Either there is a header, and then previousRow is set to the header's last row,
+                // or this is not the first row in the body, and previousRow is not null
+                resolveBordersBetweenRows(previousRow, row);
+                integrateLeadingBorders(row);
+            }
+            integrateTrailingBorders(row);
+            previousRow = row;
+        }
+
+        void endTable() {
+            if (resolverInFooter != null) {
+                resolverInFooter.endTable();
+            } else {
+                // Trailing and rest borders already resolved with integrateTrailingBorders
+                resolveBordersLastRowInTable(previousRow, false, true, false);
+            }
+        }
+    }
+
+    CollapsingBorderResolver(Table table) {
+        this.table = table;
+        firstInTable = true;
+    }
+
+    /** {@inheritDoc} */
+    public void endRow(List/*<GridUnit>*/ row, TableCellContainer container) {
+        delegate.endRow(row, container);
     }
 
     /** {@inheritDoc} */
     public void startPart(TableBody part) {
-        firstInPart = true;
-        currentTablePart = part;
-        if (part.isTableFooter()) {
-            inFooter = true;
-            previousRowSave = previousRow;
-            previousRow = null;
+        if (part.isTableHeader()) {
+            delegate = new ResolverInHeader();
+        } else {
+            if (leadingBorders == null) {
+                // No header, leading borders determined by the table
+                leadingBorders = new ArrayList(table.getNumberOfColumns());
+                for (Iterator colIter = table.getColumns().iterator(); colIter.hasNext();) {
+                    // See endRow method in ResolverInHeader for an explanation of the hack
+                    ConditionalBorder border = ((TableColumn) colIter.next()).borderBefore;
+                    border.leadingTrailing = border.rest;
+                    leadingBorders.add(border);
+                }
+            }
+            if (part.isTableFooter()) {
+                resolverInFooter = new ResolverInFooter();
+                delegate = resolverInFooter;
+            } else {
+                if (trailingBorders == null) {
+                    // No footer, trailing borders determined by the table
+                    trailingBorders = new ArrayList(table.getNumberOfColumns());
+                    for (Iterator colIter = table.getColumns().iterator(); colIter.hasNext();) {
+                        // See endRow method in ResolverInHeader for an explanation of the hack
+                        ConditionalBorder border = ((TableColumn) colIter.next()).borderAfter;
+                        border.leadingTrailing = border.rest;
+                        trailingBorders.add(border);
+                    }
+                }
+                delegate = new ResolverInBody();
+            }
         }
+        delegate.startPart(part);
     }
 
     /** {@inheritDoc} */
     public void endPart(TableBody part) {
-        // Resolve border-after for the last row in the part
-        for (int i = 0; i < previousRow.size(); i++) {
-            ((GridUnit) previousRow.get(i))
-                    .resolveBorder(CommonBorderPaddingBackground.AFTER, part);
-        }
-        if (inFooter) {
-            inFooter = false;
-            previousRow = previousRowSave;
-        }
+        delegate.endPart();
     }
 
     /** {@inheritDoc} */
     public void endTable() {
-        if (footerFirstRow != null) {
-            // Resolve after/before border between the last row of table-body and the
-            // first row of table-footer
-            for (int i = 0; i < footerFirstRow.size(); i++) {
-                GridUnit gu = (GridUnit) footerFirstRow.get(i);
-                GridUnit beforeGU = (GridUnit) previousRow.get(i);
-                gu.resolveBorder(beforeGU, CommonBorderPaddingBackground.BEFORE);
-            }
-        }
-        List lastRow;
-        if (footerLastRow != null) {
-            lastRow = footerLastRow;
-        } else {
-            lastRow = previousRow;
-        }
-        // Resolve border-after for the last row of the table
-        for (int i = 0; i < lastRow.size(); i++) {
-            TableColumn column = table.getColumn(i);
-            ((GridUnit) lastRow.get(i)).resolveBorder(CommonBorderPaddingBackground.AFTER, column);
-        }
+        delegate.endTable();
+        delegate = null;
     }
 }

Added: xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/flow/table/ConditionalBorder.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/flow/table/ConditionalBorder.java?rev=603945&view=auto
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/flow/table/ConditionalBorder.java (added)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/flow/table/ConditionalBorder.java Thu Dec 13 08:10:32 2007
@@ -0,0 +1,204 @@
+/*
+ * 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.fo.flow.table;
+
+import org.apache.fop.layoutmgr.table.CollapsingBorderModel;
+
+/**
+ * A class that holds the three possible values for a border-before/after on a table-cell,
+ * in the collapsing model. These three values are (for border-before, similar for
+ * border-after):
+ * <ul>
+ * <li>non-leading: common case, when a cell follows the cell before on a same page;</li>
+ * <li>leading: when the table is broken and the cell appears at the top of a page, in
+ * which case its border must be resolved with the header (or the top of the table)
+ * instead of with the previous cell;</li>
+ * <li>rest: when a cell is broken over several pages; same as leading but with
+ * conditionality taken into account.</li>
+ * </ul>
+ */
+public class ConditionalBorder {
+
+    /** Special case: the cell is at the top or the bottom of the page. */
+    BorderSpecification leadingTrailing;
+
+    /** Normal case, no break. */
+    BorderSpecification nonLeadingTrailing;
+
+    /** Special case: break inside the cell. */
+    BorderSpecification rest;
+
+    /** The model used to resolve borders. */
+    private CollapsingBorderModel collapsingBorderModel;
+
+    private ConditionalBorder(BorderSpecification leadingTrailing,
+            BorderSpecification nonLeadingTrailing, BorderSpecification rest,
+            CollapsingBorderModel collapsingBorderModel) {
+        this.leadingTrailing = leadingTrailing;
+        this.nonLeadingTrailing = nonLeadingTrailing;
+        this.rest = rest;
+        this.collapsingBorderModel = collapsingBorderModel;
+    }
+
+    /**
+     * Creates a new conditional border.
+     * 
+     * @param borderSpecification the border specification to take as a basis
+     * @param collapsingBorderModel the model that will be used to resolved borders
+     */
+    ConditionalBorder(BorderSpecification borderSpecification,
+            CollapsingBorderModel collapsingBorderModel) {
+        leadingTrailing = borderSpecification;
+        nonLeadingTrailing = leadingTrailing;
+        if (borderSpecification.getBorderInfo().getWidth().isDiscard()) {
+            rest = BorderSpecification.getDefaultBorder();
+        } else {
+            rest = leadingTrailing;
+        }
+        this.collapsingBorderModel = collapsingBorderModel;
+    }
+
+    /**
+     * Resolves and updates the relevant parts of this border as well as the given one.
+     * 
+     * @param competitor
+     * @param withLeadingTrailing
+     * @param withNonLeadingTrailing
+     * @param withRest
+     */
+    void resolve(ConditionalBorder competitor, boolean withLeadingTrailing,
+            boolean withNonLeadingTrailing, boolean withRest) {
+        if (withLeadingTrailing) {
+            BorderSpecification resolvedBorder = collapsingBorderModel.determineWinner(
+                    leadingTrailing, competitor.leadingTrailing);
+            if (resolvedBorder != null) {
+                leadingTrailing = resolvedBorder;
+                competitor.leadingTrailing = resolvedBorder;
+            }
+        }
+        if (withNonLeadingTrailing) {
+            BorderSpecification resolvedBorder = collapsingBorderModel.determineWinner(
+                    nonLeadingTrailing, competitor.nonLeadingTrailing);
+            if (resolvedBorder != null) {
+                nonLeadingTrailing = resolvedBorder;
+                competitor.nonLeadingTrailing = resolvedBorder;
+            }
+        }
+        if (withRest) {
+            BorderSpecification resolvedBorder = collapsingBorderModel.determineWinner(rest,
+                    competitor.rest);
+            if (resolvedBorder != null) {
+                rest = resolvedBorder;
+                competitor.rest = resolvedBorder;
+            }
+        }
+    }
+
+    /**
+     * Integrates the given segment in this border. Unlike for
+     * {@link #integrateSegment(ConditionalBorder, boolean, boolean, boolean)}, this
+     * method nicely handles the case where the CollapsingBorderModel returns null, by
+     * keeping the components to their old values.
+     * 
+     * @param competitor
+     * @param withLeadingTrailing
+     * @param withNonLeadingTrailing
+     * @param withRest
+     */
+    void integrateCompetingSegment(ConditionalBorder competitor, boolean withLeadingTrailing,
+            boolean withNonLeadingTrailing, boolean withRest) {
+        if (withLeadingTrailing) {
+            BorderSpecification resolvedBorder = collapsingBorderModel.determineWinner(
+                    leadingTrailing, competitor.leadingTrailing);
+            if (resolvedBorder != null) {
+                leadingTrailing = resolvedBorder;
+            }
+        }
+        if (withNonLeadingTrailing) {
+            BorderSpecification resolvedBorder = collapsingBorderModel.determineWinner(
+                    nonLeadingTrailing, competitor.nonLeadingTrailing);
+            if (resolvedBorder != null) {
+                nonLeadingTrailing = resolvedBorder;
+            }
+        }
+        if (withRest) {
+            BorderSpecification resolvedBorder = collapsingBorderModel.determineWinner(rest,
+                    competitor.rest);
+            if (resolvedBorder != null) {
+                rest = resolvedBorder;
+            }
+        }
+    }
+
+    /**
+     * Updates this border after taking into account the given segment. The
+     * CollapsingBorderModel is not expected to return null.
+     * 
+     * @param segment
+     * @param withLeadingTrailing
+     * @param withNonLeadingTrailing
+     * @param withRest
+     */
+    void integrateSegment(ConditionalBorder segment, boolean withLeadingTrailing,
+            boolean withNonLeadingTrailing, boolean withRest) {
+        if (withLeadingTrailing) {
+            leadingTrailing = collapsingBorderModel.determineWinner(leadingTrailing,
+                    segment.leadingTrailing);
+            assert leadingTrailing != null;
+        }
+        if (withNonLeadingTrailing) {
+            nonLeadingTrailing = collapsingBorderModel.determineWinner(nonLeadingTrailing,
+                    segment.nonLeadingTrailing);
+            assert nonLeadingTrailing != null;
+        }
+        if (withRest) {
+            rest = collapsingBorderModel.determineWinner(rest, segment.rest);
+            assert rest != null;
+        }
+    }
+
+    /**
+     * Returns a shallow copy of this border.
+     * 
+     * @return a copy of this border
+     */
+    ConditionalBorder copy() {
+        return new ConditionalBorder(leadingTrailing, nonLeadingTrailing, rest,
+                collapsingBorderModel);
+    }
+
+    /** {@inheritDoc} */
+    public String toString() {
+        return "{non-leading: " + nonLeadingTrailing + ", leading: " + leadingTrailing + ", rest: "
+                + rest + "}";
+    }
+
+    /**
+     * Returns a default border specification.
+     * 
+     * @param collapsingBorderModel the model that will be used to resolve borders
+     * @return a border with style 'none' for all of the three components
+     */
+    static ConditionalBorder getDefaultBorder(CollapsingBorderModel collapsingBorderModel) {
+        BorderSpecification defaultBorderSpec = BorderSpecification.getDefaultBorder();
+        return new ConditionalBorder(defaultBorderSpec, defaultBorderSpec, defaultBorderSpec,
+                collapsingBorderModel); 
+    }
+}

Propchange: xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/flow/table/ConditionalBorder.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/flow/table/ConditionalBorder.java
------------------------------------------------------------------------------
    svn:keywords = Id

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/flow/table/EmptyGridUnit.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/flow/table/EmptyGridUnit.java?rev=603945&r1=603944&r2=603945&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/flow/table/EmptyGridUnit.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/flow/table/EmptyGridUnit.java Thu Dec 13 08:10:32 2007
@@ -19,8 +19,6 @@
 
 package org.apache.fop.fo.flow.table;
 
-import org.apache.fop.fo.Constants;
-import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
 
 /**
  * GridUnit subclass for empty grid units.
@@ -40,10 +38,11 @@
     }
 
     /** {@inheritDoc} */
-    protected void setBorder(int side) {
-        resolvedBorders[side] = new BorderSpecification(
-                CommonBorderPaddingBackground.getDefaultBorderInfo(),
-                Constants.FO_TABLE_CELL);
+    protected void setBordersFromCell() {
+        borderBefore = ConditionalBorder.getDefaultBorder(collapsingBorderModel);
+        borderAfter = ConditionalBorder.getDefaultBorder(collapsingBorderModel);
+        borderStart = BorderSpecification.getDefaultBorder();
+        borderEnd = BorderSpecification.getDefaultBorder();
     }
 
     /** {@inheritDoc} */

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/flow/table/GridUnit.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/flow/table/GridUnit.java?rev=603945&r1=603944&r2=603945&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/flow/table/GridUnit.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/flow/table/GridUnit.java Thu Dec 13 08:10:32 2007
@@ -90,9 +90,12 @@
     /** flags for the grid unit */
     private byte flags = 0;
 
-    protected BorderSpecification[] resolvedBorders;
+    ConditionalBorder borderBefore;
+    ConditionalBorder borderAfter;
+    BorderSpecification borderStart;
+    BorderSpecification borderEnd;
 
-    private CollapsingBorderModel collapsingBorderModel;
+    protected CollapsingBorderModel collapsingBorderModel;
 
     /**
      * Creates a new grid unit.
@@ -156,26 +159,27 @@
         if (table.isSeparateBorderModel()) {
             assignBorderForSeparateBorderModel();
         } else {
-            resolvedBorders = new BorderSpecification[4];
             collapsingBorderModel = CollapsingBorderModel.getBorderModelFor(table
                     .getBorderCollapse());
-            if (rowSpanIndex == 0) {
-                setBorder(CommonBorderPaddingBackground.BEFORE);
-            }
-            if (isLastGridUnitRowSpan()) {
-                setBorder(CommonBorderPaddingBackground.AFTER);
-            }
-            if (colSpanIndex == 0) {
-                setBorder(CommonBorderPaddingBackground.START);
-            }
-            if (isLastGridUnitColSpan()) {
-                setBorder(CommonBorderPaddingBackground.END);
-            }
+            setBordersFromCell();
         }
     }
 
-    protected void setBorder(int side) {
-        resolvedBorders[side] = cell.resolvedBorders[side];
+    protected void setBordersFromCell() {
+        borderBefore = cell.borderBefore.copy();
+        if (rowSpanIndex > 0) {
+            borderBefore.nonLeadingTrailing = null;
+        }
+        borderAfter = cell.borderAfter.copy();
+        if (!isLastGridUnitRowSpan()) {
+            borderAfter.nonLeadingTrailing = null;
+        }
+        if (colSpanIndex == 0) {
+            borderStart = cell.borderStart;
+        }
+        if (isLastGridUnitColSpan()) {
+            borderEnd = cell.borderEnd;
+        }
     }
 
     public TableCell getCell() {
@@ -301,8 +305,30 @@
     }
 
     private void setBorderInfo(int side) {
-        if (resolvedBorders[side] != null) {
-            effectiveBorders.setBorderInfo(resolvedBorders[side].getBorderInfo(), side);
+        switch (side) {
+        case CommonBorderPaddingBackground.BEFORE:
+            if (borderBefore.nonLeadingTrailing/*TODO*/ != null) {
+                effectiveBorders.setBorderInfo(borderBefore.nonLeadingTrailing.getBorderInfo(),
+                        side);
+            }
+            break;
+        case CommonBorderPaddingBackground.AFTER:
+            if (borderAfter.nonLeadingTrailing/*TODO*/ != null) {
+                effectiveBorders.setBorderInfo(borderAfter.nonLeadingTrailing.getBorderInfo(),
+                        side);
+            }
+            break;
+        case CommonBorderPaddingBackground.START:
+            if (borderStart != null) {
+                effectiveBorders.setBorderInfo(borderStart.getBorderInfo(), side);
+            }
+            break;
+        case CommonBorderPaddingBackground.END:
+            if (borderEnd != null) {
+                effectiveBorders.setBorderInfo(borderEnd.getBorderInfo(), side);
+            }
+            break;
+        default: assert false;
         }
     }
 
@@ -332,26 +358,96 @@
      * CommonBorderPaddingBackground.BEFORE|AFTER|START|END)
      */
     void resolveBorder(GridUnit other, int side) {
-        BorderSpecification resolvedBorder = collapsingBorderModel.determineWinner(
-                resolvedBorders[side], other.resolvedBorders[CollapsingBorderModel
-                        .getOtherSide(side)]);
-        if (resolvedBorder != null) {
-            this.resolvedBorders[side] = resolvedBorder;
-            other.resolvedBorders[CollapsingBorderModel.getOtherSide(side)] = resolvedBorder;
+        switch (side) {
+        case CommonBorderPaddingBackground.BEFORE:
+            borderBefore.resolve(other.borderAfter, false, true, false);
+            break;
+        case CommonBorderPaddingBackground.AFTER:
+            borderAfter.resolve(other.borderBefore, false, true, false);
+            break;
+        case CommonBorderPaddingBackground.START:
+            BorderSpecification resolvedBorder = collapsingBorderModel.determineWinner(
+                    borderStart, other.borderEnd);
+            if (resolvedBorder != null) {
+                this.borderStart = resolvedBorder;
+                other.borderEnd = resolvedBorder;
+            }
+            break;
+        case CommonBorderPaddingBackground.END:
+            resolvedBorder = collapsingBorderModel.determineWinner(
+                    borderEnd, other.borderStart);
+            if (resolvedBorder != null) {
+                this.borderEnd = resolvedBorder;
+                other.borderStart = resolvedBorder;
+            }
+            break;
+        default: assert false;
         }
     }
 
     /**
-     * Resolves the border on the given side of this grid unit, comparing it against the
-     * same border of the given parent element.
+     * For the given side, integrates in the conflict resolution the border segment of the
+     * given parent element.
      * 
-     * @param side the side to resolve (one of
+     * @param side the side to consider (either CommonBorderPaddingBackground.BEFORE or
+     * AFTER)
+     * @param parent a table element whose corresponding border coincides on the given
+     * side
+     */
+    void integrateBorderSegment(int side, TableFObj parent, boolean withLeadingTrailing,
+            boolean withNonLeadingTrailing, boolean withRest) {
+        switch (side) {
+        case CommonBorderPaddingBackground.BEFORE:
+            borderBefore.integrateSegment(parent.borderBefore, withLeadingTrailing,
+                    withNonLeadingTrailing, withRest);
+            break;
+        case CommonBorderPaddingBackground.AFTER:
+            borderAfter.integrateSegment(parent.borderAfter, withLeadingTrailing,
+                    withNonLeadingTrailing, withRest);
+            break;
+        default: assert false;
+        }
+    }
+
+    /**
+     * For the given side, integrates in the conflict resolution the border segment of the
+     * given parent element.
+     * 
+     * @param side the side to consider (one of
      * CommonBorderPaddingBackground.BEFORE|AFTER|START|END)
-     * @param parent the parent element holding a competing border
+     * @param parent a table element whose corresponding border coincides on the given side
      */
-    void resolveBorder(int side, TableFObj parent) {
-        resolvedBorders[side] = collapsingBorderModel.determineWinner(resolvedBorders[side],
-                parent.resolvedBorders[side]);
+    void integrateBorderSegment(int side, TableFObj parent) {
+        switch (side) {
+        case CommonBorderPaddingBackground.BEFORE:
+        case CommonBorderPaddingBackground.AFTER:
+            integrateBorderSegment(side, parent, true, true, true);
+            break;
+        case CommonBorderPaddingBackground.START:
+            borderStart = collapsingBorderModel.determineWinner(borderStart,
+                    parent.borderStart);
+            break;
+        case CommonBorderPaddingBackground.END:
+            borderEnd = collapsingBorderModel.determineWinner(borderEnd,
+                    parent.borderEnd);
+            break;
+        default: assert false;
+        }
+    }
+
+    void integrateCompetingBorder(int side, ConditionalBorder competitor,
+            boolean withLeadingTrailing, boolean withNonLeadingTrailing, boolean withRest) {
+        switch (side) {
+        case CommonBorderPaddingBackground.BEFORE:
+            borderBefore.integrateCompetingSegment(competitor, withLeadingTrailing,
+                    withNonLeadingTrailing, withRest);
+            break;
+        case CommonBorderPaddingBackground.AFTER:
+            borderAfter.integrateCompetingSegment(competitor, withLeadingTrailing,
+                    withNonLeadingTrailing, withRest);
+            break;
+        default: assert false;
+        }
     }
 
     /**

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/flow/table/TableBody.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/flow/table/TableBody.java?rev=603945&r1=603944&r2=603945&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/flow/table/TableBody.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/flow/table/TableBody.java Thu Dec 13 08:10:32 2007
@@ -261,6 +261,10 @@
         return FO_TABLE_BODY;
     }
 
+    protected boolean isTableHeader() {
+        return false;
+    }
+
     protected boolean isTableFooter() {
         return false;
     }

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/flow/table/TableFObj.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/flow/table/TableFObj.java?rev=603945&r1=603944&r2=603945&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/flow/table/TableFObj.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/flow/table/TableFObj.java Thu Dec 13 08:10:32 2007
@@ -42,7 +42,10 @@
     private Numeric borderEndPrecedence;
     private Numeric borderStartPrecedence;
 
-    BorderSpecification[] resolvedBorders = new BorderSpecification[4]; // TODO
+    ConditionalBorder borderBefore;
+    ConditionalBorder borderAfter;
+    BorderSpecification borderStart;
+    BorderSpecification borderEnd;
 
     CollapsingBorderModel collapsingBorderModel;
     
@@ -200,7 +203,6 @@
         if (!inMarker() && !table.isSeparateBorderModel()) {
             collapsingBorderModel = CollapsingBorderModel.getBorderModelFor(table
                     .getBorderCollapse());
-            resolvedBorders = new BorderSpecification[4];
             setCollapsedBorders();
         }
     }
@@ -226,8 +228,23 @@
      * @param side one of CommonBorderPaddingBackground.BEFORE|AFTER|START|END
      */
     protected void createBorder(int side) {
-        resolvedBorders[side] = new BorderSpecification(getCommonBorderPaddingBackground()
-                .getBorderInfo(side), getNameId()); 
+        BorderSpecification borderSpec = new BorderSpecification(
+                getCommonBorderPaddingBackground().getBorderInfo(side), getNameId());
+        switch (side) {
+        case CommonBorderPaddingBackground.BEFORE:
+            borderBefore = new ConditionalBorder(borderSpec, collapsingBorderModel);
+            break;
+        case CommonBorderPaddingBackground.AFTER:
+            borderAfter = new ConditionalBorder(borderSpec, collapsingBorderModel);
+            break;
+        case CommonBorderPaddingBackground.START:
+            borderStart = borderSpec;
+            break;
+        case CommonBorderPaddingBackground.END:
+            borderEnd = borderSpec;
+            break;
+        default: assert false;
+        }
     }
 
     /**
@@ -240,7 +257,22 @@
      */
     protected void createBorder(int side, TableFObj competitor) {
         createBorder(side);
-        resolvedBorders[side] = collapsingBorderModel.determineWinner(resolvedBorders[side],
-                competitor.resolvedBorders[side]);
+        switch (side) {
+        case CommonBorderPaddingBackground.BEFORE:
+            borderBefore.integrateSegment(competitor.borderBefore, true, true, true);
+            break;
+        case CommonBorderPaddingBackground.AFTER:
+            borderAfter.integrateSegment(competitor.borderAfter, true, true, true);
+            break;
+        case CommonBorderPaddingBackground.START:
+            borderStart = collapsingBorderModel.determineWinner(borderStart,
+                    competitor.borderStart);
+            break;
+        case CommonBorderPaddingBackground.END:
+            borderEnd = collapsingBorderModel.determineWinner(borderEnd,
+                    competitor.borderEnd);
+            break;
+        default: assert false;
+        }
     }
 }

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/flow/table/TableHeader.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/flow/table/TableHeader.java?rev=603945&r1=603944&r2=603945&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/flow/table/TableHeader.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/flow/table/TableHeader.java Thu Dec 13 08:10:32 2007
@@ -66,4 +66,9 @@
     public int getNameId() {
         return FO_TABLE_HEADER;
     }
+
+    /** {@inheritDoc} */
+    protected boolean isTableHeader() {
+        return true;
+    }
 }

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/properties/CommonBorderPaddingBackground.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/properties/CommonBorderPaddingBackground.java?rev=603945&r1=603944&r2=603945&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/properties/CommonBorderPaddingBackground.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/fo/properties/CommonBorderPaddingBackground.java Thu Dec 13 08:10:32 2007
@@ -131,14 +131,68 @@
     private static BorderInfo defaultBorderInfo;
 
     /**
+     * A conditional length of value 0. Returned by the
+     * {@link CommonBorderPaddingBackground#getBorderInfo(int)} method when the
+     * corresponding border isn't specified, to avoid to callers painful checks for null.
+     */
+    private static class ConditionalNullLength extends CondLengthProperty {
+
+        /** {@inheritDoc} */
+        public Property getComponent(int cmpId) {
+            throw new UnsupportedOperationException();
+        }
+
+        /** {@inheritDoc} */
+        public Property getConditionality() {
+            throw new UnsupportedOperationException();
+        }
+
+        /** {@inheritDoc} */
+        public Length getLength() {
+            throw new UnsupportedOperationException();
+        }
+
+        /** {@inheritDoc} */
+        public Property getLengthComponent() {
+            throw new UnsupportedOperationException();
+        }
+
+        /** {@inheritDoc} */
+        public int getLengthValue() {
+            return 0;
+        }
+
+        /** {@inheritDoc} */
+        public int getLengthValue(PercentBaseContext context) {
+            return 0;
+        }
+
+        /** {@inheritDoc} */
+        public boolean isDiscard() {
+            return true;
+        }
+
+        /** {@inheritDoc} */
+        public void setComponent(int cmpId, Property cmpnValue, boolean isDefault) {
+            throw new UnsupportedOperationException();
+        }
+
+        /** {@inheritDoc} */
+        public String toString() {
+            return "CondLength[0mpt, discard]";
+        }
+    }
+
+    /**
      * Returns a default BorderInfo of style none.
      * 
      * @return a BorderInfo instance with style set to {@link Constants#EN_NONE}
      */
     public static synchronized BorderInfo getDefaultBorderInfo() {
         if (defaultBorderInfo == null) {
-            /* It is enough to set color and width to null, as they should never be consulted */
-            defaultBorderInfo = new BorderInfo(Constants.EN_NONE, null, null);
+            /* It is enough to set color to null, as it should never be consulted */
+            defaultBorderInfo = new BorderInfo(Constants.EN_NONE,
+                    new ConditionalNullLength(), null);
         }
         return defaultBorderInfo;
     }

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/table/CollapsingBorderModel.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/table/CollapsingBorderModel.java?rev=603945&r1=603944&r2=603945&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/table/CollapsingBorderModel.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/table/CollapsingBorderModel.java Thu Dec 13 08:10:32 2007
@@ -181,7 +181,22 @@
      * 
      * @param border1 a border specification
      * @param border2 another border specification
+     * @param discard true if the .conditionality component of the border width must be
+     * taken into account
      * @return the winning border, null if the two borders are equivalent
+     */
+    public abstract BorderSpecification determineWinner(BorderSpecification border1,
+            BorderSpecification border2, boolean discard);
+
+    /**
+     * Returns the border which wins the border conflict resolution. Same as
+     * {@link #determineWinner(BorderSpecification, BorderSpecification, boolean)
+     * determineWinner(border1, border2, false)}.
+     * 
+     * @param border1 a border specification
+     * @param border2 another border specification
+     * @return the winning border, null if the two borders are equivalent
+     * @see determineWinner
      */
     public abstract BorderSpecification determineWinner(BorderSpecification border1,
             BorderSpecification border2);

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/table/CollapsingBorderModelEyeCatching.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/table/CollapsingBorderModelEyeCatching.java?rev=603945&r1=603944&r2=603945&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/table/CollapsingBorderModelEyeCatching.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/table/CollapsingBorderModelEyeCatching.java Thu Dec 13 08:10:32 2007
@@ -21,6 +21,7 @@
 
 import org.apache.fop.fo.Constants;
 import org.apache.fop.fo.flow.table.BorderSpecification;
+import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
 import org.apache.fop.fo.properties.CommonBorderPaddingBackground.BorderInfo;
 
 /**
@@ -29,6 +30,27 @@
  * TODO Column groups are not yet checked in this algorithm!
  */
 public class CollapsingBorderModelEyeCatching extends CollapsingBorderModel {
+
+    /** {@inheritDoc} */
+    public BorderSpecification determineWinner(BorderSpecification border1,
+            BorderSpecification border2, boolean discard) {
+        BorderInfo bi1 = border1.getBorderInfo();
+        BorderInfo bi2 = border2.getBorderInfo();
+        if (discard) {
+            if (bi1.getWidth().isDiscard()) {
+                if (bi2.getWidth().isDiscard()) {
+                    return new BorderSpecification(
+                            CommonBorderPaddingBackground.getDefaultBorderInfo(), 0/*TODO*/);
+                } else {
+                    return border2;
+                }
+            } else if (bi2.getWidth().isDiscard()) {
+                return border1;
+            }
+        }
+        // Otherwise, fall back to the default resolution algorithm
+        return determineWinner(border1, border2);
+    }
 
     /** {@inheritDoc} */
     public BorderSpecification determineWinner(BorderSpecification border1,



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