]> source.dussan.org Git - xmlgraphics-fop.git/commitdiff
Added support for conditional borders (and paddings) in tables.
authorVincent Hennebert <vhennebert@apache.org>
Wed, 23 Jan 2008 15:22:05 +0000 (15:22 +0000)
committerVincent Hennebert <vhennebert@apache.org>
Wed, 23 Jan 2008 15:22:05 +0000 (15:22 +0000)
The proper borders are not selected yet between the header/footer and the body. There might still be a few glitches in some cases

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

28 files changed:
src/java/org/apache/fop/fo/flow/table/CollapsingBorderResolver.java
src/java/org/apache/fop/fo/flow/table/ConditionalBorder.java
src/java/org/apache/fop/fo/flow/table/FixedColRowGroupBuilder.java
src/java/org/apache/fop/fo/flow/table/GridUnit.java
src/java/org/apache/fop/fo/flow/table/PrimaryGridUnit.java
src/java/org/apache/fop/fo/flow/table/Table.java
src/java/org/apache/fop/layoutmgr/TraitSetter.java
src/java/org/apache/fop/layoutmgr/table/ActiveCell.java
src/java/org/apache/fop/layoutmgr/table/CellPart.java
src/java/org/apache/fop/layoutmgr/table/RowGroupLayoutManager.java
src/java/org/apache/fop/layoutmgr/table/RowPainter.java
src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java
src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java
src/java/org/apache/fop/layoutmgr/table/TableStepper.java
status.xml
test/fotree/unittests/table/collapsed-conditional-borders_test-generator.py
test/java/org/apache/fop/fo/flow/table/CollapsedConditionalBorderTestCase.java
test/java/org/apache/fop/fotreetest/FOTreeTestSuite.java
test/layoutengine/standard-testcases/table-cell_block_break-after.xml
test/layoutengine/standard-testcases/table-cell_span-combinations.xml
test/layoutengine/standard-testcases/table-row_break-before_break-after_2.xml
test/layoutengine/standard-testcases/table_border-collapse_collapse_conditionals.xml [new file with mode: 0644]
test/layoutengine/standard-testcases/table_border-collapse_collapse_spans_1.xml
test/layoutengine/standard-testcases/table_border-collapse_separate_border-spacing_2.xml
test/layoutengine/standard-testcases/table_border-collapse_separate_conditionals.xml [new file with mode: 0644]
test/layoutengine/standard-testcases/table_break-before_break-after.xml
test/layoutengine/standard-testcases/table_bug36403.xml
test/layoutengine/standard-testcases/table_empty-cells.xml

index 16fc55cfca4b3b84285900d5729869faa7caf05d..235f0504268121d4c4cd1e55bc45d09f0fe0367b 100644 (file)
@@ -47,12 +47,21 @@ class CollapsingBorderResolver implements BorderResolver {
 
     private Resolver delegate;
 
+    // Re-use the same ResolverInBody for every table-body
+    // Important to properly handle firstInBody!!
+    private Resolver resolverInBody = new ResolverInBody();
+
     private Resolver resolverInFooter;
 
     private List/*<ConditionalBorder>*/ leadingBorders;
 
     private List/*<ConditionalBorder>*/ trailingBorders;
 
+    /* TODO Temporary hack for resolved borders in header */
+    /* Currently the normal border is always used. */
+    private List/*<GridUnit>*/ headerLastRow = null;
+    /* End of temporary hack */
+
     /**
      * 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
@@ -184,14 +193,12 @@ class CollapsingBorderResolver implements BorderResolver {
                 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);
-                    }
+                    boolean first = (gu.getRowSpanIndex() == 0);
+                    boolean last = gu.isLastGridUnitRowSpan();
+                    gu.integrateBorderSegment(CommonBorderPaddingBackground.BEFORE, tableRow,
+                            first, first, true);
+                    gu.integrateBorderSegment(CommonBorderPaddingBackground.AFTER, tableRow,
+                            last, last, true);
                 }
             }
             if (firstInPart) {
@@ -249,7 +256,7 @@ class CollapsingBorderResolver implements BorderResolver {
                  */
                 for (Iterator guIter = row.iterator(); guIter.hasNext();) {
                     ConditionalBorder borderBefore = ((GridUnit) guIter.next()).borderBefore;
-                    borderBefore.leadingTrailing = null;
+                    borderBefore.leadingTrailing = borderBefore.nonLeadingTrailing;
                     borderBefore.rest = borderBefore.nonLeadingTrailing;
                 }
                 resolveBordersFirstRowInTable(row, false, true, true);
@@ -275,6 +282,9 @@ class CollapsingBorderResolver implements BorderResolver {
                 borderAfter.rest = borderAfter.nonLeadingTrailing;
                 leadingBorders.add(borderAfter);
             }
+            /* TODO Temporary hack for resolved borders in header */
+            headerLastRow = previousRow;
+            /* End of temporary hack */
         }
 
         void endTable() {
@@ -314,7 +324,7 @@ class CollapsingBorderResolver implements BorderResolver {
             // 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.leadingTrailing = borderAfter.nonLeadingTrailing;
                 borderAfter.rest = borderAfter.nonLeadingTrailing;
             }
             resolveBordersLastRowInTable(footerLastRow, false, true, true);
@@ -323,6 +333,8 @@ class CollapsingBorderResolver implements BorderResolver {
 
     private class ResolverInBody extends Resolver {
 
+        private boolean firstInBody = true;
+
         void endRow(List/*<GridUnit>*/ row, TableCellContainer container) {
             super.endRow(row, container);
             if (firstInTable) {
@@ -335,6 +347,13 @@ class CollapsingBorderResolver implements BorderResolver {
             }
             integrateTrailingBorders(row);
             previousRow = row;
+            if (firstInBody) {
+                firstInBody = false;
+                for (Iterator iter = row.iterator(); iter.hasNext();) {
+                    GridUnit gu = (GridUnit) iter.next();
+                    gu.borderBefore.leadingTrailing = gu.borderBefore.nonLeadingTrailing;
+                }
+            }
         }
 
         void endTable() {
@@ -343,6 +362,10 @@ class CollapsingBorderResolver implements BorderResolver {
             } else {
                 // Trailing and rest borders already resolved with integrateTrailingBorders
                 resolveBordersLastRowInTable(previousRow, false, true, false);
+                for (Iterator iter = previousRow.iterator(); iter.hasNext();) {
+                    GridUnit gu = (GridUnit) iter.next();
+                    gu.borderAfter.leadingTrailing = gu.borderAfter.nonLeadingTrailing;
+                }
             }
         }
     }
@@ -386,7 +409,7 @@ class CollapsingBorderResolver implements BorderResolver {
                         trailingBorders.add(border);
                     }
                 }
-                delegate = new ResolverInBody();
+                delegate = resolverInBody;
             }
         }
         delegate.startPart(part);
@@ -401,5 +424,19 @@ class CollapsingBorderResolver implements BorderResolver {
     public void endTable() {
         delegate.endTable();
         delegate = null;
+        /* TODO Temporary hack for resolved borders in header */
+        if (headerLastRow != null) {
+            for (Iterator iter = headerLastRow.iterator(); iter.hasNext();) {
+                GridUnit gu = (GridUnit) iter.next();
+                gu.borderAfter.leadingTrailing = gu.borderAfter.nonLeadingTrailing;
+            }
+        }
+        if (footerLastRow != null) {
+            for (Iterator iter = footerLastRow.iterator(); iter.hasNext();) {
+                GridUnit gu = (GridUnit) iter.next();
+                gu.borderAfter.leadingTrailing = gu.borderAfter.nonLeadingTrailing;
+            }
+        }
+        /* End of temporary hack */
     }
 }
index 4f3cca04666128fd65ce0024dfc729958bded858..4313b82a67ab183b3d677e74ab5bf6f505a9e2e8 100644 (file)
@@ -36,6 +36,12 @@ import org.apache.fop.layoutmgr.table.CollapsingBorderModel;
  */
 public class ConditionalBorder {
 
+    public static final int NORMAL = 0;
+
+    public static final int LEADING_TRAILING = 1;
+
+    public static final int REST = 2;
+
     /** Special case: the cell is at the top or the bottom of the page. */
     BorderSpecification leadingTrailing;
 
index 7df071191100054a52958dacbc036adae7b7f72d..2f8b0bbb8b99bfdb727bb207a9ed3ce27ad1f94c 100644 (file)
@@ -43,8 +43,6 @@ class FixedColRowGroupBuilder extends RowGroupBuilder {
     /** The rows belonging to this row group. List of List of {@link GridUnit}s. */
     private List/*<List<GridUnit>>*/ rows;
 
-    private boolean firstInTable = true;
-
     private boolean firstInPart = true;
 
     /** The last encountered row. This is the last row of the table if it has no footer. */
@@ -52,10 +50,6 @@ class FixedColRowGroupBuilder extends RowGroupBuilder {
 
     private BorderResolver borderResolver;
 
-    private boolean inFooter;
-
-    private List lastFooterRow;
-
     FixedColRowGroupBuilder(Table t) {
         super(t);
         numberOfColumns = t.getNumberOfColumns();
@@ -134,14 +128,6 @@ class FixedColRowGroupBuilder extends RowGroupBuilder {
             }
         }
         borderResolver.endRow(currentRow, container);
-        ((GridUnit) currentRow.get(0)).setFlag(GridUnit.IN_FIRST_COLUMN);
-        ((GridUnit) currentRow.get(numberOfColumns - 1)).setFlag(GridUnit.IN_LAST_COLUMN);
-        if (inFooter) {
-            lastFooterRow = currentRow;
-        } else if (firstInTable) {
-            setFlagForCols(GridUnit.FIRST_IN_TABLE, currentRow);
-            firstInTable = false;
-        }
         if (firstInPart) {
             setFlagForCols(GridUnit.FIRST_IN_PART, currentRow);
             firstInPart = false;
@@ -159,7 +145,6 @@ class FixedColRowGroupBuilder extends RowGroupBuilder {
     /** {@inheritDoc} */
     void startTablePart(TableBody part) {
         firstInPart = true;
-        inFooter = part.isTableFooter();
         borderResolver.startPart(part);
     }
 
@@ -171,18 +156,10 @@ class FixedColRowGroupBuilder extends RowGroupBuilder {
         }
         setFlagForCols(GridUnit.LAST_IN_PART, lastRow);
         borderResolver.endPart();
-        inFooter = false;
     }
 
     /** {@inheritDoc} */
     void endTable(TableBody lastTablePart) {
-        List lastTableRow;
-        if (lastFooterRow != null) {
-            lastTableRow = lastFooterRow;
-        } else {
-            lastTableRow = lastRow;
-        }
-        setFlagForCols(GridUnit.LAST_IN_TABLE, lastTableRow);
         borderResolver.endTable();
     }
 }
index d6d622d57aa028930a7ffbf747be11ee451c7a75..a583697f617ce2f16e42085780f36a5001b13935 100644 (file)
@@ -19,8 +19,6 @@
 
 package org.apache.fop.fo.flow.table;
 
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
 import org.apache.fop.fo.FONode;
 import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
 import org.apache.fop.fo.properties.CommonBorderPaddingBackground.BorderInfo;
@@ -31,37 +29,23 @@ import org.apache.fop.layoutmgr.table.CollapsingBorderModel;
  */
 public class GridUnit {
 
-    private static Log log = LogFactory.getLog(GridUnit.class);
-
-    /** Indicates that the grid unit is in the first column. */
-    public static final int IN_FIRST_COLUMN = 0;
-
-    /** Indicates that the grid unit is in the last column. */
-    public static final int IN_LAST_COLUMN = 1;
-
-    /** Indicates that the grid unit is in the first row of the table. */
-    public static final int FIRST_IN_TABLE = 2;
-
     /**
      * Indicates that the grid unit is in the first row of the table part (header, footer,
      * body).
      */
-    public static final int FIRST_IN_PART = 3;
+    public static final int FIRST_IN_PART = 0;
 
     /**
      * Indicates that the grid unit is in the last row of the table part (header, footer,
      * body).
      */
-    public static final int LAST_IN_PART = 4;
-
-    /** Indicates that the grid unit is in the last row of the table. */
-    public static final int LAST_IN_TABLE = 5;
+    public static final int LAST_IN_PART = 1;
 
     /** Indicates that the primary grid unit has a pending keep-with-next. */
-    public static final int KEEP_WITH_NEXT_PENDING = 6;
+    public static final int KEEP_WITH_NEXT_PENDING = 2;
 
     /** Indicates that the primary grid unit has a pending keep-with-previous. */
-    public static final int KEEP_WITH_PREVIOUS_PENDING = 7;
+    public static final int KEEP_WITH_PREVIOUS_PENDING = 3;
 
     /** Primary grid unit */
     private PrimaryGridUnit primary;
@@ -84,9 +68,6 @@ public class GridUnit {
     /** index of grid unit within cell in row direction */
     private int rowSpanIndex;
 
-    /** effective borders for a cell slot */
-    private CommonBorderPaddingBackground effectiveBorders;
-
     /** flags for the grid unit */
     private byte flags = 0;
 
@@ -156,29 +137,35 @@ public class GridUnit {
     }
 
     private void setBorders(Table table/*TODO*/) {
-        if (table.isSeparateBorderModel()) {
-            assignBorderForSeparateBorderModel();
-        } else {
+        if (!table.isSeparateBorderModel()) {
             collapsingBorderModel = CollapsingBorderModel.getBorderModelFor(table
                     .getBorderCollapse());
             setBordersFromCell();
         }
     }
 
+    /**
+     * Prepares the borders of this grid unit for upcoming resolution, in the collapsing
+     * model.
+     */
     protected void setBordersFromCell() {
         borderBefore = cell.borderBefore.copy();
         if (rowSpanIndex > 0) {
-            borderBefore.nonLeadingTrailing = null;
+            borderBefore.nonLeadingTrailing = BorderSpecification.getDefaultBorder();
         }
         borderAfter = cell.borderAfter.copy();
         if (!isLastGridUnitRowSpan()) {
-            borderAfter.nonLeadingTrailing = null;
+            borderAfter.nonLeadingTrailing = BorderSpecification.getDefaultBorder();
         }
         if (colSpanIndex == 0) {
             borderStart = cell.borderStart;
+        } else {
+            borderStart = BorderSpecification.getDefaultBorder();
         }
         if (isLastGridUnitColSpan()) {
             borderEnd = cell.borderEnd;
+        } else {
+            borderEnd = BorderSpecification.getDefaultBorder();
         }
     }
 
@@ -235,6 +222,11 @@ public class GridUnit {
         return cell == null;
     }
 
+    /**
+     * Returns the index of the column this grid unit belongs to.
+     * 
+     * @return the column index, 0-based
+     */
     public int getStartCol() {
         return startCol;
     }
@@ -264,89 +256,67 @@ public class GridUnit {
     }
 
     /**
-     * Returns a BorderInfo instance for a side of the currently applicable cell before
-     * border resolution (i.e. the value from the FO). A return value of null indicates an
-     * empty cell. See CollapsingBorderModel(EyeCatching) where this method is used.
+     * Returns the resolved border-before of this grid unit, in the collapsing-border
+     * model.
      * 
-     * @param side for which side to return the BorderInfo
-     * @return the requested BorderInfo instance or null if the grid unit is an empty cell
+     * @param which one of {@link ConditionalBorder#NORMAL},
+     * {@link ConditionalBorder#LEADING_TRAILING} or {@link ConditionalBorder#REST}
+     * @return the corresponding border
      */
-    public BorderInfo getOriginalBorderInfoForCell(int side) {
-        if (cell != null) {
-            return cell.getCommonBorderPaddingBackground().getBorderInfo(side);
-        } else {
+    public BorderInfo getBorderBefore(int which) {
+        switch (which) {
+        case ConditionalBorder.NORMAL:
+            return borderBefore.nonLeadingTrailing.getBorderInfo();
+        case ConditionalBorder.LEADING_TRAILING:
+            return borderBefore.leadingTrailing.getBorderInfo();
+        case ConditionalBorder.REST:
+            return borderBefore.rest.getBorderInfo();
+        default:
+            assert false;
             return null;
         }
     }
 
     /**
-     * @return the resolved normal borders for this grid unit
+     * Returns the resolved border-after of this grid unit, in the collapsing-border
+     * model.
+     * 
+     * @param which one of {@link ConditionalBorder#NORMAL},
+     * {@link ConditionalBorder#LEADING_TRAILING} or {@link ConditionalBorder#REST}
+     * @return the corresponding border
      */
-    public CommonBorderPaddingBackground getBorders() {
-        // TODO
-        if (effectiveBorders == null) {
-            effectiveBorders = new CommonBorderPaddingBackground();
-            setBorderInfo(CommonBorderPaddingBackground.BEFORE);
-            setBorderInfo(CommonBorderPaddingBackground.AFTER);
-            setBorderInfo(CommonBorderPaddingBackground.START);
-            setBorderInfo(CommonBorderPaddingBackground.END);
-            if (cell != null) {
-                effectiveBorders.setPadding(cell.getCommonBorderPaddingBackground());
-            }
-            if (log.isDebugEnabled()) {
-                log.debug(this + " resolved borders: " + "before="
-                        + effectiveBorders.getBorderBeforeWidth(false) + ", " + "after="
-                        + effectiveBorders.getBorderAfterWidth(false) + ", " + "start="
-                        + effectiveBorders.getBorderStartWidth(false) + ", " + "end="
-                        + effectiveBorders.getBorderEndWidth(false));
-            }
-        }
-        return effectiveBorders;
-    }
-
-    private void setBorderInfo(int 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;
+    public BorderInfo getBorderAfter(int which) {
+        switch (which) {
+        case ConditionalBorder.NORMAL:
+            return borderAfter.nonLeadingTrailing.getBorderInfo();
+        case ConditionalBorder.LEADING_TRAILING:
+            return borderAfter.leadingTrailing.getBorderInfo();
+        case ConditionalBorder.REST:
+            return borderAfter.rest.getBorderInfo();
+        default:
+            assert false;
+            return null;
         }
     }
 
     /**
-     * @return true if the grid unit has any borders.
+     * Returns the resolved border-start of this grid unit, in the collapsing-border
+     * model.
+     * 
+     * @return the corresponding border
      */
-    public boolean hasBorders() {
-        return (getBorders() != null) && getBorders().hasBorder();
+    public BorderInfo getBorderStart() {
+        return borderStart.getBorderInfo();
     }
 
     /**
-     * Assigns the borders from the given cell to this cell info. Used in case of separate
-     * border model.
+     * Returns the resolved border-end of this grid unit, in the collapsing-border
+     * model.
+     * 
+     * @return the corresponding border
      */
-    void assignBorderForSeparateBorderModel() {
-        if (cell != null) {
-            effectiveBorders = cell.getCommonBorderPaddingBackground();
-        }
+    public BorderInfo getBorderEnd() {
+        return borderEnd.getBorderInfo();
     }
 
     /**
index ae8db7ba7db1e430cadcbf4f86978be2bac01372..684fa58d13a64ab5137adeac530c17798f69915c 100644 (file)
@@ -24,6 +24,7 @@ import java.util.List;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
 import org.apache.fop.layoutmgr.ElementListUtils;
 import org.apache.fop.layoutmgr.table.TableCellLayoutManager;
 
@@ -46,6 +47,9 @@ public class PrimaryGridUnit extends GridUnit {
     /** The calculated size of the cell's content. (cached value) */
     private int contentLength = -1;
 
+    private boolean isSeparateBorderModel;
+    private int halfBorderSeparationBPD;
+
     /**
      * Creates a new primary grid unit.
      *
@@ -57,6 +61,9 @@ public class PrimaryGridUnit extends GridUnit {
      */
     PrimaryGridUnit(TableCell cell, TableRow row, TableColumn column, int startCol) {
         super(cell, row, column, startCol, 0, 0);
+        this.isSeparateBorderModel = column.getTable().isSeparateBorderModel(); // TODO
+        this.halfBorderSeparationBPD = column.getTable().getBorderSeparation().getBPD().getLength()
+                .getValue() / 2;  // TODO
         log.trace("PrimaryGridUnit created, row " + startRow + " col " + startCol);
     }
 
@@ -89,58 +96,120 @@ public class PrimaryGridUnit extends GridUnit {
     }
 
     /**
-     * @return half the maximum before border width of this cell.
+     * Returns the widths of the border-before and -after for this cell. In the separate
+     * border model the border-separation is included. In the collapsing model only half
+     * of them is counted, since the other halves belong to the neighbouring cells; also,
+     * the returned value is the maximum of the segments of each applicable grid unit.
+     * 
+     * @return the sum of the before and after border widths
      */
-    public int getHalfMaxBeforeBorderWidth() {
-        int value = 0;
-        if (getRows() != null) {
-            int before = 0;
-            //first row for before borders
-            GridUnit[] row = (GridUnit[])getRows().get(0);
-            for (int i = 0; i < row.length; i++) {
-                if (row[i].hasBorders()) {
-                    before = Math.max(before,
-                            row[i].getBorders().getBorderBeforeWidth(false));
+    public int getBeforeAfterBorderWidth() {
+        return getBeforeBorderWidth(0, ConditionalBorder.NORMAL)
+                + getAfterBorderWidth(ConditionalBorder.NORMAL);
+    }
+
+    /**
+     * Returns the width of the before-border for the given row-span of this cell. In the
+     * separate border model half of the border-separation is included. In the collapsing
+     * model only half of the border is counted, since the other half belongs to the
+     * preceding cell; also, the returned value is the maximum of the segments of each
+     * applicable grid unit.
+     * 
+     * @param rowIndex index of the span for which the border must be computed, 0-based
+     * @param which one of {@link ConditionalBorder#NORMAL},
+     * {@link ConditionalBorder#LEADING_TRAILING} or {@link ConditionalBorder#REST}
+     * @return the before border width
+     */
+    public int getBeforeBorderWidth(int rowIndex, int which) {
+        if (isSeparateBorderModel) {
+            if (getCell() == null) {
+                return 0;
+            } else {
+                CommonBorderPaddingBackground cellBorders = getCell()
+                        .getCommonBorderPaddingBackground();
+                switch (which) {
+                case ConditionalBorder.NORMAL:
+                case ConditionalBorder.LEADING_TRAILING:
+                    return cellBorders.getBorderBeforeWidth(false) + halfBorderSeparationBPD;
+                case ConditionalBorder.REST:
+                    if (cellBorders.getBorderInfo(CommonBorderPaddingBackground.BEFORE).getWidth()
+                            .isDiscard()) {
+                        return 0;
+                    } else {
+                        return cellBorders.getBorderBeforeWidth(true) + halfBorderSeparationBPD;
+                    }
+                default:
+                    assert false;
+                    return 0;
                 }
             }
-            value += before / 2;
         } else {
-            if (hasBorders()) {
-                value += getBorders().getBorderBeforeWidth(false) / 2;
+            int width = 0;
+            GridUnit[] row = (GridUnit[]) rows.get(rowIndex);
+            for (int i = 0; i < row.length; i++) {
+                width = Math.max(width,
+                        row[i].getBorderBefore(which).getRetainedWidth());
             }
+            return width / 2;
         }
-        return value;
     }
 
     /**
-     * @return half the maximum after border width of this cell.
+     * Returns the width of the before-after for the given row-span of this cell. In the
+     * separate border model half of the border-separation is included. In the collapsing
+     * model only half of the border is counted, since the other half belongs to the
+     * following cell; also, the returned value is the maximum of the segments of each
+     * applicable grid unit.
+     * 
+     * @param rowIndex index of the span for which the border must be computed, 0-based
+     * @param which one of {@link ConditionalBorder#NORMAL},
+     * {@link ConditionalBorder#LEADING_TRAILING} or {@link ConditionalBorder#REST}
+     * @return the after border width
      */
-    public int getHalfMaxAfterBorderWidth() {
-        int value = 0;
-        if (getRows() != null) {
-            //Last row for after borders
-            int after = 0;
-            GridUnit[] row = (GridUnit[])getRows().get(getRows().size() - 1);
-            for (int i = 0; i < row.length; i++) {
-                if (row[i].hasBorders()) {
-                    after = Math.max(after, row[i].getBorders().getBorderAfterWidth(false));
+    public int getAfterBorderWidth(int rowIndex, int which) {
+        if (isSeparateBorderModel) {
+            if (getCell() == null) {
+                return 0;
+            } else {
+                CommonBorderPaddingBackground cellBorders = getCell()
+                        .getCommonBorderPaddingBackground();
+                switch (which) {
+                case ConditionalBorder.NORMAL:
+                case ConditionalBorder.LEADING_TRAILING:
+                    return cellBorders.getBorderAfterWidth(false) + halfBorderSeparationBPD;
+                case ConditionalBorder.REST:
+                    if (cellBorders.getBorderInfo(CommonBorderPaddingBackground.AFTER).getWidth()
+                            .isDiscard()) {
+                        return 0;
+                    } else {
+                        return cellBorders.getBorderAfterWidth(true) + halfBorderSeparationBPD;
+                    }
+                default:
+                    assert false;
+                    return 0;
                 }
             }
-            value += after / 2;
         } else {
-            if (hasBorders()) {
-                value += getBorders().getBorderAfterWidth(false) / 2;
+            int width = 0;
+            GridUnit[] row = (GridUnit[]) rows.get(rowIndex);
+            for (int i = 0; i < row.length; i++) {
+                width = Math.max(width,
+                        row[i].getBorderAfter(which).getRetainedWidth());
             }
+            return width / 2;
         }
-        return value;
     }
 
     /**
-     * @return the sum of half the maximum before and after border
-     * widths of this cell.
+     * Returns the width of the before-after for the last row-span of this cell. See
+     * {@link #getAfterBorderWidth(int, int)}.
+     * 
+     * @param which one of {@link ConditionalBorder#NORMAL},
+     * {@link ConditionalBorder#LEADING_TRAILING} or {@link ConditionalBorder#REST}
+     * @return the after border width
      */
-    public int getHalfMaxBorderWidth() {
-        return getHalfMaxBeforeBorderWidth() + getHalfMaxAfterBorderWidth();
+    public int getAfterBorderWidth(int which) {
+        return getAfterBorderWidth(getCell().getNumberRowsSpanned() - 1, which);
     }
 
     /** @return the length of the cell content. */
@@ -201,18 +270,18 @@ public class PrimaryGridUnit extends GridUnit {
      */
     public int[] getStartEndBorderWidths() {
         int[] widths = new int[2];
-        if (rows == null) {
-            widths[0] = getBorders().getBorderStartWidth(false);
-            widths[1] = getBorders().getBorderEndWidth(false);
+        if (getCell() == null) {
+            return widths;
+        } else if (getCell().getTable().isSeparateBorderModel()) {
+            widths[0] = getCell().getCommonBorderPaddingBackground().getBorderStartWidth(false);
+            widths[1] = getCell().getCommonBorderPaddingBackground().getBorderEndWidth(false);
         } else {
             for (int i = 0; i < rows.size(); i++) {
                 GridUnit[] gridUnits = (GridUnit[])rows.get(i);
                 widths[0] = Math.max(widths[0],
-                        (gridUnits[0]).
-                            getBorders().getBorderStartWidth(false));
-                widths[1] = Math.max(widths[1],
-                        (gridUnits[gridUnits.length - 1]).
-                            getBorders().getBorderEndWidth(false));
+                        gridUnits[0].borderStart.getBorderInfo().getRetainedWidth());
+                widths[1] = Math.max(widths[1], gridUnits[gridUnits.length - 1].borderEnd
+                        .getBorderInfo().getRetainedWidth());
             }
         }
         return widths;
index a915edf87bbe623ae1d5365fa9745078aa20a92f..2b6570dcca733ee6c49596780282e6ead2a04a13 100644 (file)
@@ -395,7 +395,7 @@ public class Table extends TableFObj implements ColumnNumberManagerHolder {
      * @param index index of the column to be retrieved, 0-based
      * @return the corresponding column (may be an implicitly created column)
      */
-    TableColumn getColumn(int index) {
+    public TableColumn getColumn(int index) {
         return (TableColumn) columns.get(index);
     }
 
@@ -404,7 +404,7 @@ public class Table extends TableFObj implements ColumnNumberManagerHolder {
      * 
      * @return the number of columns, implicit or explicit, in this table
      */
-    int getNumberOfColumns() {
+    public int getNumberOfColumns() {
         return columns.size();
     }
 
index f1e5ffdc64a9d173c757698b3474d3fd73abe5f3..841a9470515fd094b923ca251b275e6594c98e3b 100644 (file)
@@ -21,7 +21,6 @@ package org.apache.fop.layoutmgr;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-
 import org.apache.fop.area.Area;
 import org.apache.fop.area.Trait;
 import org.apache.fop.datatypes.LengthBase;
@@ -31,6 +30,7 @@ import org.apache.fop.fo.Constants;
 import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
 import org.apache.fop.fo.properties.CommonMarginBlock;
 import org.apache.fop.fo.properties.CommonTextDecoration;
+import org.apache.fop.fo.properties.CommonBorderPaddingBackground.BorderInfo;
 import org.apache.fop.fonts.Font;
 import org.apache.fop.traits.BorderProps;
 import org.apache.fop.traits.MinOptMax;
@@ -178,32 +178,30 @@ public class TraitSetter {
      * Layout managers that create areas with borders can use this to
      * add the borders to the area.
      * @param area the area to set the traits on.
-     * @param bordProps border properties
+     * @param borderBefore the resolved before border
+     * @param borderAfter the resolved after border
+     * @param borderStart the resolved start border
+     * @param borderEnd the resolved end border
      * @param outer 4 boolean values indicating if the side represents the 
      *     table's outer border. Order: before, after, start, end
-     * @param context Property evaluation context
      */
-    public static void addCollapsingBorders(Area area, 
-            CommonBorderPaddingBackground bordProps,
-            boolean[] outer,
-            PercentBaseContext context) {
-        BorderProps bps = getCollapsingBorderProps(bordProps, 
-                CommonBorderPaddingBackground.BEFORE, outer[0]);
+    public static void addCollapsingBorders(Area area,
+            BorderInfo borderBefore, BorderInfo borderAfter,
+            BorderInfo borderStart, BorderInfo borderEnd,
+            boolean[] outer) {
+        BorderProps bps = getCollapsingBorderProps(borderBefore, outer[0]);
         if (bps != null) {
             area.addTrait(Trait.BORDER_BEFORE, bps);
         }
-        bps = getCollapsingBorderProps(bordProps, 
-                CommonBorderPaddingBackground.AFTER, outer[1]);
+        bps = getCollapsingBorderProps(borderAfter, outer[1]);
         if (bps != null) {
             area.addTrait(Trait.BORDER_AFTER, bps);
         }
-        bps = getCollapsingBorderProps(bordProps, 
-                CommonBorderPaddingBackground.START, outer[2]);
+        bps = getCollapsingBorderProps(borderStart, outer[2]);
         if (bps != null) {
             area.addTrait(Trait.BORDER_START, bps);
         }
-        bps = getCollapsingBorderProps(bordProps, 
-                CommonBorderPaddingBackground.END, outer[3]);
+        bps = getCollapsingBorderProps(borderEnd, outer[3]);
         if (bps != null) {
             area.addTrait(Trait.BORDER_END, bps);
         }
@@ -270,13 +268,11 @@ public class TraitSetter {
         }
     }
 
-    private static BorderProps getCollapsingBorderProps(
-            CommonBorderPaddingBackground bordProps, int side, boolean outer) {
-        int width = bordProps.getBorderWidth(side, false);
+    private static BorderProps getCollapsingBorderProps(BorderInfo borderInfo, boolean outer) {
+        assert borderInfo != null;
+        int width = borderInfo.getRetainedWidth();
         if (width != 0) {
-            BorderProps bps;
-            bps = new BorderProps(bordProps.getBorderStyle(side),
-                    width, bordProps.getBorderColor(side),
+            BorderProps bps = new BorderProps(borderInfo.getStyle(), width, borderInfo.getColor(),
                     (outer ? BorderProps.COLLAPSE_OUTER : BorderProps.COLLAPSE_INNER));
             return bps;
         } else {
index a1957eb27166758814c74bb87c7d75017c928d55..4321c32b8eff4c33ec975773aedef6d0dabc84b3 100644 (file)
@@ -22,9 +22,11 @@ package org.apache.fop.layoutmgr.table;
 import java.util.List;
 import java.util.ListIterator;
 
+import org.apache.fop.fo.flow.table.ConditionalBorder;
 import org.apache.fop.fo.flow.table.EffRow;
 import org.apache.fop.fo.flow.table.GridUnit;
 import org.apache.fop.fo.flow.table.PrimaryGridUnit;
+import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
 import org.apache.fop.layoutmgr.ElementListUtils;
 import org.apache.fop.layoutmgr.KnuthBox;
 import org.apache.fop.layoutmgr.KnuthElement;
@@ -39,15 +41,8 @@ class ActiveCell {
     private List elementList;
     /** Iterator over the Knuth element list. */
     private ListIterator knuthIter;
-    private boolean prevIsBox = false;
     /** Number of the row where the row-span ends, zero-based. */
     private int endRowIndex;
-    /** Index, in the list of Knuth elements, of the element starting the current step. */
-    private int start;
-    /** Index, in the list of Knuth elements, of the element ending the current step. */
-    private int end;
-    /** Length of the Knuth elements up to the next feasible break. */
-    private int nextStepLength;
     /** Length of the Knuth elements not yet included in the steps. */
     private int remainingLength;
     /** Heights of the rows (in the row-group) preceding the one where this cell starts. */
@@ -56,17 +51,81 @@ class ActiveCell {
     private int totalLength;
     /** Length of the Knuth elements already included in the steps. */
     private int includedLength;
-    private int borderBefore;
-    private int borderAfter;
-    private int paddingBefore;
-    private int paddingAfter;
+
+    private int borderBeforeNormal;
+    private int borderBeforeLeading;
+    private int borderAfterNormal;
+    private int borderAfterTrailing;
+    private int paddingBeforeNormal;
+    private int paddingBeforeLeading;
+    private int paddingAfterNormal;
+    private int paddingAfterTrailing;
+
     private boolean keepWithNextSignal;
-    /** Length of the penalty ending the last step, if any. */
-    private int lastPenaltyLength;
+
+    private int spanIndex = 0;
+    private CellPart lastCellPart;
+
+    private Step previousStep;
+    private Step nextStep;
+
+    /**
+     * Auxiliary class to store all the informations related to a breaking step.
+     */
+    private static class Step {
+        /** Index, in the list of Knuth elements, of the element starting this step. */
+        private int start;
+        /** Index, in the list of Knuth elements, of the element ending this step. */
+        private int end;
+        /** Length of the Knuth elements up to this step. */
+        private int contentLength;
+        /** Total length up to this step, including paddings and borders. */
+        private int totalLength;
+        /** Length of the penalty ending this step, if any. */
+        private int penaltyLength;
+        /**
+         * Length of the optional content for the next step. That is, content that will
+         * not appear if the next step starts a new page.
+         */
+        private int nextCondBeforeContentLength;
+
+        Step(int contentLength) {
+            this.contentLength = contentLength;
+            // TODO necessary if a cell part must be created while this cell hasn't
+            // contributed any content yet. To be removed along with the 900-penalty
+            // mechanism
+            this.end = -1;
+        }
+
+        Step(Step other) {
+            set(other);
+        }
+
+        void set(Step other) {
+            this.start         = other.start;
+            this.end           = other.end;
+            this.contentLength = other.contentLength;
+            this.totalLength   = other.totalLength;
+            this.penaltyLength = other.penaltyLength;
+            this.nextCondBeforeContentLength = other.nextCondBeforeContentLength;
+        }
+    }
 
     ActiveCell(PrimaryGridUnit pgu, EffRow row, int rowIndex, int previousRowsLength,
             TableLayoutManager tableLM) {
         this.pgu = pgu;
+        CommonBorderPaddingBackground bordersPaddings = pgu.getCell()
+                .getCommonBorderPaddingBackground();
+        borderBeforeNormal = pgu.getBeforeBorderWidth(0, ConditionalBorder.NORMAL);
+        borderBeforeLeading = pgu.getBeforeBorderWidth(0, ConditionalBorder.REST);
+        borderAfterNormal = pgu.getAfterBorderWidth(ConditionalBorder.NORMAL);
+        borderAfterTrailing = pgu.getAfterBorderWidth(0, ConditionalBorder.REST);
+        TableCellLayoutManager cellLM = pgu.getCellLM();
+        paddingBeforeNormal = bordersPaddings.getPaddingBefore(false, cellLM);
+        paddingBeforeLeading = bordersPaddings.getPaddingBefore(true, cellLM);
+        paddingAfterNormal = bordersPaddings.getPaddingAfter(false, cellLM);
+        paddingAfterTrailing = bordersPaddings.getPaddingAfter(true, cellLM);
+
         boolean makeBoxForWholeRow = false;
         if (row.getExplicitHeight().min > 0) {
             boolean contentsSmaller = ElementListUtils.removeLegalBreaks(
@@ -81,38 +140,24 @@ class ActiveCell {
         }
         if (makeBoxForWholeRow) {
             elementList = new java.util.ArrayList(1);
-            int height = row.getExplicitHeight().opt;
-            if (height == 0) {
-                height = row.getHeight().opt;
-            }
+            int height = row.getHeight().opt;
+            height -= 2 * tableLM.getHalfBorderSeparationBPD();
+            height -= borderBeforeNormal + borderAfterNormal;  // TODO conditionals
+            height -= paddingBeforeNormal + paddingAfterNormal;
             elementList.add(new KnuthBoxCellWithBPD(height));
         } else {
             elementList = pgu.getElements();
-//          if (log.isTraceEnabled()) {
-//  log.trace("column " + (column+1) + ": recording " + elementLists.size() + " element(s)");
-//          }
         }
         knuthIter = elementList.listIterator();
         includedLength = -1;  // Avoid troubles with cells having content of zero length
         this.previousRowsLength = previousRowsLength;
-        nextStepLength = previousRowsLength;
         totalLength = previousRowsLength + ElementListUtils.calcContentLength(elementList);
-        if (tableLM.getTable().isSeparateBorderModel()) {
-            borderBefore = pgu.getBorders().getBorderBeforeWidth(false)
-                    + tableLM.getHalfBorderSeparationBPD();
-            borderAfter = pgu.getBorders().getBorderAfterWidth(false)
-                    + tableLM.getHalfBorderSeparationBPD();
-        } else {
-            borderBefore = pgu.getHalfMaxBeforeBorderWidth();
-            borderAfter = pgu.getHalfMaxAfterBorderWidth();
-        }
-        paddingBefore = pgu.getBorders().getPaddingBefore(false, pgu.getCellLM());
-        paddingAfter = pgu.getBorders().getPaddingAfter(false, pgu.getCellLM());
-        start = 0;
-        end = -1;
         endRowIndex = rowIndex + pgu.getCell().getNumberRowsSpanned() - 1;
         keepWithNextSignal = false;
         remainingLength = totalLength - previousRowsLength;
+
+        nextStep = new Step(previousRowsLength);
+        previousStep = new Step(nextStep);
         goToNextLegalBreak();
     }
 
@@ -139,36 +184,48 @@ class ActiveCell {
         } else if (includedLength == totalLength) {
             return 0;
         } else {
-            return remainingLength + borderBefore + borderAfter + paddingBefore + paddingAfter;
+            return borderBeforeLeading + paddingBeforeLeading + remainingLength
+                    + paddingAfterNormal + borderAfterNormal;
         }
     }
 
     private void goToNextLegalBreak() {
-        lastPenaltyLength = 0;
+        nextStep.penaltyLength = 0;
         boolean breakFound = false;
+        boolean prevIsBox = false;
         while (!breakFound && knuthIter.hasNext()) {
             KnuthElement el = (KnuthElement) knuthIter.next();
             if (el.isPenalty()) {
                 prevIsBox = false;
                 if (el.getP() < KnuthElement.INFINITE) {
-                    //First legal break point
-                    lastPenaltyLength = el.getW();
+                    // First legal break point
+                    nextStep.penaltyLength = el.getW();
                     breakFound = true;
                 }
             } else if (el.isGlue()) {
                 if (prevIsBox) {
-                    //Second legal break point
+                    // Second legal break point
                     breakFound = true;
                 } else {
-                    nextStepLength += el.getW();
+                    nextStep.contentLength += el.getW();
                 }
                 prevIsBox = false;
             } else {
                 prevIsBox = true;
-                nextStepLength += el.getW();
+                nextStep.contentLength += el.getW();
             }
         }
-        end = knuthIter.nextIndex() - 1;
+        nextStep.end = knuthIter.nextIndex() - 1;
+        if (nextStep.end == elementList.size() - 1) {
+            // TODO wait that every cell on the row has finished before including border-after!!
+            nextStep.totalLength = borderBeforeNormal + paddingBeforeNormal
+                    + nextStep.contentLength + nextStep.penaltyLength
+                    + paddingAfterNormal + borderAfterNormal;
+        } else {
+            nextStep.totalLength = borderBeforeNormal + paddingBeforeNormal
+                    + nextStep.contentLength + nextStep.penaltyLength
+                    + paddingAfterTrailing + borderAfterTrailing; 
+        }
     }
 
     /**
@@ -177,23 +234,20 @@ class ActiveCell {
      * @return the total length up to the next legal break (-1 signals no further step)
      */
     int getNextStep() {
-        if (!includedInLastStep()) {
-            return nextStepLength + lastPenaltyLength 
-                    + borderBefore + borderAfter + paddingBefore + paddingAfter;
-        } else {
-            start = end + 1;
-            if (knuthIter.hasNext()) {
-                goToNextLegalBreak();
-                return nextStepLength + lastPenaltyLength 
-                        + borderBefore + borderAfter + paddingBefore + paddingAfter; 
-            } else {
+        if (includedInLastStep()) {
+            previousStep.set(nextStep);
+            nextStep.start = nextStep.end + 1;
+            if (!knuthIter.hasNext()) {
                 return -1;
+            } else {
+                goToNextLegalBreak();
             }
         }
+        return nextStep.totalLength;
     }
 
     private boolean includedInLastStep() {
-        return includedLength == nextStepLength;
+        return includedLength == nextStep.contentLength;
     }
 
     /**
@@ -204,14 +258,26 @@ class ActiveCell {
      * @return
      */
     boolean signalMinStep(int minStep) {
-        if (nextStepLength + lastPenaltyLength 
-                + borderBefore + borderAfter + paddingBefore + paddingAfter <= minStep) {
-            includedLength = nextStepLength;
+        if (nextStep.totalLength <= minStep) {
+            includedLength = nextStep.contentLength;
             computeRemainingLength();
             return false;
         } else {
-            return previousRowsLength + borderBefore 
-                    + borderAfter + paddingBefore + paddingAfter > minStep;
+            return borderBeforeNormal + paddingBeforeNormal + previousRowsLength
+                    + paddingAfterTrailing + borderAfterTrailing > minStep;
+        }
+    }
+
+    void endRow(int rowIndex) {
+        if (endsOnRow(rowIndex)) {
+            int bpAfterNormal = paddingAfterNormal + borderAfterNormal;
+            int bpAfterLast = paddingAfterNormal
+                    + pgu.getAfterBorderWidth(ConditionalBorder.LEADING_TRAILING);
+            lastCellPart.setLast(bpAfterNormal, bpAfterLast);
+        } else {
+            spanIndex++;
+            borderBeforeLeading = pgu.getBeforeBorderWidth(spanIndex, ConditionalBorder.REST);
+            borderAfterTrailing = pgu.getAfterBorderWidth(spanIndex, ConditionalBorder.REST);
         }
     }
 
@@ -221,13 +287,15 @@ class ActiveCell {
      * paddings are not considered here.
      */
     private void computeRemainingLength() {
-        remainingLength = totalLength - nextStepLength;
+        remainingLength = totalLength - nextStep.contentLength;
+        nextStep.nextCondBeforeContentLength = 0;
         // Save the current location in the element list
         int oldIndex = knuthIter.nextIndex();
         KnuthElement el;
         while (knuthIter.hasNext() && !(el = (KnuthElement) knuthIter.next()).isBox()) {
             if (el.isGlue()) {
                 remainingLength -= el.getW();
+                nextStep.nextCondBeforeContentLength += el.getW();
             }
         }
         // Reset the iterator to the current location
@@ -244,7 +312,7 @@ class ActiveCell {
     boolean contributesContent() {
         // return includedInLastStep() && the cell hasn't finished yet, otherwise there's
         // nothing more to contribute
-        return includedInLastStep() && end >= start;
+        return includedInLastStep() && nextStep.end >= nextStep.start;
     }
 
     /**
@@ -262,7 +330,7 @@ class ActiveCell {
      * @return true if the end of this cell is reached
      */
     boolean isFinished() {
-        return includedInLastStep() && (end == elementList.size() - 1);
+        return includedInLastStep() && (nextStep.end == elementList.size() - 1);
     }
 
     /**
@@ -272,7 +340,7 @@ class ActiveCell {
      * @return a CellPart instance
      */
     CellPart createCellPart() {
-        if (end + 1 == elementList.size()) {
+        if (nextStep.end + 1 == elementList.size()) {
             if (pgu.getFlag(GridUnit.KEEP_WITH_NEXT_PENDING)) {
                 keepWithNextSignal = true;
             }
@@ -280,22 +348,47 @@ class ActiveCell {
                 keepWithNextSignal = true;
             }
         }
-        if (start == 0 && end == 0
+        int bpBeforeNormal;
+        int bpBeforeFirst;
+        int bpAfterNormal;
+        int bpAfterLast;
+        if (nextStep.start == 0) {
+            bpBeforeNormal = borderBeforeNormal + paddingBeforeNormal;
+            bpBeforeFirst = pgu.getBeforeBorderWidth(0, ConditionalBorder.LEADING_TRAILING)
+                    + paddingBeforeNormal;
+        } else {
+            bpBeforeNormal = 0;
+            bpBeforeFirst = borderBeforeLeading + paddingBeforeLeading;
+        }
+        bpAfterNormal = 0;
+        bpAfterLast = paddingAfterTrailing + borderAfterTrailing;
+        int length = nextStep.contentLength - previousStep.contentLength
+                - previousStep.nextCondBeforeContentLength;
+        if (!includedInLastStep() || nextStep.start == elementList.size()) {
+            lastCellPart = new CellPart(pgu, nextStep.start, previousStep.end,
+                    0, 0, previousStep.penaltyLength,
+                    bpBeforeNormal, bpBeforeFirst, bpAfterNormal, bpAfterLast);
+        } else if (nextStep.start == 0 && nextStep.end == 0
                 && elementList.size() == 1
                 && elementList.get(0) instanceof KnuthBoxCellWithBPD) {
             //Special case: Cell with fixed BPD
-            return new CellPart(pgu, 0, pgu.getElements().size() - 1);
+            lastCellPart = new CellPart(pgu, 0, pgu.getElements().size() - 1,
+                    previousStep.nextCondBeforeContentLength, length, nextStep.penaltyLength,
+                    bpBeforeNormal, bpBeforeFirst, bpAfterNormal, bpAfterLast);
         } else {
-            return new CellPart(pgu, start, end);
+            lastCellPart = new CellPart(pgu, nextStep.start, nextStep.end,
+                    previousStep.nextCondBeforeContentLength, length, nextStep.penaltyLength,
+                    bpBeforeNormal, bpBeforeFirst, bpAfterNormal, bpAfterLast);
         }
+        return lastCellPart;
     }
 
     boolean isLastForcedBreak() {
-        return ((KnuthElement)elementList.get(end)).isForcedBreak();
+        return ((KnuthElement)elementList.get(nextStep.end)).isForcedBreak();
     }
 
     int getLastBreakClass() {
-        return ((KnuthPenalty)elementList.get(end)).getBreakClass();
+        return ((KnuthPenalty)elementList.get(nextStep.end)).getBreakClass();
     }
 
     boolean keepWithNextSignal() {
index bf5ad64cfebe3bd4f55296c296e204a0338750f8..f6c292f973c657fe78e3e47de1acc2f9076a39f0 100644 (file)
@@ -23,7 +23,7 @@ import org.apache.fop.fo.flow.table.GridUnit;
 import org.apache.fop.fo.flow.table.PrimaryGridUnit;
 
 /**
- * Represents a non-dividable part of a grid unit. Used by the table stepper.
+ * Represents a non-divisible part of a grid unit. Used by the table stepper.
  */
 class CellPart {
 
@@ -34,16 +34,47 @@ class CellPart {
     /** Index of the ending element of this part */
     protected int end;
 
+    private int condBeforeContentLength;
+    private int length;
+    private int condAfterContentLength;
+    private int bpBeforeNormal;
+    private int bpBeforeFirst;
+    private int bpAfterNormal;
+    private int bpAfterLast;
+    private boolean isLast;
+
     /**
      * Creates a new CellPart.
+     * 
      * @param pgu Primary grid unit
      * @param start starting element
      * @param end ending element
+     * @param condBeforeContentLength length of the additional content that will have to
+     * be displayed if this part will be the first one on the page
+     * @param length length of the content represented by this cell part
+     * @param condAfterContentLength length of the additional content that will have to be
+     * displayed if this part will be the last one on the page
+     * @param bpBeforeNormal width of border- and padding-before in the normal case
+     * @param bpBeforeFirst width of (possibly optional) border- and padding-before if
+     * this part will be the first one on the page
+     * @param bpAfterNormal width of border- and padding-after in the normal case
+     * @param bpAfterFirst width of (possibly optional) border- and padding-after if this
+     * part will be the last one on the page
      */
-    protected CellPart(PrimaryGridUnit pgu, int start, int end) {
+    protected CellPart(PrimaryGridUnit pgu, int start, int end,
+            int condBeforeContentLength, int length, int condAfterContentLength,
+            int bpBeforeNormal, int bpBeforeFirst,
+            int bpAfterNormal, int bpAfterLast) {
         this.pgu = pgu;
         this.start = start;
         this.end = end;
+        this.condBeforeContentLength = condBeforeContentLength;
+        this.length = length;
+        this.condAfterContentLength = condAfterContentLength;
+        this.bpBeforeNormal = bpBeforeNormal;
+        this.bpBeforeFirst = bpBeforeFirst;
+        this.bpAfterNormal = bpAfterNormal;
+        this.bpAfterLast = bpAfterLast;
     }
 
     /** @return true if this part is the first part of a cell */
@@ -52,8 +83,42 @@ class CellPart {
     }
 
     /** @return true if this part is the last part of a cell */
-    public boolean isLastPart() {
-        return (end >= 0 && end == pgu.getElements().size() - 1);
+    boolean isLastPart() {
+        return isLast;
+    }
+
+    void setLast(int bpNormal, int bpLast) {
+        isLast = true;
+        bpAfterNormal = bpNormal;
+        bpAfterLast = bpLast;
+    }
+
+    int getBorderPaddingBefore(boolean firstOnPage) {
+        if (firstOnPage) {
+            return bpBeforeFirst;
+        } else {
+            return bpBeforeNormal;
+        }
+    }
+
+    int getBorderPaddingAfter(boolean lastOnPage) {
+        if (lastOnPage) {
+            return bpAfterLast;
+        } else {
+            return bpAfterNormal;
+        }
+    }
+
+    int getConditionalBeforeContentLength() {
+        return condBeforeContentLength;
+    }
+
+    int getLength() {
+        return length;
+    }
+
+    int getConditionalAfterContentLength() {
+        return condAfterContentLength;
     }
 
     /** {@inheritDoc} */
index 3fa40a8fd59782b2bb5afd4918e4a38589ab2212..199af0fc1470bfdb3c95fbea86ba9b901b4c094b 100644 (file)
@@ -34,7 +34,6 @@ import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
 import org.apache.fop.fo.properties.LengthRangeProperty;
 import org.apache.fop.layoutmgr.BreakElement;
 import org.apache.fop.layoutmgr.ElementListObserver;
-import org.apache.fop.layoutmgr.ElementListUtils;
 import org.apache.fop.layoutmgr.KnuthElement;
 import org.apache.fop.layoutmgr.KnuthPenalty;
 import org.apache.fop.layoutmgr.LayoutContext;
@@ -239,13 +238,7 @@ class RowGroupLayoutManager {
                         effectiveCellBPD = Math.max(effectiveCellBPD, 
                                 primary.getContentLength());
                         
-                        int borderWidths;
-                        if (tableLM.getTable().isSeparateBorderModel()) {
-                            borderWidths = primary.getBorders().getBorderBeforeWidth(false)
-                                    + primary.getBorders().getBorderAfterWidth(false);
-                        } else {
-                            borderWidths = primary.getHalfMaxBorderWidth();
-                        }
+                        int borderWidths = primary.getBeforeAfterBorderWidth();
                         int padding = 0;
                         maxCellBPD = Math.max(maxCellBPD, effectiveCellBPD);
                         CommonBorderPaddingBackground cbpb 
@@ -253,8 +246,7 @@ class RowGroupLayoutManager {
                         padding += cbpb.getPaddingBefore(false, primary.getCellLM());
                         padding += cbpb.getPaddingAfter(false, primary.getCellLM());
                         int effRowHeight = effectiveCellBPD 
-                                + padding + borderWidths
-                                + 2 * tableLM.getHalfBorderSeparationBPD();
+                                + padding + borderWidths;
                         for (int previous = 0; previous < gu.getRowSpanIndex(); previous++) {
                             effRowHeight -= rowHeights[rgi - previous - 1].opt;
                         }
index 9a79d7744d97bcd0e05b59470a015c898b0c253d..f46b503bbe9d66b822b6aa8490ccb462d69f6e43 100644 (file)
@@ -26,16 +26,17 @@ import java.util.List;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+import org.apache.fop.fo.flow.table.ConditionalBorder;
 import org.apache.fop.fo.flow.table.EffRow;
 import org.apache.fop.fo.flow.table.GridUnit;
 import org.apache.fop.fo.flow.table.PrimaryGridUnit;
 import org.apache.fop.fo.flow.table.TableRow;
-import org.apache.fop.fo.properties.LengthRangeProperty;
 import org.apache.fop.layoutmgr.ElementListUtils;
 import org.apache.fop.layoutmgr.KnuthElement;
 import org.apache.fop.layoutmgr.KnuthPossPosIter;
 import org.apache.fop.layoutmgr.LayoutContext;
 import org.apache.fop.layoutmgr.SpaceResolver;
+import org.apache.fop.traits.BorderProps;
 
 class RowPainter {
     private static Log log = LogFactory.getLog(RowPainter.class);
@@ -50,6 +51,14 @@ class RowPainter {
      * Index of the first row of the current part present on the current page.
      */
     private int firstRowIndex;
+
+    /**
+     * Index of the very first row on the current page. Needed to properly handle
+     * {@link BorderProps#COLLAPSE_OUTER}. This is not the same as {@link #firstRowIndex}
+     * when the table has headers!
+     */
+    private int firstRowOnPageIndex;
+
     /**
      * Keeps track of the y-offsets of each row on a page.
      * This is particularly needed for spanned cells where you need to know the y-offset
@@ -57,36 +66,23 @@ class RowPainter {
      */
     private List rowOffsets = new ArrayList();
 
-    //These three variables are our buffer to recombine the individual steps into cells
-    /** Primary grid units corresponding to the currently handled grid units, per row. */
-    private PrimaryGridUnit[] primaryGridUnits;
-    /**
-     * Index, in the corresponding table cell's list of Knuth elements, of the first
-     * element present on the current page, per column.
-     */
-    private int[] start;
-    /**
-     * Index, in the corresponding table cell's list of Knuth elements, of the last
-     * element present on the current page, per column.
-     */
-    private int[] end;
-    /**
-     * Length, for each column, of the elements from the current cell put on the
-     * current page. This is the corresponding area's bpd.
-     */
-    private int[] partBPD;
+    private int[] cellHeights;
+    private boolean[] firstCellOnPage;
+    private CellPart[] firstCellParts;
+    private CellPart[] lastCellParts;
+
     private TableContentLayoutManager tclm;
 
     RowPainter(TableContentLayoutManager tclm, LayoutContext layoutContext) {
         this.tclm = tclm;
         this.layoutContext = layoutContext;
         this.colCount = tclm.getColumns().getColumnCount();
-        this.primaryGridUnits = new PrimaryGridUnit[colCount];
-        this.start = new int[colCount];
-        this.end = new int[colCount];
-        this.partBPD = new int[colCount];
+        this.cellHeights = new int[colCount];
+        this.firstCellOnPage = new boolean[colCount];
+        this.firstCellParts = new CellPart[colCount];
+        this.lastCellParts = new CellPart[colCount];
         this.firstRowIndex = -1;
-        Arrays.fill(end, -1);
+        this.firstRowOnPageIndex = -1;
     }
 
     int getAccumulatedBPD() {
@@ -101,7 +97,7 @@ class RowPainter {
      */
     void handleTableContentPosition(TableContentPosition tcpos) {
         if (tcpos.row != currentRow && currentRow != null) {
-            addAreasAndFlushRow(false);
+            addAreasAndFlushRow(false, false);
         }
         if (log.isDebugEnabled()) {
             log.debug("===handleTableContentPosition(" + tcpos);
@@ -110,6 +106,9 @@ class RowPainter {
         currentRow = tcpos.row;
         if (firstRowIndex < 0) {
             firstRowIndex = currentRow.getIndex();
+            if (firstRowOnPageIndex < 0) {
+                firstRowOnPageIndex = firstRowIndex;
+            }
         }
         Iterator partIter = tcpos.cellParts.iterator();
         //Iterate over all grid units in the current step
@@ -119,173 +118,153 @@ class RowPainter {
                 log.debug(">" + cellPart);
             }
             int colIndex = cellPart.pgu.getStartCol();
-            if (primaryGridUnits[colIndex] != cellPart.pgu) {
-                if (primaryGridUnits[colIndex] != null) {
-                    log.warn("Replacing GU in slot " + colIndex
-                            + ". Some content may not be painted.");
-                }
-                primaryGridUnits[colIndex] = cellPart.pgu;
-                start[colIndex] = cellPart.start;
-                end[colIndex] = cellPart.end;
+            if (firstCellParts[colIndex] == null) {
+                firstCellParts[colIndex] = cellPart;
+                cellHeights[colIndex] = cellPart.getBorderPaddingBefore(firstCellOnPage[colIndex]);
             } else {
-                if (cellPart.end < end[colIndex]) {
-                    throw new IllegalStateException("Internal Error: stepper problem");
-                }
-                end[colIndex] = cellPart.end;
+                assert firstCellParts[colIndex].pgu == cellPart.pgu; 
+                cellHeights[colIndex] += cellPart.getConditionalBeforeContentLength();
             }
+            cellHeights[colIndex] += cellPart.getLength();
+            lastCellParts[colIndex] = cellPart;
         }
     }
 
     /**
-     * Create the areas corresponding to the last row. This method is called either
-     * because the row is finished (all of the elements present on this row have been
-     * added), or because this is the last row on the current page, and the part of it
-     * lying on the current page must be drawn.
+     * Creates the areas corresponding to the last row. That is, an area with background
+     * for the row, plus areas for all the cells that finish on the row (not spanning over
+     * further rows).
      * 
-     * @param forcedFlush true if the elements must be drawn even if the row isn't
-     * finished yet (last row on the page), or if the row is the last of the current table
-     * part
+     * @param lastInPart true if the row is the last from its table part to be displayed
+     * on the current page. In which case all the cells must be flushed even if they
+     * aren't finished, plus the proper collapsed borders must be selected (trailing
+     * instead of normal, or rest if the cell is unfinished)
+     * @param lastOnPage true if the row is the very last row of the table that will be
+     * displayed on the current page. In which case collapsed after borders must be drawn
+     * in the outer mode
      */
-    void addAreasAndFlushRow(boolean forcedFlush) {
-        int actualRowHeight = 0;
-
+    void addAreasAndFlushRow(boolean lastInPart, boolean lastOnPage) {
         if (log.isDebugEnabled()) {
             log.debug("Remembering yoffset for row " + currentRow.getIndex() + ": "
                     + currentRowOffset);
         }
         recordRowOffset(currentRow.getIndex(), currentRowOffset);
 
-        for (int i = 0; i < primaryGridUnits.length; i++) {
-            if ((primaryGridUnits[i] != null)
-                    && (forcedFlush || (end[i] == primaryGridUnits[i].getElements().size() - 1))) {
-                actualRowHeight = Math.max(actualRowHeight, computeSpanHeight(
-                        primaryGridUnits[i], start[i], end[i], i));
+        // Need to compute the actual row height first
+        int actualRowHeight = 0;
+        for (int i = 0; i < colCount; i++) {
+            GridUnit currentGU = currentRow.getGridUnit(i);            
+            if (!currentGU.isEmpty() && currentGU.getColSpanIndex() == 0
+                    && (lastInPart || currentGU.isLastGridUnitRowSpan())) {
+                int cellHeight = cellHeights[i];
+                cellHeight += lastCellParts[i].getConditionalAfterContentLength();
+                cellHeight += lastCellParts[i].getBorderPaddingAfter(lastInPart);
+                int cellOffset = getRowOffset(Math.max(firstCellParts[i].pgu.getStartRow(),
+                        firstRowIndex));
+                actualRowHeight = Math.max(actualRowHeight, cellOffset + cellHeight
+                        - currentRowOffset);
             }
         }
-        actualRowHeight += 2 * tclm.getTableLM().getHalfBorderSeparationBPD();
 
-        //Add areas for row
+        // Then add areas for cells finishing on the current row
         tclm.addRowBackgroundArea(rowFO, actualRowHeight, layoutContext.getRefIPD(),
                 currentRowOffset);
-        for (int i = 0; i < primaryGridUnits.length; i++) {
+        for (int i = 0; i < colCount; i++) {
             GridUnit currentGU = currentRow.getGridUnit(i);            
             if (!currentGU.isEmpty() && currentGU.getColSpanIndex() == 0
-                    && (forcedFlush || currentGU.isLastGridUnitRowSpan())) {
-                addAreasForCell(currentGU.getPrimary(), start[i], end[i], currentRow, partBPD[i],
-                        actualRowHeight);
-                primaryGridUnits[i] = null;
-                start[i] = 0;
-                end[i] = -1;
-                partBPD[i] = 0;
+                    && (lastInPart || currentGU.isLastGridUnitRowSpan())) {
+                assert firstCellParts[i].pgu == currentGU.getPrimary();
+                int borderBeforeWhich;
+                if (firstCellParts[i].start == 0) {
+                    if (firstCellOnPage[i]) {
+                        borderBeforeWhich = ConditionalBorder.LEADING_TRAILING;
+                    } else {
+                        borderBeforeWhich = ConditionalBorder.NORMAL;
+                    }
+                } else {
+                    assert firstCellOnPage[i];
+                    borderBeforeWhich = ConditionalBorder.REST;
+                }
+                int borderAfterWhich;
+                if (lastCellParts[i].isLastPart()) {
+                    if (lastInPart) {
+                        borderAfterWhich = ConditionalBorder.LEADING_TRAILING;
+                    } else {
+                        borderAfterWhich = ConditionalBorder.NORMAL;
+                    }
+                } else {
+                    borderAfterWhich = ConditionalBorder.REST;
+                }
+                addAreasForCell(firstCellParts[i].pgu,
+                        firstCellParts[i].start, lastCellParts[i].end,
+                        actualRowHeight, borderBeforeWhich, borderAfterWhich,
+                        lastOnPage);
+                firstCellParts[i] = null;
+                firstCellOnPage[i] = false;
             }
         }
         currentRowOffset += actualRowHeight;
-        if (forcedFlush) {
-            // Either the end of the page is reached, then this was the last call of this
-            // method and we no longer care about currentRow; or the end of a table-part
-            // (header, footer, body) has been reached, and the next row will anyway be
-            // different from the current one, and this is unnecessary to recall this
-            // method in the first lines of handleTableContentPosition, so we may reset
-            // the following variables
+        if (lastInPart) {
+            /*
+             * Either the end of the page is reached, then this was the last call of this
+             * method and we no longer care about currentRow; or the end of a table-part
+             * (header, footer, body) has been reached, and the next row will anyway be
+             * different from the current one, and this is unnecessary to call this method
+             * again in the first lines of handleTableContentPosition, so we may reset the
+             * following variables.
+             */
             currentRow = null;
             firstRowIndex = -1;
             rowOffsets.clear();
+            /*
+             * The current table part has just been handled. Be it the first one or not,
+             * the header or the body, in any case the borders-before of the next row
+             * (i.e., the first row of the next part if any) must be painted in
+             * COLLAPSE_INNER mode. So the firstRowOnPageIndex indicator must be kept
+             * disabled. The following way is not the most elegant one but will be good
+             * enough.
+             */
+            firstRowOnPageIndex = Integer.MAX_VALUE;
         }
     }
 
-    /**
-     * Computes the total height of the part of the given cell spanning on the current
-     * active row, including borders and paddings. The bpd is also stored in partBPD, and
-     * it is ensured that the cell's or row's explicit height is respected.
-     * 
-     * @param pgu primary grid unit corresponding to the cell
-     * @param start index of the first element of the cell occuring on the current page
-     * @param end index of the last element of the cell occuring on the current page
-     * @param columnIndex column index of the cell
-     * @param bodyType {@link TableRowIterator#HEADER}, {@link TableRowIterator#FOOTER}, or
-     * {@link TableRowIterator#BODY}
-     * @return the cell's height
-     */
-    private int computeSpanHeight(PrimaryGridUnit pgu, int start, int end, int columnIndex) {
-        if (log.isTraceEnabled()) {
-            log.trace("getting len for " + columnIndex + " "
-                    + start + "-" + end);
-        }
-        int actualStart = start;
-        // Skip from the content length calculation glues and penalties occuring at the
+    // TODO this is not very efficient and should probably be done another way
+    // this method is only necessary when display-align = center or after, in which case
+    // the exact content length is needed to compute the size of the empty block that will
+    // be used as padding.
+    // This should be handled automatically by a proper use of Knuth elements
+    private int computeContentLength(PrimaryGridUnit pgu, int startIndex, int endIndex) {
+        int actualStart = startIndex;
+        // Skip from the content length calculation glues and penalties occurring at the
         // beginning of the page
-        while (actualStart <= end && !((KnuthElement)pgu.getElements().get(actualStart)).isBox()) {
+        while (actualStart <= endIndex
+                && !((KnuthElement) pgu.getElements().get(actualStart)).isBox()) {
             actualStart++;
         }
         int len = ElementListUtils.calcContentLength(
-                pgu.getElements(), actualStart, end);
-        KnuthElement el = (KnuthElement)pgu.getElements().get(end);
+                pgu.getElements(), actualStart, endIndex);
+        KnuthElement el = (KnuthElement)pgu.getElements().get(endIndex);
         if (el.isPenalty()) {
             len += el.getW();
         }
-        partBPD[columnIndex] = len;
-        if (log.isTraceEnabled()) {
-            log.trace("len of part: " + len);
-        }
-
-        if (start == 0) {
-            LengthRangeProperty bpd = pgu.getCell()
-                    .getBlockProgressionDimension();
-            if (!bpd.getMinimum(tclm.getTableLM()).isAuto()) {
-                int min = bpd.getMinimum(tclm.getTableLM())
-                            .getLength().getValue(tclm.getTableLM());
-                if (min > 0) {
-                    len = Math.max(len, min);
-                }
-            }
-            if (!bpd.getOptimum(tclm.getTableLM()).isAuto()) {
-                int opt = bpd.getOptimum(tclm.getTableLM())
-                            .getLength().getValue(tclm.getTableLM());
-                if (opt > 0) {
-                    len = Math.max(len, opt);
-                }
-            }
-            if (pgu.getRow() != null) {
-                bpd = pgu.getRow().getBlockProgressionDimension();
-                if (!bpd.getMinimum(tclm.getTableLM()).isAuto()) {
-                    int min = bpd.getMinimum(tclm.getTableLM()).getLength()
-                                .getValue(tclm.getTableLM());
-                    if (min > 0) {
-                        len = Math.max(len, min);
-                    }
-                }
-            }
-        }
-
-        // Add the padding if any
-        len += pgu.getBorders()
-                        .getPaddingBefore(false, pgu.getCellLM());
-        len += pgu.getBorders()
-                        .getPaddingAfter(false, pgu.getCellLM());
-
-        //Now add the borders to the contentLength
-        if (tclm.isSeparateBorderModel()) {
-            len += pgu.getBorders().getBorderBeforeWidth(false);
-            len += pgu.getBorders().getBorderAfterWidth(false);
-        } else {
-            len += pgu.getHalfMaxBeforeBorderWidth();
-            len += pgu.getHalfMaxAfterBorderWidth();
-        }
-        int cellOffset = getRowOffset(Math.max(pgu.getStartRow(), firstRowIndex));
-        len -= currentRowOffset - cellOffset;
         return len;
     }
 
     private void addAreasForCell(PrimaryGridUnit pgu, int startPos, int endPos,
-            EffRow row, int contentHeight, int rowHeight) {
-        //Determine the first row in this sequence
+            int rowHeight, int borderBeforeWhich, int borderAfterWhich, boolean lastOnPage) {
+        /*
+         * Determine the index of the first row of this cell that will be displayed on the
+         * current page.
+         */
         int startRowIndex = Math.max(pgu.getStartRow(), firstRowIndex);
         int currentRowIndex = currentRow.getIndex();
 
-        // In collapsing-border model, if the cell spans over several columns/rows then
-        // dedicated areas will be created for each grid unit to hold the corresponding
-        // borders. For that we need to know the height of each grid unit, that is of each
-        // grid row spanned over by the cell
+        /*
+         * In collapsing-border model, if the cell spans over several columns/rows then
+         * dedicated areas will be created for each grid unit to hold the corresponding
+         * borders. For that we need to know the height of each grid unit, that is of each
+         * grid row spanned over by the cell
+         */
         int[] spannedGridRowHeights = null;
         if (!tclm.getTableLM().getTable().isSeparateBorderModel() && pgu.hasSpanning()) {
             spannedGridRowHeights = new int[currentRowIndex - startRowIndex + 1];
@@ -297,24 +276,19 @@ class RowPainter {
             }
             spannedGridRowHeights[currentRowIndex - startRowIndex] = rowHeight;
         }
-
         int cellOffset = getRowOffset(startRowIndex);
-        int effCellHeight = rowHeight;
-        effCellHeight += currentRowOffset - cellOffset;
+        int cellTotalHeight = rowHeight + currentRowOffset - cellOffset;
         if (log.isDebugEnabled()) {
             log.debug("Creating area for cell:");
-            log.debug("  current row: " + row.getIndex());
             log.debug("  start row: " + pgu.getStartRow() + " " + currentRowOffset + " "
                     + cellOffset);
-            log.debug("  contentHeight: " + contentHeight + " rowHeight=" + rowHeight
-                    + " effCellHeight=" + effCellHeight);
+            log.debug(" rowHeight=" + rowHeight + " cellTotalHeight=" + cellTotalHeight);
         }
         TableCellLayoutManager cellLM = pgu.getCellLM();
         cellLM.setXOffset(tclm.getXOffsetOfGridUnit(pgu));
         cellLM.setYOffset(cellOffset);
-        cellLM.setContentHeight(contentHeight);
-        cellLM.setRowHeight(effCellHeight);
-        //cellLM.setRowHeight(row.getHeight().opt);
+        cellLM.setContentHeight(computeContentLength(pgu, startPos, endPos));
+        cellLM.setTotalHeight(cellTotalHeight);
         int prevBreak = ElementListUtils.determinePreviousBreak(pgu.getElements(), startPos);
         if (endPos >= 0) {
             SpaceResolver.performConditionalsNotification(pgu.getElements(),
@@ -322,7 +296,8 @@ class RowPainter {
         }
         cellLM.addAreas(new KnuthPossPosIter(pgu.getElements(), startPos, endPos + 1),
                 layoutContext, spannedGridRowHeights, startRowIndex - pgu.getStartRow(),
-                currentRowIndex - pgu.getStartRow() + 1);
+                currentRowIndex - pgu.getStartRow(), borderBeforeWhich, borderAfterWhich,
+                startRowIndex == firstRowOnPageIndex, lastOnPage);
     }
 
     /**
@@ -358,4 +333,14 @@ class RowPainter {
     private int getRowOffset(int rowIndex) {
         return ((Integer) rowOffsets.get(rowIndex - firstRowIndex)).intValue();
     }
+
+    // TODO get rid of that
+    void startBody() {
+        Arrays.fill(firstCellOnPage, true);
+    }
+
+    // TODO get rid of that
+    void endBody() {
+        Arrays.fill(firstCellOnPage, false);
+    }
 }
index 63810e05764fbcc1dff6531114e47f893570186c..421d3d58090f2f1b78ce74e83250ac6466d31f4b 100644 (file)
@@ -28,11 +28,13 @@ import org.apache.fop.area.Block;
 import org.apache.fop.area.Trait;
 import org.apache.fop.datatypes.PercentBaseContext;
 import org.apache.fop.fo.FONode;
+import org.apache.fop.fo.flow.table.ConditionalBorder;
 import org.apache.fop.fo.flow.table.GridUnit;
 import org.apache.fop.fo.flow.table.PrimaryGridUnit;
 import org.apache.fop.fo.flow.table.Table;
 import org.apache.fop.fo.flow.table.TableCell;
 import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
+import org.apache.fop.fo.properties.CommonBorderPaddingBackground.BorderInfo;
 import org.apache.fop.layoutmgr.AreaAdditionUtil;
 import org.apache.fop.layoutmgr.BlockLevelLayoutManager;
 import org.apache.fop.layoutmgr.BlockStackingLayoutManager;
@@ -47,6 +49,7 @@ import org.apache.fop.layoutmgr.Position;
 import org.apache.fop.layoutmgr.PositionIterator;
 import org.apache.fop.layoutmgr.SpaceResolver;
 import org.apache.fop.layoutmgr.TraitSetter;
+import org.apache.fop.traits.BorderProps;
 import org.apache.fop.traits.MinOptMax;
 
 /**
@@ -65,8 +68,6 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager
 
     private Block curBlockArea;
 
-    private int inRowIPDOffset;
-
     private int xoffset;
     private int yoffset;
     private int cellIPD;
@@ -137,7 +138,8 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager
             startIndent /= 2;
             endIndent /= 2;
         }
-        startIndent += getTableCell().getCommonBorderPaddingBackground().getPaddingStart(false, this);
+        startIndent += getTableCell().getCommonBorderPaddingBackground().getPaddingStart(false,
+                this);
         endIndent += getTableCell().getCommonBorderPaddingBackground().getPaddingEnd(false, this);
         return startIndent + endIndent;
     }
@@ -271,15 +273,6 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager
         xoffset = off;
     }
 
-    /**
-     * Set the IPD offset of this cell inside the table-row.
-     * This offset is used to determine the absolute position of the cell.
-     * @param off the IPD offset
-     */
-    public void setInRowIPDOffset(int off) {
-        this.inRowIPDOffset = off;
-    }
-
     /**
      * Set the content height for this cell. This method is used during
      * addAreas() stage.
@@ -291,36 +284,15 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager
     }
 
     /**
-     * Set the row height that contains this cell. This method is used during
-     * addAreas() stage.
-     *
-     * @param h the height of the row
+     * Sets the total height of this cell on the current page. That is, the cell's bpd
+     * plus before and after borders and paddings, plus the table's border-separation.
+     * 
+     * @param h the height of cell
      */
-    public void setRowHeight(int h) {
+    public void setTotalHeight(int h) {
         rowHeight = h;
     }
 
-    /**
-     * Returns the bpd of the given grid unit.
-     * @param gu a grid unit belonging to this cell
-     * @return the content height of the grid unit
-     */
-    private int getContentHeight(GridUnit gu) {
-        int bpd = rowHeight;
-        if (isSeparateBorderModel()) {
-            bpd -= gu.getPrimary().getBorders().getBorderBeforeWidth(false);
-            bpd -= gu.getPrimary().getBorders().getBorderAfterWidth(false);
-        } else {
-            bpd -= gu.getPrimary().getHalfMaxBorderWidth();
-        }
-        CommonBorderPaddingBackground cbpb
-            = gu.getCell().getCommonBorderPaddingBackground();
-        bpd -= cbpb.getPaddingBefore(false, this);
-        bpd -= cbpb.getPaddingAfter(false, this);
-        bpd -= 2 * ((TableLayoutManager)getParent()).getHalfBorderSeparationBPD();
-        return bpd;
-    }
-
     /**
      * Add the areas for the break points. The cell contains block stacking layout
      * managers that add block areas.
@@ -336,99 +308,151 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager
      * of each spanned grid row
      * @param startRow first grid row on the current page spanned over by the cell,
      * inclusive
-     * @param endRow last grid row on the current page spanned over by the cell, exclusive
+     * @param endRow last grid row on the current page spanned over by the cell, inclusive
+     * @param borderBeforeWhich one of {@link ConditionalBorder#NORMAL},
+     * {@link ConditionalBorder#LEADING_TRAILING} or {@link ConditionalBorder#REST}
+     * @param borderAfterWhich one of {@link ConditionalBorder#NORMAL},
+     * {@link ConditionalBorder#LEADING_TRAILING} or {@link ConditionalBorder#REST}
+     * @param firstOnPage true if the cell will be the very first one on the page, in
+     * which case collapsed before borders must be drawn in the outer mode
+     * @param lastOnPage true if the cell will be the very last one on the page, in which
+     * case collapsed after borders must be drawn in the outer mode
      */
     public void addAreas(PositionIterator parentIter,
                          LayoutContext layoutContext,
                          int[] spannedGridRowHeights,
                          int startRow,
-                         int endRow) {
+                         int endRow,
+                         int borderBeforeWhich,
+                         int borderAfterWhich,
+                         boolean firstOnPage,
+                         boolean lastOnPage) {
         getParentArea(null);
 
         getPSLM().addIDToPage(getTableCell().getId());
 
+        int borderBeforeWidth = primaryGridUnit.getBeforeBorderWidth(startRow, borderBeforeWhich);
+        int borderAfterWidth = primaryGridUnit.getAfterBorderWidth(endRow, borderAfterWhich);
         if (isSeparateBorderModel()) {
             if (!emptyCell || getTableCell().showEmptyCells()) {
-                TraitSetter.addBorders(curBlockArea, getTableCell().getCommonBorderPaddingBackground(),
-                        false, false, false, false, this);
-                TraitSetter.addPadding(curBlockArea, getTableCell().getCommonBorderPaddingBackground(),
-                        false, false, false, false, this);
+                if (borderBeforeWidth > 0) {
+                    int halfBorderSepBPD = getTableCell().getTable().getBorderSeparation().getBPD()
+                            .getLength().getValue() / 2;
+                    adjustYOffset(curBlockArea, halfBorderSepBPD);
+                }
+                TraitSetter.addBorders(curBlockArea,
+                        getTableCell().getCommonBorderPaddingBackground(),
+                        borderBeforeWidth == 0, borderAfterWidth == 0,
+                        false, false, this);
             }
         } else {
+            boolean inFirstColumn = (primaryGridUnit.getStartCol() == 0);
+            boolean inLastColumn = (primaryGridUnit.getStartCol()
+                    + getTableCell().getNumberColumnsSpanned() == getTable()
+                    .getNumberOfColumns());
             if (!primaryGridUnit.hasSpanning()) {
+                adjustYOffset(curBlockArea, -borderBeforeWidth);
                 //Can set the borders directly if there's no span
-                boolean[] outer = new boolean[] {
-                        primaryGridUnit.getFlag(GridUnit.FIRST_IN_TABLE),
-                        primaryGridUnit.getFlag(GridUnit.LAST_IN_TABLE),
-                        primaryGridUnit.getFlag(GridUnit.IN_FIRST_COLUMN),
-                        primaryGridUnit.getFlag(GridUnit.IN_LAST_COLUMN)};
+                boolean[] outer = new boolean[] {firstOnPage, lastOnPage, inFirstColumn,
+                        inLastColumn};
                 TraitSetter.addCollapsingBorders(curBlockArea,
-                        primaryGridUnit.getBorders(), outer, this);
+                        primaryGridUnit.getBorderBefore(borderBeforeWhich),
+                        primaryGridUnit.getBorderAfter(borderAfterWhich),
+                        primaryGridUnit.getBorderStart(),
+                        primaryGridUnit.getBorderEnd(), outer);
             } else {
-                boolean[] outer = new boolean[4];
+                adjustYOffset(curBlockArea, borderBeforeWidth);
+                Block[][] blocks = new Block[getTableCell().getNumberRowsSpanned()][getTableCell()
+                        .getNumberColumnsSpanned()];
+                GridUnit[] gridUnits = (GridUnit[]) primaryGridUnit.getRows().get(startRow);
+                for (int x = 0; x < getTableCell().getNumberColumnsSpanned(); x++) {
+                    GridUnit gu = gridUnits[x];
+                    BorderInfo border = gu.getBorderBefore(borderBeforeWhich);
+                    int borderWidth = border.getRetainedWidth() / 2;
+                    if (borderWidth > 0) {
+                        addBorder(blocks, startRow, x, Trait.BORDER_BEFORE, border, firstOnPage);
+                        adjustYOffset(blocks[startRow][x], -borderWidth);
+                        adjustBPD(blocks[startRow][x], -borderWidth);
+                    }
+                }
+                gridUnits = (GridUnit[]) primaryGridUnit.getRows().get(endRow);
+                for (int x = 0; x < getTableCell().getNumberColumnsSpanned(); x++) {
+                    GridUnit gu = gridUnits[x];
+                    BorderInfo border = gu.getBorderAfter(borderAfterWhich);
+                    int borderWidth = border.getRetainedWidth() / 2;
+                    if (borderWidth > 0) {
+                        addBorder(blocks, endRow, x, Trait.BORDER_AFTER, border, lastOnPage);
+                        adjustBPD(blocks[endRow][x], -borderWidth);
+                    }
+                }
+                for (int y = startRow; y <= endRow; y++) {
+                    gridUnits = (GridUnit[]) primaryGridUnit.getRows().get(y);
+                    BorderInfo border = gridUnits[0].getBorderStart();
+                    int borderWidth = border.getRetainedWidth() / 2;
+                    if (borderWidth > 0) {
+                        addBorder(blocks, y, 0, Trait.BORDER_START, border, inFirstColumn);
+                        adjustXOffset(blocks[y][0], borderWidth);
+                        adjustIPD(blocks[y][0], -borderWidth);
+                    }
+                    border = gridUnits[gridUnits.length - 1].getBorderEnd();
+                    borderWidth = border.getRetainedWidth() / 2;
+                    if (borderWidth > 0) {
+                        addBorder(blocks, y, gridUnits.length - 1, Trait.BORDER_END, border,
+                                inLastColumn);
+                        adjustIPD(blocks[y][gridUnits.length - 1], -borderWidth);
+                    }
+                }
                 int dy = yoffset;
-                for (int y = startRow; y < endRow; y++) {
-                    GridUnit[] gridUnits = (GridUnit[])primaryGridUnit.getRows().get(y);
+                for (int y = startRow; y <= endRow; y++) {
+                    int bpd = spannedGridRowHeights[y - startRow];
                     int dx = xoffset;
                     for (int x = 0; x < gridUnits.length; x++) {
-                        GridUnit gu = gridUnits[x];
-                        if (gu.hasBorders()) {
-                            //Blocks for painting grid unit borders
-                            Block block = new Block();
-                            block.addTrait(Trait.IS_REFERENCE_AREA, Boolean.TRUE);
-                            block.setPositioning(Block.ABSOLUTE);
-    
-                            int bpd = spannedGridRowHeights[y - startRow];
-                            bpd -= gu.getBorders().getBorderBeforeWidth(false) / 2;
-                            bpd -= gu.getBorders().getBorderAfterWidth(false) / 2;
-                            block.setBPD(bpd);
-                            if (log.isTraceEnabled()) {
-                                log.trace("pgu: " + primaryGridUnit + "; gu: " + gu + "; yoffset: "
-                                        + (dy - gu.getBorders().getBorderBeforeWidth(false) / 2)
-                                        + "; bpd: " + bpd);
-                            }
-                            int ipd = gu.getColumn().getColumnWidth().getValue(
-                                    (PercentBaseContext) getParent());
-                            int borderStartWidth = gu.getBorders().getBorderStartWidth(false) / 2;
-                            ipd -= borderStartWidth;
-                            ipd -= gu.getBorders().getBorderEndWidth(false) / 2;
-                            block.setIPD(ipd);
-                            block.setXOffset(dx + borderStartWidth);
-                            block.setYOffset(dy - gu.getBorders().getBorderBeforeWidth(false) / 2);
-                            outer[0] = gu.getFlag(GridUnit.FIRST_IN_TABLE);
-                            outer[1] = gu.getFlag(GridUnit.LAST_IN_TABLE);
-                            outer[2] = gu.getFlag(GridUnit.IN_FIRST_COLUMN);
-                            outer[3] = gu.getFlag(GridUnit.IN_LAST_COLUMN);
-                            TraitSetter.addCollapsingBorders(block, gu.getBorders(), outer, this);
+                        int ipd = getTable().getColumn(primaryGridUnit.getStartCol() + x)
+                                .getColumnWidth().getValue((PercentBaseContext) getParent());
+                        if (blocks[y][x] != null) {
+                            Block block = blocks[y][x];
+                            adjustYOffset(block, dy);
+                            adjustXOffset(block, dx);
+                            adjustIPD(block, ipd);
+                            adjustBPD(block, bpd);
                             parentLM.addChildArea(block);
                         }
-                        dx += gu.getColumn().getColumnWidth().getValue(
-                                (PercentBaseContext) getParent());
+                        dx += ipd;
                     }
-                    dy += spannedGridRowHeights[y - startRow];
+                    dy += bpd;
                 }
             }
         }
-        TraitSetter.addPadding(curBlockArea, primaryGridUnit.getBorders(),
-                false, false, false, false, this);
+
+        CommonBorderPaddingBackground padding = primaryGridUnit.getCell()
+                .getCommonBorderPaddingBackground();
+        TraitSetter.addPadding(curBlockArea,
+                padding,
+                borderBeforeWhich == ConditionalBorder.REST,
+                borderAfterWhich == ConditionalBorder.REST,
+                false, false, this);
+
+        int cellBPD = rowHeight - borderBeforeWidth - borderAfterWidth;
+        cellBPD -= padding.getPaddingBefore(borderBeforeWhich == ConditionalBorder.REST, this);
+        cellBPD -= padding.getPaddingAfter(borderAfterWhich == ConditionalBorder.REST, this);
 
         //Handle display-align
-        int contentBPD = getContentHeight(primaryGridUnit);
-        if (usedBPD < contentBPD) {
+        if (usedBPD < cellBPD) {
             if (getTableCell().getDisplayAlign() == EN_CENTER) {
                 Block space = new Block();
-                space.setBPD((contentBPD - usedBPD) / 2);
+                space.setBPD((cellBPD - usedBPD) / 2);
                 curBlockArea.addBlock(space);
             } else if (getTableCell().getDisplayAlign() == EN_AFTER) {
                 Block space = new Block();
-                space.setBPD((contentBPD - usedBPD));
+                space.setBPD(cellBPD - usedBPD);
                 curBlockArea.addBlock(space);
             }
         }
 
         AreaAdditionUtil.addAreas(this, parentIter, layoutContext);
-
-        curBlockArea.setBPD(contentBPD);
+        // Re-adjust the cell's bpd as it may have been modified by the previous call
+        // for some reason (?)
+        curBlockArea.setBPD(cellBPD);
 
         // Add background after we know the BPD
         if (isSeparateBorderModel()) {
@@ -448,6 +472,34 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager
         curBlockArea = null;
     }
 
+    private void addBorder(Block[][] blocks, int i, int j, Integer side, BorderInfo border,
+            boolean outer) {
+        if (blocks[i][j] == null) {
+            blocks[i][j] = new Block();
+            blocks[i][j].addTrait(Trait.IS_REFERENCE_AREA, Boolean.TRUE);
+            blocks[i][j].setPositioning(Block.ABSOLUTE);
+        }
+        blocks[i][j].addTrait(side, new BorderProps(border.getStyle(),
+                border.getRetainedWidth(), border.getColor(),
+                outer ? BorderProps.COLLAPSE_OUTER : BorderProps.COLLAPSE_INNER));
+    }
+
+    private static void adjustXOffset(Block block, int amount) {
+        block.setXOffset(block.getXOffset() + amount);
+    }
+
+    private static void adjustYOffset(Block block, int amount) {
+        block.setYOffset(block.getYOffset() + amount);
+    }
+
+    private static void adjustIPD(Block block, int amount) {
+        block.setIPD(block.getIPD() + amount);
+    }
+
+    private static void adjustBPD(Block block, int amount) {
+        block.setBPD(block.getBPD() + amount);
+    }
+
     /**
      * Return an Area which can contain the passed childArea. The childArea
      * may not yet have any content, but it has essential traits set.
@@ -467,25 +519,10 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager
             curBlockArea.addTrait(Trait.IS_REFERENCE_AREA, Boolean.TRUE);
             TraitSetter.setProducerID(curBlockArea, getTableCell().getId());
             curBlockArea.setPositioning(Block.ABSOLUTE);
-            // set position
-            int borderAdjust = 0;
-            if (!isSeparateBorderModel()) {
-                if (primaryGridUnit.hasSpanning()) {
-                    borderAdjust -= primaryGridUnit.getHalfMaxBeforeBorderWidth();
-                } else {
-                    borderAdjust += primaryGridUnit.getHalfMaxBeforeBorderWidth();
-                }
-            } else {
-                //borderAdjust += primaryGridUnit.getBorders().getBorderBeforeWidth(false);
-            }
-            TableLayoutManager tableLM = (TableLayoutManager)getParent();
-            curBlockArea.setXOffset(xoffset + inRowIPDOffset + startIndent);
-            curBlockArea.setYOffset(yoffset - borderAdjust
-                    + tableLM.getHalfBorderSeparationBPD());
+            curBlockArea.setXOffset(xoffset + startIndent);
+            curBlockArea.setYOffset(yoffset);
             curBlockArea.setIPD(cellIPD);
-            //curBlockArea.setHeight();
 
-            // Set up dimensions
             /*Area parentArea =*/ parentLM.getParentArea(curBlockArea);
             // Get reference IPD from parentArea
             setCurrentArea(curBlockArea); // ??? for generic operations
index 57972078eb2b73172ccccbaee4cefc33a2f53ea4..344c90e07446ae7aa8ca909bebe651d7a5024609 100644 (file)
@@ -19,6 +19,7 @@
 
 package org.apache.fop.layoutmgr.table;
 
+import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
@@ -125,7 +126,7 @@ public class TableContentLayoutManager implements PercentBaseContext {
         return this.footerList;
     }
 
-    /** @see org.apache.fop.layoutmgr.LayoutManager#getNextKnuthElements(LayoutContext, int) */
+    /** {@inheritDoc} */
     public LinkedList getNextKnuthElements(LayoutContext context, int alignment) {
         if (log.isDebugEnabled()) {
             log.debug("==> Columns: " + getTableLM().getColumns());
@@ -321,9 +322,12 @@ public class TableContentLayoutManager implements PercentBaseContext {
             } else if (pos instanceof TableHFPenaltyPosition) {
                 //ignore for now, see special handling below if break is at a penalty
                 //Only if the last position in this part/page us such a position it will be used 
-            } else {
-                //leave order as is for the rest
+            } else if (pos instanceof TableContentPosition) {
                 positions.add(pos);
+            } else {
+                if (log.isDebugEnabled()) {
+                    log.debug("Ignoring position: " + pos);
+                }
             }
         }
         if (lastPos instanceof TableHFPenaltyPosition) {
@@ -349,17 +353,20 @@ public class TableContentLayoutManager implements PercentBaseContext {
             //header positions for the last part are the second-to-last element and need to
             //be handled first before all other TableContentPositions
             PositionIterator nestedIter = new KnuthPossPosIter(headerElements);
-            iterateAndPaintPositions(nestedIter, painter);
+            iterateAndPaintPositions(nestedIter, painter, false);
         }
         
         //Iterate over all steps
         Iterator posIter = positions.iterator();
-        iterateAndPaintPositions(posIter, painter);
+        painter.startBody();
+        // Here we are sure that posIter iterates only over TableContentPosition instances
+        iterateAndPaintPositions(posIter, painter, footerElements == null);
+        painter.endBody();
 
         if (footerElements != null) {
             //Positions for footers are simply added at the end
             PositionIterator nestedIter = new KnuthPossPosIter(footerElements);
-            iterateAndPaintPositions(nestedIter, painter);
+            iterateAndPaintPositions(nestedIter, painter, true);
         }
         
         this.usedBPD += painter.getAccumulatedBPD();
@@ -377,9 +384,12 @@ public class TableContentLayoutManager implements PercentBaseContext {
      * @param iterator iterator over Position elements. Those positions correspond to the
      * elements of the table present on the current page
      * @param painter
+     * @param lastOnPage true if the corresponding part will be the last on the page
+     * (either body or footer, obviously)
      */
-    private void iterateAndPaintPositions(Iterator iterator, RowPainter painter) {
-        List lst = new java.util.ArrayList();
+    private void iterateAndPaintPositions(Iterator iterator, RowPainter painter,
+            boolean lastOnPage) {
+        List lst = new ArrayList();
         boolean firstPos = false;
         TableBody body = null;
         while (iterator.hasNext()) {
@@ -405,10 +415,6 @@ public class TableContentLayoutManager implements PercentBaseContext {
                     body = null;
                     lst.clear();
                 }
-            } else {
-                if (log.isDebugEnabled()) {
-                    log.debug("Ignoring position: " + pos);
-                }
             }
         }
         if (body != null) {
@@ -417,7 +423,7 @@ public class TableContentLayoutManager implements PercentBaseContext {
             // lastPos is necessarily false
             handleMarkersAndPositions(lst, body, firstPos, false, painter);
         }
-        painter.addAreasAndFlushRow(true);
+        painter.addAreasAndFlushRow(true, lastOnPage);
     }
 
     private void handleMarkersAndPositions(List positions, TableBody body, boolean firstPos,
index 35bf4c8441bfbacba6ac958ebcd4c0c04e5397fd..1d9f95ca1e2ae37b921bb1ba3f6531e153877b21 100644 (file)
@@ -133,7 +133,8 @@ public class TableStepper {
         for (int i = 0; i < columnCount; i++) {
             GridUnit gu = getActiveGridUnit(i);
             if (gu != null && !gu.isEmpty() && gu.isPrimary()) {
-                activeCells.add(new ActiveCell((PrimaryGridUnit) gu, row, activeRowIndex, previousRowsLength, getTableLM()));
+                activeCells.add(new ActiveCell((PrimaryGridUnit) gu, row, activeRowIndex,
+                        previousRowsLength, getTableLM()));
             }
         }
     }
@@ -173,17 +174,17 @@ public class TableStepper {
             List cellParts = new java.util.ArrayList(maxColumnCount);
             for (Iterator iter = activeCells.iterator(); iter.hasNext();) {
                 ActiveCell activeCell = (ActiveCell) iter.next();
+                CellPart part = activeCell.createCellPart();
+                cellParts.add(part);
                 if (activeCell.contributesContent()) {
-                    CellPart part = activeCell.createCellPart();
-                    cellParts.add(part);
                     forcedBreak = activeCell.isLastForcedBreak();
                     if (forcedBreak) {
                         breakClass = activeCell.getLastBreakClass();
                     }
-                    if (returnList.size() == 0 && part.isFirstPart()
-                            && part.mustKeepWithPrevious()) {
-                        context.setFlags(LayoutContext.KEEP_WITH_PREVIOUS_PENDING);
-                    }
+                }
+                if (returnList.size() == 0 && part.isFirstPart()
+                        && part.mustKeepWithPrevious()) {
+                    context.setFlags(LayoutContext.KEEP_WITH_PREVIOUS_PENDING);
                 }
             }
             //log.debug(">>> guPARTS: " + cellParts);
@@ -327,6 +328,7 @@ public class TableStepper {
     private void removeCellsEndingOnCurrentRow() {
         for (Iterator iter = activeCells.iterator(); iter.hasNext();) {
             ActiveCell activeCell = (ActiveCell) iter.next();
+            activeCell.endRow(activeRowIndex);
             if (activeCell.endsOnRow(activeRowIndex)) {
                 iter.remove();
             }
index 21c98c9ab55f1bd099f8ddd6e1cb901a73f10d4f..c261f442b26848f0dd7fa8b8a4f36b2ef5d822c2 100644 (file)
 
   <changes>
     <release version="FOP Trunk">
+      <action context="Layout" dev="VH" type="add" importance="high" fixes-bug="43934">
+          Added support for conditional borders in tables, for both the separate and the collapsing
+          border model.
+      </action>
       <action context="Layout" dev="JM" type="fix" fixes-bug="44160">
         Fixed a possible IndexOutOfBoundsException that could happen with certain constellations
         when footnotes are used.
index b3b6972351475d884e2b33836dcbb6993c665096..1bd5d441d692f7acaae7f21c3da07f6d199e5d33 100755 (executable)
@@ -74,7 +74,7 @@ class TableGenerator:
             ]
 
     bordersBefore = None
-    resBefore = None
+    resBefore = {}
     """The comma between each table; nothing before the first one."""
     separator = ''
 
@@ -85,8 +85,8 @@ class TableGenerator:
         Params:
         borderSet: a list of 5 border specifications for resp. table, table-column,
         table-body, table-row and table-cell
-        resolution: the resolved border for the leading and rest cases (for the normal
-        case the resolution is always the same)
+        resolution: the resolved border for the rest case (for the normal and leading
+        cases the resolution is always the same)
         """
         if not self.bordersBefore:
             self.bordersBefore = borderSet
@@ -110,16 +110,14 @@ class TableGenerator:
             sys.stderr.write(self.separator + '{')
             comma = ''
             for beforeAfter in [self.resBefore, resolution]:
-                for leadRest in range(2):
-                    sys.stderr.write(comma + '{border' + beforeAfter[leadRest]['length']
-                            + ', Color.' + beforeAfter[leadRest]['color']
-                            + '}')
-                    comma = ', '
+                sys.stderr.write(comma + '{border' + beforeAfter['length']
+                        + ', Color.' + beforeAfter['color'] + '}')
+                comma = ', '
             sys.stderr.write('}')
             self.separator = ',\n'
             # Reset
             self.bordersBefore = None
-            self.resBefore = None
+            self.resBefore = {}
 
 class TableHFGenerator:
     """Generates on stdout tables with headers and footers, and the border specifications
@@ -254,7 +252,7 @@ def generateTestCases():
         defaultBorders.append({'length': '4pt', 'cond': 'discard', 'color': color})
     defaultBorders[fo_table]['length'] = '8pt'
 
-    resolution = [{'length': '4pt', 'color': 'yellow'}, {'length': '0pt', 'color': 'black'}]
+    resolution = {'length': '0pt', 'color': 'black'}
     tableGenerator.addBorderSet(defaultBorders, resolution)
     for combinations in createAllCombinations()[1:]:
         for combination in combinations:
@@ -266,9 +264,9 @@ def generateTestCases():
                 if index != fo_table:
                     finalBorders[index]['length'] = '6pt'
                 if fo_table in combination:
-                    resolution = [{'length': '8pt', 'color': 'black'}] * 2
+                    resolution = {'length': '8pt', 'color': 'black'}
                 else:
-                    resolution = [{'length': '6pt', 'color': finalBorders[index]['color']}] * 2
+                    resolution = {'length': '6pt', 'color': finalBorders[index]['color']}
                 tableGenerator.addBorderSet(finalBorders, resolution)
     printFOEnd()
 
index 8037df8ad302f3206df4ca7ac74739be5e298e91..e42ee2935ccba219db73fa4751da32a6b80355e0 100644 (file)
@@ -47,46 +47,46 @@ public class CollapsedConditionalBorderTestCase extends AbstractTableTestCase {
      * script.
      */
     private Object[][][] resolvedBorders = {
-{{border4pt, Color.yellow}, {border0pt, Color.black}, {border8pt, Color.black}, {border8pt, Color.black}},
-{{border6pt, Color.red}, {border6pt, Color.red}, {border6pt, Color.magenta}, {border6pt, Color.magenta}},
-{{border6pt, Color.blue}, {border6pt, Color.blue}, {border6pt, Color.yellow}, {border6pt, Color.yellow}},
-{{border8pt, Color.black}, {border8pt, Color.black}, {border8pt, Color.black}, {border8pt, Color.black}},
-{{border8pt, Color.black}, {border8pt, Color.black}, {border8pt, Color.black}, {border8pt, Color.black}},
-{{border6pt, Color.red}, {border6pt, Color.red}, {border6pt, Color.magenta}, {border6pt, Color.magenta}},
-{{border8pt, Color.black}, {border8pt, Color.black}, {border8pt, Color.black}, {border8pt, Color.black}},
-{{border6pt, Color.red}, {border6pt, Color.red}, {border6pt, Color.blue}, {border6pt, Color.blue}},
-{{border6pt, Color.magenta}, {border6pt, Color.magenta}, {border6pt, Color.blue}, {border6pt, Color.blue}},
-{{border8pt, Color.black}, {border8pt, Color.black}, {border8pt, Color.black}, {border8pt, Color.black}},
-{{border6pt, Color.red}, {border6pt, Color.red}, {border6pt, Color.yellow}, {border6pt, Color.yellow}},
-{{border6pt, Color.magenta}, {border6pt, Color.magenta}, {border6pt, Color.yellow}, {border6pt, Color.yellow}},
-{{border6pt, Color.blue}, {border6pt, Color.blue}, {border6pt, Color.yellow}, {border6pt, Color.yellow}},
-{{border8pt, Color.black}, {border8pt, Color.black}, {border8pt, Color.black}, {border8pt, Color.black}},
-{{border8pt, Color.black}, {border8pt, Color.black}, {border8pt, Color.black}, {border8pt, Color.black}},
-{{border8pt, Color.black}, {border8pt, Color.black}, {border8pt, Color.black}, {border8pt, Color.black}},
-{{border8pt, Color.black}, {border8pt, Color.black}, {border8pt, Color.black}, {border8pt, Color.black}},
-{{border8pt, Color.black}, {border8pt, Color.black}, {border6pt, Color.red}, {border6pt, Color.red}},
-{{border6pt, Color.magenta}, {border6pt, Color.magenta}, {border6pt, Color.blue}, {border6pt, Color.blue}},
-{{border8pt, Color.black}, {border8pt, Color.black}, {border8pt, Color.black}, {border8pt, Color.black}},
-{{border8pt, Color.black}, {border8pt, Color.black}, {border8pt, Color.black}, {border8pt, Color.black}},
-{{border8pt, Color.black}, {border8pt, Color.black}, {border8pt, Color.black}, {border8pt, Color.black}},
-{{border6pt, Color.red}, {border6pt, Color.red}, {border6pt, Color.magenta}, {border6pt, Color.magenta}},
-{{border6pt, Color.yellow}, {border6pt, Color.yellow}, {border8pt, Color.black}, {border8pt, Color.black}},
-{{border8pt, Color.black}, {border8pt, Color.black}, {border8pt, Color.black}, {border8pt, Color.black}},
-{{border6pt, Color.red}, {border6pt, Color.red}, {border6pt, Color.blue}, {border6pt, Color.blue}},
-{{border6pt, Color.yellow}, {border6pt, Color.yellow}, {border6pt, Color.magenta}, {border6pt, Color.magenta}},
-{{border6pt, Color.blue}, {border6pt, Color.blue}, {border6pt, Color.yellow}, {border6pt, Color.yellow}},
-{{border8pt, Color.black}, {border8pt, Color.black}, {border8pt, Color.black}, {border8pt, Color.black}},
-{{border8pt, Color.black}, {border8pt, Color.black}, {border8pt, Color.black}, {border8pt, Color.black}},
-{{border8pt, Color.black}, {border8pt, Color.black}, {border8pt, Color.black}, {border8pt, Color.black}},
-{{border8pt, Color.black}, {border8pt, Color.black}, {border8pt, Color.black}, {border8pt, Color.black}},
-{{border8pt, Color.black}, {border8pt, Color.black}, {border8pt, Color.black}, {border8pt, Color.black}},
-{{border8pt, Color.black}, {border8pt, Color.black}, {border8pt, Color.black}, {border8pt, Color.black}},
-{{border8pt, Color.black}, {border8pt, Color.black}, {border8pt, Color.black}, {border8pt, Color.black}},
-{{border8pt, Color.black}, {border8pt, Color.black}, {border8pt, Color.black}, {border8pt, Color.black}},
-{{border6pt, Color.red}, {border6pt, Color.red}, {border6pt, Color.magenta}, {border6pt, Color.magenta}},
-{{border6pt, Color.blue}, {border6pt, Color.blue}, {border6pt, Color.yellow}, {border6pt, Color.yellow}},
-{{border8pt, Color.black}, {border8pt, Color.black}, {border8pt, Color.black}, {border8pt, Color.black}},
-{{border8pt, Color.black}, {border8pt, Color.black}, {border8pt, Color.black}, {border8pt, Color.black}}
+            {{border0pt, Color.black}, {border8pt, Color.black}},
+            {{border6pt, Color.red}, {border6pt, Color.magenta}},
+            {{border6pt, Color.blue}, {border6pt, Color.yellow}},
+            {{border8pt, Color.black}, {border8pt, Color.black}},
+            {{border8pt, Color.black}, {border8pt, Color.black}},
+            {{border6pt, Color.red}, {border6pt, Color.magenta}},
+            {{border8pt, Color.black}, {border8pt, Color.black}},
+            {{border6pt, Color.red}, {border6pt, Color.blue}},
+            {{border6pt, Color.magenta}, {border6pt, Color.blue}},
+            {{border8pt, Color.black}, {border8pt, Color.black}},
+            {{border6pt, Color.red}, {border6pt, Color.yellow}},
+            {{border6pt, Color.magenta}, {border6pt, Color.yellow}},
+            {{border6pt, Color.blue}, {border6pt, Color.yellow}},
+            {{border8pt, Color.black}, {border8pt, Color.black}},
+            {{border8pt, Color.black}, {border8pt, Color.black}},
+            {{border8pt, Color.black}, {border8pt, Color.black}},
+            {{border8pt, Color.black}, {border8pt, Color.black}},
+            {{border8pt, Color.black}, {border6pt, Color.red}},
+            {{border6pt, Color.magenta}, {border6pt, Color.blue}},
+            {{border8pt, Color.black}, {border8pt, Color.black}},
+            {{border8pt, Color.black}, {border8pt, Color.black}},
+            {{border8pt, Color.black}, {border8pt, Color.black}},
+            {{border6pt, Color.red}, {border6pt, Color.magenta}},
+            {{border6pt, Color.yellow}, {border8pt, Color.black}},
+            {{border8pt, Color.black}, {border8pt, Color.black}},
+            {{border6pt, Color.red}, {border6pt, Color.blue}},
+            {{border6pt, Color.yellow}, {border6pt, Color.magenta}},
+            {{border6pt, Color.blue}, {border6pt, Color.yellow}},
+            {{border8pt, Color.black}, {border8pt, Color.black}},
+            {{border8pt, Color.black}, {border8pt, Color.black}},
+            {{border8pt, Color.black}, {border8pt, Color.black}},
+            {{border8pt, Color.black}, {border8pt, Color.black}},
+            {{border8pt, Color.black}, {border8pt, Color.black}},
+            {{border8pt, Color.black}, {border8pt, Color.black}},
+            {{border8pt, Color.black}, {border8pt, Color.black}},
+            {{border8pt, Color.black}, {border8pt, Color.black}},
+            {{border6pt, Color.red}, {border6pt, Color.magenta}},
+            {{border6pt, Color.blue}, {border6pt, Color.yellow}},
+            {{border8pt, Color.black}, {border8pt, Color.black}},
+            {{border8pt, Color.black}, {border8pt, Color.black}}
     };
 
     /**
@@ -142,13 +142,13 @@ public class CollapsedConditionalBorderTestCase extends AbstractTableTestCase {
 
             String errorMsge = baseErrorMsge + "border-before";
             checkBorder(errorMsge, gu.borderBefore.nonLeadingTrailing, 8000, Color.black);
-            checkBorder(errorMsge, gu.borderBefore.leadingTrailing, resolvedBorders[tableNum][0]);
-            checkBorder(errorMsge, gu.borderBefore.rest, resolvedBorders[tableNum][1]);
+            checkBorder(errorMsge, gu.borderBefore.leadingTrailing, 8000, Color.black);
+            checkBorder(errorMsge, gu.borderBefore.rest, resolvedBorders[tableNum][0]);
 
             errorMsge = baseErrorMsge + "border-after";
             checkBorder(errorMsge, gu.borderAfter.nonLeadingTrailing, 8000, Color.black);
-            checkBorder(errorMsge, gu.borderAfter.leadingTrailing, resolvedBorders[tableNum][2]);
-            checkBorder(errorMsge, gu.borderAfter.rest, resolvedBorders[tableNum][3]);
+            checkBorder(errorMsge, gu.borderAfter.leadingTrailing, 8000, Color.black);
+            checkBorder(errorMsge, gu.borderAfter.rest, resolvedBorders[tableNum][1]);
 
             tableNum++;
         } while (tableIterator.hasNext());
index 5e492ec75731daec77431bc43c4a04693bda1572..04752064f8bc85f206117568009fa681b1a59616 100644 (file)
@@ -36,6 +36,7 @@ import org.apache.commons.io.filefilter.PrefixFileFilter;
 import org.apache.commons.io.filefilter.SuffixFileFilter;
 import org.apache.commons.io.filefilter.TrueFileFilter;
 import org.apache.fop.DebugHelper;
+import org.apache.fop.fo.flow.table.CollapsedConditionalBorderTestCase;
 import org.apache.fop.fo.flow.table.IllegalRowSpanTestCase;
 import org.apache.fop.fo.flow.table.RowGroupBuilderTestCase;
 import org.apache.fop.fo.flow.table.TableColumnColumnNumberTestCase;
@@ -115,6 +116,7 @@ public final class FOTreeTestSuite {
         suite.addTestSuite(IllegalRowSpanTestCase.class);
         suite.addTestSuite(RowGroupBuilderTestCase.class);
         suite.addTestSuite(TableColumnColumnNumberTestCase.class);
+        suite.addTestSuite(CollapsedConditionalBorderTestCase.class);
     }
 
     private static class FOTreeTestCase extends TestCase {
index 14c5f3b8934e89afeed4d427e071bffd55ec0059..8b595ce3c10185f281d80a39ae1d5a7ced0c60b4 100644 (file)
     <eval expected="3" xpath="count(//pageViewport[@nr=1]//flow/block[1]/block[1]/block)"/>
     <eval expected="67000" xpath="//pageViewport[@nr=1]//flow/block[1]/block[1]/@ipd"/>
     <eval expected="75000" xpath="//pageViewport[@nr=1]//flow/block[1]/block[1]/@ipda"/>
-    <eval expected="71200" xpath="//pageViewport[@nr=1]//flow/block[1]/block[1]/@bpd"/>
-    <eval expected="79200" xpath="//pageViewport[@nr=1]//flow/block[1]/block[1]/@bpda"/>
+    <eval expected="69200" xpath="//pageViewport[@nr=1]//flow/block[1]/block[1]/@bpd"/>
+    <eval expected="73200" xpath="//pageViewport[@nr=1]//flow/block[1]/block[1]/@bpda"/>
     <!-- 2 blocks in the second cell -->
     <eval expected="2" xpath="count(//pageViewport[@nr=1]//flow/block[1]/block[2]/block)"/>
     <eval expected="63000" xpath="//pageViewport[@nr=1]//flow/block[1]/block[2]/@ipd"/>
     <eval expected="75000" xpath="//pageViewport[@nr=1]//flow/block[1]/block[2]/@ipda"/>
     <eval expected="67200" xpath="//pageViewport[@nr=1]//flow/block[1]/block[2]/@bpd"/>
-    <eval expected="79200" xpath="//pageViewport[@nr=1]//flow/block[1]/block[2]/@bpda"/>
+    <eval expected="73200" xpath="//pageViewport[@nr=1]//flow/block[1]/block[2]/@bpda"/>
     <!-- 3 lines in the second block of the second cell -->
     <eval expected="3" xpath="count(//pageViewport[@nr=1]//flow/block[1]/block[2]/block[2]//lineArea)"/>
 
@@ -82,8 +82,8 @@
     <eval expected="0" xpath="count(//pageViewport[@nr=2]//flow/block[1]/block[1]/block)"/>
     <eval expected="67000" xpath="//pageViewport[@nr=2]//flow/block[1]/block[1]/@ipd"/>
     <eval expected="75000" xpath="//pageViewport[@nr=2]//flow/block[1]/block[1]/@ipda"/>
-    <eval expected="20800" xpath="//pageViewport[@nr=2]//flow/block[1]/block[1]/@bpd"/>
-    <eval expected="28800" xpath="//pageViewport[@nr=2]//flow/block[1]/block[1]/@bpda"/>
+    <eval expected="18800" xpath="//pageViewport[@nr=2]//flow/block[1]/block[1]/@bpd"/>
+    <eval expected="22800" xpath="//pageViewport[@nr=2]//flow/block[1]/block[1]/@bpda"/>
     <!-- One block expected in the second cell -->
     <eval expected="1" xpath="count(//pageViewport[@nr=2]//flow/block[1]/block[2]/block)"/>
     <!-- One line in the block -->
@@ -91,6 +91,6 @@
     <eval expected="63000" xpath="//pageViewport[@nr=2]//flow/block[1]/block[2]/@ipd"/>
     <eval expected="75000" xpath="//pageViewport[@nr=2]//flow/block[1]/block[2]/@ipda"/>
     <eval expected="16800" xpath="//pageViewport[@nr=2]//flow/block[1]/block[2]/@bpd"/>
-    <eval expected="28800" xpath="//pageViewport[@nr=2]//flow/block[1]/block[2]/@bpda"/>
+    <eval expected="22800" xpath="//pageViewport[@nr=2]//flow/block[1]/block[2]/@bpda"/>
   </checks>
 </testcase>
index fc2357e9f9d0a9e50fc753735f2e568024574dcf..22ccc303d62ee3d0f7ee9e01267e78ac3a48b0fc 100644 (file)
@@ -53,6 +53,9 @@
                 <fo:table-cell id="cell4" number-columns-spanned="2" number-rows-spanned="2" border="solid 0.5pt"  background-color="lightgray">
                   <fo:block>cell4</fo:block>
                 </fo:table-cell>
+                <fo:table-cell>
+                  <fo:block> </fo:block>
+                </fo:table-cell>
               </fo:table-row>
               <fo:table-row>
                 <fo:table-cell id="cell5" border="solid 0.5pt">
@@ -78,7 +81,7 @@
     <eval expected="1" xpath="count(//block[@prod-id = 'cell4'])"/>
     <eval expected="1" xpath="count(//block[@prod-id = 'cell5'])"/>
     <eval expected="1" xpath="count(//block[@prod-id = 'cell6'])"/>
-    <eval expected="45200" xpath="//block[@prod-id = 'cell2']/@bpd"/>
-    <eval expected="29800" xpath="//block[@prod-id = 'cell4']/@bpd"/>
+    <eval expected="44200" xpath="//block[@prod-id = 'cell2']/@bpd"/>
+    <eval expected="28800" xpath="//block[@prod-id = 'cell4']/@bpd"/>
   </checks>
 </testcase>
index 93b495d56a5f48be19dc2ba038d797cb397673c4..b7f2b7c6fd98503a2951dfedd27f753accb6c6d5 100644 (file)
       <fo:page-sequence master-reference="normal" white-space-collapse="true">
         <fo:flow flow-name="xsl-region-body">
           <fo:block>before the table</fo:block>
-          <fo:table table-layout="fixed" width="100%">
-            <fo:table-column/>
-            <fo:table-column/>
+          <fo:table table-layout="fixed" width="100%" border-collapse="separate" border="4pt solid black">
+            <fo:table-column number-columns-repeated="2" column-width="proportional-column-width(1)"/>
             <fo:table-body>
               <fo:table-row break-before="odd-page" break-after="odd-page">
-                <fo:table-cell background-color="orange">
-                  <fo:block>cell3</fo:block>
+                <fo:table-cell border="2pt solid blue" background-color="orange">
+                  <fo:block>cell1</fo:block>
                 </fo:table-cell>
-                <fo:table-cell>
-                  <fo:block>cell4</fo:block>
+                <fo:table-cell border="2pt solid red">
+                  <fo:block>cell2</fo:block>
                 </fo:table-cell>
               </fo:table-row>
             </fo:table-body>
   </fo>
   <checks>
     <eval expected="5" xpath="count(//pageViewport)"/>
+    <!-- table -->
+    <eval expected="18400" xpath="//pageViewport[@nr=3]//flow/block[1]/@bpd"/>
+    <!--
+    <eval expected="26400" xpath="//pageViewport[@nr=3]//flow/block[1]/@bpda"/>
+    <eval expected="(solid,#000000,4000)" xpath="//pageViewport[@nr=3]//flow/block[1]/@border-before"/>
+    <eval expected="(solid,#000000,4000)" xpath="//pageViewport[@nr=3]//flow/block[1]/@border-after"/>
+    -->
+    <!-- cell 1 -->
+    <eval expected="14400" xpath="//pageViewport[@nr=3]//flow/block[1]/block[1]/@bpd"/>
+    <eval expected="18400" xpath="//pageViewport[@nr=3]//flow/block[1]/block[1]/@bpda"/>
+    <eval expected="(solid,#0000ff,2000)" xpath="//pageViewport[@nr=3]//flow/block[1]/block[1]/@border-before"/>
+    <eval expected="(solid,#0000ff,2000)" xpath="//pageViewport[@nr=3]//flow/block[1]/block[1]/@border-after"/>
+    <!-- cell 2 -->
+    <eval expected="14400" xpath="//pageViewport[@nr=3]//flow/block[1]/block[2]/@bpd"/>
+    <eval expected="18400" xpath="//pageViewport[@nr=3]//flow/block[1]/block[2]/@bpda"/>
+    <eval expected="(solid,#ff0000,2000)" xpath="//pageViewport[@nr=3]//flow/block[1]/block[2]/@border-before"/>
+    <eval expected="(solid,#ff0000,2000)" xpath="//pageViewport[@nr=3]//flow/block[1]/block[2]/@border-after"/>
   </checks>
 </testcase>
diff --git a/test/layoutengine/standard-testcases/table_border-collapse_collapse_conditionals.xml b/test/layoutengine/standard-testcases/table_border-collapse_collapse_conditionals.xml
new file mode 100644 (file)
index 0000000..a653be4
--- /dev/null
@@ -0,0 +1,177 @@
+<?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 that conditional paddings and borders on table-cells are handled correctly.
+    </p>
+  </info>
+  <fo>
+    <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
+      <fo:layout-master-set>
+        <fo:simple-page-master master-name="page" page-height="5cm" page-width="15cm" margin="1cm">
+          <fo:region-body background-color="#F0F0F0"/>
+        </fo:simple-page-master>
+      </fo:layout-master-set>
+      <fo:page-sequence master-reference="page" font-family="serif" font-size="8pt" line-height="10pt">
+        <fo:flow flow-name="xsl-region-body">
+
+          <!-- table 1 -->
+          <fo:block
+            space-after.minimum="30pt"
+            space-after.optimum="40pt"
+            space-after.maximum="50pt"
+            >Before the table</fo:block>
+          <fo:table width="100%" table-layout="fixed" border="6pt solid black">
+            <fo:table-column column-width="proportional-column-width(1)" number-columns-repeated="2"/>
+            <fo:table-body>
+              <fo:table-row border="5pt solid red">
+                <fo:table-cell border="7pt solid blue" padding="2pt">
+                  <fo:block background-color="yellow">
+                    <fo:block>Cell 1.1</fo:block>
+                    <fo:block>Cell 1.1</fo:block>
+                  </fo:block>
+                </fo:table-cell>
+                <fo:table-cell number-rows-spanned="2"
+                  border="4pt solid blue" padding="2pt"
+                  border-before-width.length="4pt"
+                  border-before-width.conditionality="retain"
+                  padding-after.length="7pt"
+                  padding-after.conditionality="retain">
+                  <fo:block background-color="yellow">
+                    <fo:block>Cell 1.2</fo:block>
+                    <fo:block>Cell 1.2</fo:block>
+                    <fo:block>Cell 1.2</fo:block>
+                    <fo:block>Cell 1.2</fo:block>
+                  </fo:block>
+                </fo:table-cell>
+              </fo:table-row>
+              <fo:table-row border="5pt solid purple"
+                border-before-width.length="5pt"
+                border-before-width.conditionality="retain">
+                <fo:table-cell border="4pt solid green" padding="2pt">
+                  <fo:block background-color="yellow">
+                    <fo:block>Cell 2.1</fo:block>
+                    <fo:block>Cell 2.1</fo:block>
+                  </fo:block>
+                </fo:table-cell>
+              </fo:table-row>
+            </fo:table-body>
+          </fo:table>
+
+          <!-- table 2 -->
+          <fo:block break-before="page"
+            space-after.minimum="30pt"
+            space-after.optimum="40pt"
+            space-after.maximum="50pt"
+            >Before the table</fo:block>
+          <fo:table width="100%" table-layout="fixed" border="6pt solid black">
+            <fo:table-column column-width="proportional-column-width(1)" number-columns-repeated="2"/>
+            <fo:table-body>
+              <fo:table-row border="5pt solid red">
+                <fo:table-cell border="7pt solid blue" padding="2pt">
+                  <fo:block background-color="yellow">
+                    <fo:block>Cell 1.1</fo:block>
+                  </fo:block>
+                </fo:table-cell>
+                <fo:table-cell number-rows-spanned="3"
+                  border="4pt solid blue" padding="2pt"
+                  border-before-width.length="4pt"
+                  border-before-width.conditionality="retain"
+                  padding-after.length="7pt"
+                  padding-after.conditionality="retain">
+                  <fo:block background-color="yellow">
+                    <fo:block>Cell 1.2</fo:block>
+                  </fo:block>
+                </fo:table-cell>
+              </fo:table-row>
+              <fo:table-row border="5pt solid purple"
+                border-before-width.length="5pt"
+                border-before-width.conditionality="retain">
+                <fo:table-cell border="4pt solid green" padding="2pt">
+                  <fo:block background-color="yellow">
+                    <fo:block>Cell 2.1</fo:block>
+                    <fo:block>Cell 2.1</fo:block>
+                  </fo:block>
+                </fo:table-cell>
+              </fo:table-row>
+              <fo:table-row border="5pt solid purple"
+                border-before-width.length="5pt"
+                border-before-width.conditionality="retain">
+                <fo:table-cell border="4pt solid green" padding="2pt">
+                  <fo:block background-color="yellow">
+                    <fo:block>Cell 3.1</fo:block>
+                    <fo:block>Cell 3.1</fo:block>
+                  </fo:block>
+                </fo:table-cell>
+              </fo:table-row>
+            </fo:table-body>
+          </fo:table>
+
+        </fo:flow>
+      </fo:page-sequence>
+    </fo:root>
+  </fo>
+  <checks>
+
+    <!-- before break -->
+    <eval expected="31000"                               xpath="//pageViewport[@nr='1']//flow/block[2]/@bpd"/>
+    <!-- cell 1.1 -->
+    <eval expected="20000"                               xpath="//pageViewport[@nr='1']//flow/block[2]/block[1]/@bpd"/>
+    <eval expected="38000"                               xpath="//pageViewport[@nr='1']//flow/block[2]/block[1]/@bpda"/>
+    <eval expected="-3500"                               xpath="//pageViewport[@nr='1']//flow/block[2]/block[1]/@top-offset"/>
+    <eval expected="(solid,#0000ff,7000,collapse-outer)" xpath="//pageViewport[@nr='1']//flow/block[2]/block[1]/@border-before"/>
+    <eval expected="2000"                                xpath="//pageViewport[@nr='1']//flow/block[2]/block[1]/@padding-before"/>
+    <eval expected="2000"                                xpath="//pageViewport[@nr='1']//flow/block[2]/block[1]/@padding-after"/>
+    <eval expected="(solid,#0000ff,7000,collapse-outer)" xpath="//pageViewport[@nr='1']//flow/block[2]/block[1]/@border-after"/>
+    <!-- cell 1.2 -->
+    <eval expected="28000"                               xpath="//pageViewport[@nr='1']//flow/block[2]/block[2]/@bpd"/>
+    <eval expected="34000"                               xpath="//pageViewport[@nr='1']//flow/block[2]/block[2]/@bpda"/>
+    <eval expected="-3000"                               xpath="//pageViewport[@nr='1']//flow/block[2]/block[2]/@top-offset"/>
+    <eval expected="(solid,#000000,6000,collapse-outer)" xpath="//pageViewport[@nr='1']//flow/block[2]/block[2]/@border-before"/>
+    <eval expected=""                                    xpath="//pageViewport[@nr='1']//flow/block[2]/block[2]/@border-after"/>
+    <eval expected="19000"                               xpath="//pageViewport[@nr='1']//flow/block[2]/block[3]/@bpd"/>
+    <eval expected="28000"                               xpath="//pageViewport[@nr='1']//flow/block[2]/block[3]/@bpda"/>
+    <eval expected="3000"                                xpath="//pageViewport[@nr='1']//flow/block[2]/block[3]/@top-offset"/>
+    <eval expected="2000"                                xpath="//pageViewport[@nr='1']//flow/block[2]/block[3]/@padding-before"/>
+    <eval expected="7000"                                xpath="//pageViewport[@nr='1']//flow/block[2]/block[3]/@padding-after"/>
+    <!-- after break -->
+    <eval expected="42500"                               xpath="//pageViewport[@nr='2']//flow/block[1]/@bpd"/>
+    <!-- cell 1.1 -->
+    <eval expected="33000"                               xpath="//pageViewport[@nr='2']//flow/block[1]/block[1]/@bpd"/>
+    <eval expected="48000"                               xpath="//pageViewport[@nr='2']//flow/block[1]/block[1]/@bpda"/>
+    <eval expected="-2500"                               xpath="//pageViewport[@nr='2']//flow/block[1]/block[1]/@top-offset"/>
+    <eval expected="(solid,#800080,5000,collapse-outer)" xpath="//pageViewport[@nr='2']//flow/block[1]/block[1]/@border-before"/>
+    <eval expected="2000"                                xpath="//pageViewport[@nr='2']//flow/block[1]/block[1]/@padding-before"/>
+    <eval expected="2000"                                xpath="//pageViewport[@nr='2']//flow/block[1]/block[1]/@padding-after"/>
+    <eval expected="(solid,#000000,6000,collapse-outer)" xpath="//pageViewport[@nr='2']//flow/block[1]/block[1]/@border-after"/>
+    <!-- cell 1.2 -->
+    <eval expected="37000"                               xpath="//pageViewport[@nr='2']//flow/block[1]/block[2]/@bpd"/>
+    <eval expected="48000"                               xpath="//pageViewport[@nr='2']//flow/block[1]/block[2]/@bpda"/>
+    <eval expected="-2500"                               xpath="//pageViewport[@nr='2']//flow/block[1]/block[2]/@top-offset"/>
+    <eval expected="(solid,#800080,5000,collapse-outer)" xpath="//pageViewport[@nr='2']//flow/block[1]/block[2]/@border-before"/>
+    <eval expected="(solid,#000000,6000,collapse-outer)" xpath="//pageViewport[@nr='2']//flow/block[1]/block[2]/@border-after"/>
+    <eval expected="30000"                               xpath="//pageViewport[@nr='2']//flow/block[1]/block[3]/@bpd"/>
+    <eval expected="37000"                               xpath="//pageViewport[@nr='2']//flow/block[1]/block[3]/@bpda"/>
+    <eval expected="2500"                                xpath="//pageViewport[@nr='2']//flow/block[1]/block[3]/@top-offset"/>
+    <eval expected=""                                    xpath="//pageViewport[@nr='2']//flow/block[1]/block[3]/@padding-before"/>
+    <eval expected="7000"                                xpath="//pageViewport[@nr='2']//flow/block[1]/block[3]/@padding-after"/>
+
+  </checks>
+</testcase>
index 5bc7aed33f159d14e6a6ce771cbedb634dd5fec4..4a9464bf1cc9cbe280bcaeec47e974f96c964a60 100644 (file)
     <eval expected="6000" xpath="//flow/block[2]/block[2]/@left-offset"/>
     <eval expected="-8000" xpath="//flow/block[2]/block[2]/@top-offset"/>
     <eval expected="(solid,#000000,16000,collapse-outer)" xpath="//flow/block[2]/block[2]/@border-before"/>
+    <eval expected=""                                     xpath="//flow/block[2]/block[2]/@border-after"/>
     <eval expected="(solid,#ff0000,12000,collapse-outer)" xpath="//flow/block[2]/block[2]/@border-start"/>
     <eval expected="(solid,#800080,10000,collapse-inner)" xpath="//flow/block[2]/block[2]/@border-end"/>
     <eval expected="92000" xpath="//flow/block[2]/block[3]/@ipd"/>
     <eval expected="41800" xpath="//flow/block[2]/block[3]/@bpda"/>
     <eval expected="6000" xpath="//flow/block[2]/block[3]/@left-offset"/>
     <eval expected="21400" xpath="//flow/block[2]/block[3]/@top-offset"/>
+    <eval expected=""                                     xpath="//flow/block[2]/block[3]/@border-before"/>
     <eval expected="(solid,#0000ff,10000,collapse-outer)" xpath="//flow/block[2]/block[3]/@border-after"/>
     <eval expected="(solid,#ff0000,12000,collapse-outer)" xpath="//flow/block[2]/block[3]/@border-start"/>
     <eval expected="(solid,#008080,4000,collapse-inner)" xpath="//flow/block[2]/block[3]/@border-end"/>
     <eval expected="102000" xpath="//flow/block[4]/block[3]/@left-offset"/>
     <eval expected="-2000" xpath="//flow/block[4]/block[3]/@top-offset"/>
     <eval expected="(solid,#c0c0c0,4000,collapse-outer)" xpath="//flow/block[4]/block[3]/@border-before"/>
+    <eval expected=""                                    xpath="//flow/block[4]/block[3]/@border-after"/>
     <eval expected="(solid,#800080,4000,collapse-inner)" xpath="//flow/block[4]/block[3]/@border-start"/>
     <eval expected="(solid,#808000,10000,collapse-outer)" xpath="//flow/block[4]/block[3]/@border-end"/>
     <eval expected="87000" xpath="//flow/block[4]/block[4]/@ipd"/>
     <eval expected="71600" xpath="//flow/block[4]/block[4]/@bpda"/>
     <eval expected="108000" xpath="//flow/block[4]/block[4]/@left-offset"/>
     <eval expected="26400" xpath="//flow/block[4]/block[4]/@top-offset"/>
+    <eval expected=""                                    xpath="//flow/block[4]/block[4]/@border-before"/>
     <eval expected="(solid,#800080,4000,collapse-outer)" xpath="//flow/block[4]/block[4]/@border-after"/>
     <eval expected="(solid,#808000,16000,collapse-inner)" xpath="//flow/block[4]/block[4]/@border-start"/>
     <eval expected="(solid,#808000,10000,collapse-outer)" xpath="//flow/block[4]/block[4]/@border-end"/>
     <eval expected="(solid,#000000,2000,collapse-outer)" xpath="//flow/block[6]/block[1]/@border-before"/>
     <eval expected="(solid,#0000ff,4000,collapse-inner)" xpath="//flow/block[6]/block[1]/@border-after"/>
     <eval expected="(solid,#ff0000,2000,collapse-outer)" xpath="//flow/block[6]/block[1]/@border-start"/>
+    <eval expected=""                                    xpath="//flow/block[6]/block[6]/@border-end"/>
     <eval expected="99000" xpath="//flow/block[6]/block[2]/@ipd"/>
     <eval expected="101000" xpath="//flow/block[6]/block[2]/@ipda"/>
     <eval expected="23400" xpath="//flow/block[6]/block[2]/@bpd"/>
     <eval expected="-1000" xpath="//flow/block[6]/block[2]/@top-offset"/>
     <eval expected="(solid,#000000,2000,collapse-outer)" xpath="//flow/block[6]/block[2]/@border-before"/>
     <eval expected="(solid,#000000,10000,collapse-inner)" xpath="//flow/block[6]/block[2]/@border-after"/>
+    <eval expected=""                                    xpath="//flow/block[6]/block[2]/@border-start"/>
     <eval expected="(solid,#008080,2000,collapse-outer)" xpath="//flow/block[6]/block[2]/@border-end"/>
     <eval expected="185000" xpath="//flow/block[6]/block[3]/@ipd"/>
     <eval expected="198000" xpath="//flow/block[6]/block[3]/@ipda"/>
     <eval expected="(solid,#c0c0c0,15000,collapse-inner)" xpath="//flow/block[8]/block[3]/@border-before"/>
     <eval expected="(solid,#000080,6000,collapse-outer)" xpath="//flow/block[8]/block[3]/@border-after"/>
     <eval expected="(solid,#800080,6000,collapse-outer)" xpath="//flow/block[8]/block[3]/@border-start"/>
+    <eval expected=""                                     xpath="//flow/block[8]/block[3]/@border-end"/>
     <eval expected="97000" xpath="//flow/block[8]/block[4]/@ipd"/>
     <eval expected="103000" xpath="//flow/block[8]/block[4]/@ipda"/>
     <eval expected="39400" xpath="//flow/block[8]/block[4]/@bpd"/>
     <eval expected="34800" xpath="//flow/block[8]/block[4]/@top-offset"/>
     <eval expected="(solid,#c0c0c0,15000,collapse-inner)" xpath="//flow/block[8]/block[4]/@border-before"/>
     <eval expected="(solid,#000080,6000,collapse-outer)" xpath="//flow/block[8]/block[4]/@border-after"/>
+    <eval expected=""                                     xpath="//flow/block[8]/block[4]/@border-start"/>
     <eval expected="(solid,#808000,6000,collapse-outer)" xpath="//flow/block[8]/block[4]/@border-end"/>
     <eval expected="144000" xpath="//flow/block[8]/block[5]/@ipd"/>
     <eval expected="194000" xpath="//flow/block[8]/block[5]/@ipda"/>
index bb4746cdd95b5f4fdcce988458b4e4b296ffdfb3..52f0de812ba288d551ba44089866ac1c967f67fd 100644 (file)
       <box w="0"/>
       <penalty w="0" p="INF"/>
       <glue w="7500"/>
-      <box w="15000"/>
-      <penalty w="0"/>
-      <box w="5000"/>
-      <penalty w="5000"/>
-      <box w="0"/>
-      <penalty w="10000"/>
-      <box w="15000"/>
+      <box w="2500"/>
+      <penalty w="10000" p="900"/>
+      <box w="12500"/>
       <penalty w="0"/>
+      <box w="7500"/>
+      <penalty w="0" p="900"/>
       <box w="0"/>
       <penalty w="5000"/>
-      <box w="15000"/>
+      <box w="12500"/>
+      <penalty w="0"/>
+      <box w="2500"/>
+      <penalty w="0" p="900"/>
+      <box w="12500"/>
       <penalty w="0" p="INF"/>
       <glue w="7500"/>
 
       <box w="0"/>
       <penalty w="0" p="INF"/>
       <glue w="7500"/>
-      <box w="15000"/>
-      <penalty w="0"/>
-      <box w="5000"/>
-      <penalty w="5000"/>
-      <box w="0"/>
-      <penalty w="10000"/>
-      <box w="15000"/>
+      <box w="2500"/>
+      <penalty w="10000" p="900"/>
+      <box w="12500"/>
       <penalty w="0"/>
+      <box w="7500"/>
+      <penalty w="0" p="900"/>
       <box w="0"/>
       <penalty w="5000"/>
-      <box w="15000"/>
+      <box w="12500"/>
+      <penalty w="0"/>
+      <box w="2500"/>
+      <penalty w="0" p="900"/>
+      <box w="12500"/>
       <box w="0"/> <!-- with SpaceHandlingPosition -->
       <penalty w="0" p="INF"/>
       <glue w="7500"/>
diff --git a/test/layoutengine/standard-testcases/table_border-collapse_separate_conditionals.xml b/test/layoutengine/standard-testcases/table_border-collapse_separate_conditionals.xml
new file mode 100644 (file)
index 0000000..227d556
--- /dev/null
@@ -0,0 +1,386 @@
+<?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 that conditional paddings and borders on table-cells are handled correctly.
+    </p>
+  </info>
+  <fo>
+    <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
+      <fo:layout-master-set>
+        <fo:simple-page-master master-name="page" page-height="5cm" page-width="15cm" margin="1cm">
+          <fo:region-body background-color="#F0F0F0"/>
+        </fo:simple-page-master>
+      </fo:layout-master-set>
+      <fo:page-sequence master-reference="page" font-family="serif" font-size="8pt" line-height="10pt">
+        <fo:flow flow-name="xsl-region-body">
+
+          <!-- Table 1 -->
+          <fo:block
+            space-after.minimum="30pt"
+            space-after.optimum="40pt"
+            space-after.maximum="50pt"
+            >Before the table</fo:block>
+          <fo:table width="100%" table-layout="fixed"
+            border-collapse="separate" border="4pt solid black">
+            <fo:table-column column-width="proportional-column-width(1)" number-columns-repeated="2"/>
+            <fo:table-body>
+              <fo:table-row>
+                <fo:table-cell border="4pt solid blue" padding="2pt"
+                  padding-after.length="3pt"
+                  padding-after.conditionality="retain"
+                  padding-before.length="2pt"
+                  padding-before.conditionality="retain">
+                  <fo:block background-color="yellow">
+                    <fo:block>Cell 1.1</fo:block>
+                    <fo:block>Cell 1.1</fo:block>
+                    <fo:block>Cell 1.1</fo:block>
+                    <fo:block>Cell 1.1</fo:block>
+                  </fo:block>
+                </fo:table-cell>
+                <fo:table-cell border="4pt solid blue" padding="2pt"
+                  border-before-width.length="6pt"
+                  border-before-width.conditionality="retain"
+                  border-after-width.length="2pt"
+                  border-after-width.conditionality="retain">
+                  <fo:block background-color="yellow">
+                    <fo:block>Cell 1.2</fo:block>
+                    <fo:block>Cell 1.2</fo:block>
+                    <fo:block>Cell 1.2</fo:block>
+                    <fo:block>Cell 1.2</fo:block>
+                  </fo:block>
+                </fo:table-cell>
+              </fo:table-row>
+            </fo:table-body>
+          </fo:table>
+
+          <!-- Table 2 -->
+          <fo:block break-before="page"
+            space-after.minimum="20pt"
+            space-after.optimum="30pt"
+            space-after.maximum="40pt"
+            >Before the table</fo:block>
+          <fo:table width="100%" table-layout="fixed"
+            border-collapse="separate" border="4pt solid black">
+            <fo:table-column column-width="proportional-column-width(1)" number-columns-repeated="2"/>
+            <fo:table-body>
+              <fo:table-row>
+                <fo:table-cell border="4pt solid blue" padding="2pt"
+                  border-before-width.length="8pt"
+                  border-before-width.conditionality="retain"
+                  padding-after.length="5pt"
+                  padding-after.conditionality="retain">
+                  <fo:block background-color="yellow">
+                    <fo:block>Cell 1.1</fo:block>
+                    <fo:block>Cell 1.1</fo:block>
+                    <fo:block>Cell 1.1</fo:block>
+                    <fo:block>Cell 1.1</fo:block>
+                  </fo:block>
+                </fo:table-cell>
+                <fo:table-cell border="4pt solid blue" padding="2pt"
+                  border-after-width.length="6pt"
+                  border-after-width.conditionality="retain"
+                  padding-before.length="7pt"
+                  padding-before.conditionality="retain">
+                  <fo:block background-color="yellow">
+                    <fo:block>Cell 1.2</fo:block>
+                    <fo:block>Cell 1.2</fo:block>
+                    <fo:block>Cell 1.2</fo:block>
+                    <fo:block>Cell 1.2</fo:block>
+                  </fo:block>
+                </fo:table-cell>
+              </fo:table-row>
+            </fo:table-body>
+          </fo:table>
+
+          <!-- Table 3 -->
+          <fo:block break-before="page"
+            space-after.minimum="20pt"
+            space-after.optimum="30pt"
+            space-after.maximum="40pt"
+            >Before the table</fo:block>
+          <fo:table width="100%" table-layout="fixed"
+            border-collapse="separate" border="4pt solid black" border-separation="6pt">
+            <fo:table-column column-width="proportional-column-width(1)" number-columns-repeated="2"/>
+            <fo:table-body>
+              <fo:table-row>
+                <fo:table-cell border="4pt solid blue" padding="2pt"
+                  border-before-width.length="7pt"
+                  border-before-width.conditionality="retain"
+                  border-after-width.length="3pt"
+                  border-after-width.conditionality="retain"
+                  padding-before.length="5pt"
+                  padding-before.conditionality="retain"
+                  padding-after.length="1pt"
+                  padding-after.conditionality="retain">
+                  <fo:block background-color="yellow">
+                    <fo:block>Cell 1.1</fo:block>
+                    <fo:block>Cell 1.1</fo:block>
+                    <fo:block>Cell 1.1</fo:block>
+                    <fo:block>Cell 1.1</fo:block>
+                  </fo:block>
+                </fo:table-cell>
+                <fo:table-cell border="4pt solid blue" padding="2pt">
+                  <fo:block background-color="yellow">
+                    <fo:block>Cell 1.2</fo:block>
+                    <fo:block>Cell 1.2</fo:block>
+                    <fo:block>Cell 1.2</fo:block>
+                    <fo:block>Cell 1.2</fo:block>
+                  </fo:block>
+                </fo:table-cell>
+              </fo:table-row>
+            </fo:table-body>
+          </fo:table>
+
+          <!-- Table 4 -->
+          <fo:block break-before="page"
+            space-after.minimum="20pt"
+            space-after.optimum="30pt"
+            space-after.maximum="40pt"
+            >Before the table</fo:block>
+          <fo:table width="100%" table-layout="fixed"
+            border-collapse="separate" border="4pt solid black" border-separation="5pt">
+            <fo:table-column column-width="proportional-column-width(1)" number-columns-repeated="2"/>
+            <fo:table-body>
+              <fo:table-row>
+                <fo:table-cell border="4pt solid blue" padding="2pt"
+                  border-after-width.length="1pt"
+                  border-after-width.conditionality="retain"
+                  padding-after.length="9pt"
+                  padding-after.conditionality="retain">
+                  <fo:block background-color="yellow">
+                    <fo:block>Cell 1.1</fo:block>
+                    <fo:block>Cell 1.1</fo:block>
+                    <fo:block>Cell 1.1</fo:block>
+                    <fo:block>Cell 1.1</fo:block>
+                  </fo:block>
+                </fo:table-cell>
+                <fo:table-cell border="4pt solid blue" padding="2pt"
+                  border-before-width.length="10pt"
+                  border-before-width.conditionality="retain"
+                  padding-before.length="11pt"
+                  padding-before.conditionality="retain">
+                  <fo:block background-color="yellow">
+                    <fo:block>Cell 1.2</fo:block>
+                    <fo:block>Cell 1.2</fo:block>
+                    <fo:block>Cell 1.2</fo:block>
+                    <fo:block>Cell 1.2</fo:block>
+                  </fo:block>
+                </fo:table-cell>
+              </fo:table-row>
+            </fo:table-body>
+          </fo:table>
+
+          <!-- Table 5 -->
+          <!-- The cell on the second column finished early. Still, the conditional border-after
+          must be taken into account -->
+          <fo:block break-before="page"
+            space-after.minimum="40pt"
+            space-after.optimum="50pt"
+            space-after.maximum="60pt"
+            >Before the table</fo:block>
+          <fo:table width="100%" table-layout="fixed"
+            border-collapse="separate" border="4pt solid black">
+            <fo:table-column column-width="proportional-column-width(1)" number-columns-repeated="2"/>
+            <fo:table-body>
+              <fo:table-row>
+                <fo:table-cell border="2pt solid blue">
+                  <fo:block>Cell 1.1</fo:block>
+                  <fo:block>Cell 1.1</fo:block>
+                  <fo:block>Cell 1.1</fo:block>
+                  <fo:block>Cell 1.1</fo:block>
+                </fo:table-cell>
+                <fo:table-cell border="2pt solid red">
+                  <fo:block>Cell 1.2</fo:block>
+                </fo:table-cell>
+              </fo:table-row>
+            </fo:table-body>
+          </fo:table>
+
+        </fo:flow>
+      </fo:page-sequence>
+    </fo:root>
+  </fo>
+  <checks>
+
+    <!-- table 1 -->
+    <!-- before break -->
+    <eval expected="30000"                 xpath="//pageViewport[@nr='1']//flow/block[2]/@bpd"/>
+    <!-- cell 1.1 -->
+    <eval expected="21000"                 xpath="//pageViewport[@nr='1']//flow/block[2]/block[1]/@bpd"/>
+    <eval expected="30000"                 xpath="//pageViewport[@nr='1']//flow/block[2]/block[1]/@bpda"/>
+    <eval expected="(solid,#0000ff,4000)"  xpath="//pageViewport[@nr='1']//flow/block[2]/block[1]/@border-before"/>
+    <eval expected="2000"                  xpath="//pageViewport[@nr='1']//flow/block[2]/block[1]/@padding-before"/>
+    <eval expected="3000"                  xpath="//pageViewport[@nr='1']//flow/block[2]/block[1]/@padding-after"/>
+    <eval expected=""                      xpath="//pageViewport[@nr='1']//flow/block[2]/block[1]/@border-after"/>
+    <!-- cell 1.2 -->
+    <eval expected="20000"                 xpath="//pageViewport[@nr='1']//flow/block[2]/block[2]/@bpd"/>
+    <eval expected="30000"                 xpath="//pageViewport[@nr='1']//flow/block[2]/block[2]/@bpda"/>
+    <eval expected="(solid,#0000ff,6000)"  xpath="//pageViewport[@nr='1']//flow/block[2]/block[2]/@border-before"/>
+    <eval expected="2000"                  xpath="//pageViewport[@nr='1']//flow/block[2]/block[2]/@padding-before"/>
+    <eval expected=""                      xpath="//pageViewport[@nr='1']//flow/block[2]/block[2]/@padding-after"/>
+    <eval expected="(solid,#0000ff,2000)"  xpath="//pageViewport[@nr='1']//flow/block[2]/block[2]/@border-after"/>
+    <!-- after break -->
+    <eval expected="30000"                 xpath="//pageViewport[@nr='2']//flow/block[1]/@bpd"/>
+    <!-- cell 1.1 -->
+    <eval expected="21000"                 xpath="//pageViewport[@nr='2']//flow/block[1]/block[1]/@bpd"/>
+    <eval expected="30000"                 xpath="//pageViewport[@nr='2']//flow/block[1]/block[1]/@bpda"/>
+    <eval expected=""                      xpath="//pageViewport[@nr='2']//flow/block[1]/block[1]/@border-before"/>
+    <eval expected="2000"                  xpath="//pageViewport[@nr='2']//flow/block[1]/block[1]/@padding-before"/>
+    <eval expected="3000"                  xpath="//pageViewport[@nr='2']//flow/block[1]/block[1]/@padding-after"/>
+    <eval expected="(solid,#0000ff,4000)"  xpath="//pageViewport[@nr='2']//flow/block[1]/block[1]/@border-after"/>
+    <!-- cell 1.2 -->
+    <eval expected="20000"                 xpath="//pageViewport[@nr='2']//flow/block[1]/block[2]/@bpd"/>
+    <eval expected="30000"                 xpath="//pageViewport[@nr='2']//flow/block[1]/block[2]/@bpda"/>
+    <eval expected="(solid,#0000ff,6000)"  xpath="//pageViewport[@nr='2']//flow/block[1]/block[2]/@border-before"/>
+    <eval expected=""                      xpath="//pageViewport[@nr='2']//flow/block[1]/block[2]/@padding-before"/>
+    <eval expected="2000"                  xpath="//pageViewport[@nr='2']//flow/block[1]/block[2]/@padding-after"/>
+    <eval expected="(solid,#0000ff,2000)"  xpath="//pageViewport[@nr='2']//flow/block[1]/block[2]/@border-after"/>
+
+    <!-- table 2 -->
+    <!-- before break -->
+    <eval expected="45000"                 xpath="//pageViewport[@nr='3']//flow/block[2]/@bpd"/>
+    <!-- cell 1.1 -->
+    <eval expected="30000"                 xpath="//pageViewport[@nr='3']//flow/block[2]/block[1]/@bpd"/>
+    <eval expected="45000"                 xpath="//pageViewport[@nr='3']//flow/block[2]/block[1]/@bpda"/>
+    <eval expected="(solid,#0000ff,8000)"  xpath="//pageViewport[@nr='3']//flow/block[2]/block[1]/@border-before"/>
+    <eval expected="2000"                  xpath="//pageViewport[@nr='3']//flow/block[2]/block[1]/@padding-before"/>
+    <eval expected="5000"                  xpath="//pageViewport[@nr='3']//flow/block[2]/block[1]/@padding-after"/>
+    <eval expected=""                      xpath="//pageViewport[@nr='3']//flow/block[2]/block[1]/@border-after"/>
+    <!-- cell 1.2 -->
+    <eval expected="28000"                 xpath="//pageViewport[@nr='3']//flow/block[2]/block[2]/@bpd"/>
+    <eval expected="45000"                 xpath="//pageViewport[@nr='3']//flow/block[2]/block[2]/@bpda"/>
+    <eval expected="(solid,#0000ff,4000)"  xpath="//pageViewport[@nr='3']//flow/block[2]/block[2]/@border-before"/>
+    <eval expected="7000"                  xpath="//pageViewport[@nr='3']//flow/block[2]/block[2]/@padding-before"/>
+    <eval expected=""                      xpath="//pageViewport[@nr='3']//flow/block[2]/block[2]/@padding-after"/>
+    <eval expected="(solid,#0000ff,6000)"  xpath="//pageViewport[@nr='3']//flow/block[2]/block[2]/@border-after"/>
+    <!-- after break -->
+    <eval expected="35000"                 xpath="//pageViewport[@nr='4']//flow/block[1]/@bpd"/>
+    <!-- cell 1.1 -->
+    <eval expected="18000"                 xpath="//pageViewport[@nr='4']//flow/block[1]/block[1]/@bpd"/>
+    <eval expected="35000"                 xpath="//pageViewport[@nr='4']//flow/block[1]/block[1]/@bpda"/>
+    <eval expected="(solid,#0000ff,8000)"  xpath="//pageViewport[@nr='4']//flow/block[1]/block[1]/@border-before"/>
+    <eval expected=""                      xpath="//pageViewport[@nr='4']//flow/block[1]/block[1]/@padding-before"/>
+    <eval expected="5000"                  xpath="//pageViewport[@nr='4']//flow/block[1]/block[1]/@padding-after"/>
+    <eval expected="(solid,#0000ff,4000)"  xpath="//pageViewport[@nr='4']//flow/block[1]/block[1]/@border-after"/>
+    <!-- cell 1.2 -->
+    <eval expected="20000"                 xpath="//pageViewport[@nr='4']//flow/block[1]/block[2]/@bpd"/>
+    <eval expected="35000"                 xpath="//pageViewport[@nr='4']//flow/block[1]/block[2]/@bpda"/>
+    <eval expected=""                      xpath="//pageViewport[@nr='4']//flow/block[1]/block[2]/@border-before"/>
+    <eval expected="7000"                  xpath="//pageViewport[@nr='4']//flow/block[1]/block[2]/@padding-before"/>
+    <eval expected="2000"                  xpath="//pageViewport[@nr='4']//flow/block[1]/block[2]/@padding-after"/>
+    <eval expected="(solid,#0000ff,6000)"  xpath="//pageViewport[@nr='4']//flow/block[1]/block[2]/@border-after"/>
+
+    <!-- table 3 -->
+    <!-- before break -->
+    <eval expected="42000"                 xpath="//pageViewport[@nr='5']//flow/block[2]/@bpd"/>
+    <!-- cell 1.1 -->
+    <eval expected="20000"                 xpath="//pageViewport[@nr='5']//flow/block[2]/block[1]/@bpd"/>
+    <eval expected="36000"                 xpath="//pageViewport[@nr='5']//flow/block[2]/block[1]/@bpda"/>
+    <eval expected="(solid,#0000ff,7000)"  xpath="//pageViewport[@nr='5']//flow/block[2]/block[1]/@border-before"/>
+    <eval expected="5000"                  xpath="//pageViewport[@nr='5']//flow/block[2]/block[1]/@padding-before"/>
+    <eval expected="1000"                  xpath="//pageViewport[@nr='5']//flow/block[2]/block[1]/@padding-after"/>
+    <eval expected="(solid,#0000ff,3000)"  xpath="//pageViewport[@nr='5']//flow/block[2]/block[1]/@border-after"/>
+    <!-- cell 1.2 -->
+    <eval expected="33000"                 xpath="//pageViewport[@nr='5']//flow/block[2]/block[2]/@bpd"/>
+    <eval expected="39000"                 xpath="//pageViewport[@nr='5']//flow/block[2]/block[2]/@bpda"/>
+    <eval expected="(solid,#0000ff,4000)"  xpath="//pageViewport[@nr='5']//flow/block[2]/block[2]/@border-before"/>
+    <eval expected="2000"                  xpath="//pageViewport[@nr='5']//flow/block[2]/block[2]/@padding-before"/>
+    <eval expected=""                      xpath="//pageViewport[@nr='5']//flow/block[2]/block[2]/@padding-after"/>
+    <eval expected=""                      xpath="//pageViewport[@nr='5']//flow/block[2]/block[2]/@border-after"/>
+    <!-- after break -->
+    <eval expected="42000"                 xpath="//pageViewport[@nr='6']//flow/block[1]/@bpd"/>
+    <!-- cell 1.1 -->
+    <eval expected="20000"                 xpath="//pageViewport[@nr='6']//flow/block[1]/block[1]/@bpd"/>
+    <eval expected="36000"                 xpath="//pageViewport[@nr='6']//flow/block[1]/block[1]/@bpda"/>
+    <eval expected="(solid,#0000ff,7000)"  xpath="//pageViewport[@nr='6']//flow/block[1]/block[1]/@border-before"/>
+    <eval expected="5000"                  xpath="//pageViewport[@nr='6']//flow/block[1]/block[1]/@padding-before"/>
+    <eval expected="1000"                  xpath="//pageViewport[@nr='6']//flow/block[1]/block[1]/@padding-after"/>
+    <eval expected="(solid,#0000ff,3000)"  xpath="//pageViewport[@nr='6']//flow/block[1]/block[1]/@border-after"/>
+    <!-- cell 1.2 -->
+    <eval expected="33000"                 xpath="//pageViewport[@nr='6']//flow/block[1]/block[2]/@bpd"/>
+    <eval expected="39000"                 xpath="//pageViewport[@nr='6']//flow/block[1]/block[2]/@bpda"/>
+    <eval expected=""                      xpath="//pageViewport[@nr='6']//flow/block[1]/block[2]/@border-before"/>
+    <eval expected=""                      xpath="//pageViewport[@nr='6']//flow/block[1]/block[2]/@padding-before"/>
+    <eval expected="2000"                  xpath="//pageViewport[@nr='6']//flow/block[1]/block[2]/@padding-after"/>
+    <eval expected="(solid,#0000ff,4000)"  xpath="//pageViewport[@nr='6']//flow/block[1]/block[2]/@border-after"/>
+
+    <!-- table 4 -->
+    <!-- before break -->
+    <eval expected="41000"                 xpath="//pageViewport[@nr='7']//flow/block[2]/@bpd"/>
+    <!-- cell 1.1 -->
+    <eval expected="20000"                 xpath="//pageViewport[@nr='7']//flow/block[2]/block[1]/@bpd"/>
+    <eval expected="36000"                 xpath="//pageViewport[@nr='7']//flow/block[2]/block[1]/@bpda"/>
+    <eval expected="(solid,#0000ff,4000)"  xpath="//pageViewport[@nr='7']//flow/block[2]/block[1]/@border-before"/>
+    <eval expected="2000"                  xpath="//pageViewport[@nr='7']//flow/block[2]/block[1]/@padding-before"/>
+    <eval expected="9000"                  xpath="//pageViewport[@nr='7']//flow/block[2]/block[1]/@padding-after"/>
+    <eval expected="(solid,#0000ff,1000)"  xpath="//pageViewport[@nr='7']//flow/block[2]/block[1]/@border-after"/>
+    <!-- cell 1.2 -->
+    <eval expected="17500"                 xpath="//pageViewport[@nr='7']//flow/block[2]/block[2]/@bpd"/>
+    <eval expected="38500"                 xpath="//pageViewport[@nr='7']//flow/block[2]/block[2]/@bpda"/>
+    <eval expected="(solid,#0000ff,10000)" xpath="//pageViewport[@nr='7']//flow/block[2]/block[2]/@border-before"/>
+    <eval expected="11000"                 xpath="//pageViewport[@nr='7']//flow/block[2]/block[2]/@padding-before"/>
+    <eval expected=""                      xpath="//pageViewport[@nr='7']//flow/block[2]/block[2]/@padding-after"/>
+    <eval expected=""                      xpath="//pageViewport[@nr='7']//flow/block[2]/block[2]/@border-after"/>
+    <!-- after break -->
+    <eval expected="62000"                 xpath="//pageViewport[@nr='8']//flow/block[1]/@bpd"/>
+    <!-- cell 1.1 -->
+    <eval expected="49500"                 xpath="//pageViewport[@nr='8']//flow/block[1]/block[1]/@bpd"/>
+    <eval expected="59500"                 xpath="//pageViewport[@nr='8']//flow/block[1]/block[1]/@bpda"/>
+    <eval expected=""                      xpath="//pageViewport[@nr='8']//flow/block[1]/block[1]/@border-before"/>
+    <eval expected=""                      xpath="//pageViewport[@nr='8']//flow/block[1]/block[1]/@padding-before"/>
+    <eval expected="9000"                  xpath="//pageViewport[@nr='8']//flow/block[1]/block[1]/@padding-after"/>
+    <eval expected="(solid,#0000ff,1000)"  xpath="//pageViewport[@nr='8']//flow/block[1]/block[1]/@border-after"/>
+    <!-- cell 1.2 -->
+    <eval expected="30000"                 xpath="//pageViewport[@nr='8']//flow/block[1]/block[2]/@bpd"/>
+    <eval expected="57000"                 xpath="//pageViewport[@nr='8']//flow/block[1]/block[2]/@bpda"/>
+    <eval expected="(solid,#0000ff,10000)" xpath="//pageViewport[@nr='8']//flow/block[1]/block[2]/@border-before"/>
+    <eval expected="11000"                 xpath="//pageViewport[@nr='8']//flow/block[1]/block[2]/@padding-before"/>
+    <eval expected="2000"                  xpath="//pageViewport[@nr='8']//flow/block[1]/block[2]/@padding-after"/>
+    <eval expected="(solid,#0000ff,4000)"  xpath="//pageViewport[@nr='8']//flow/block[1]/block[2]/@border-after"/>
+
+    <!-- table 5 -->
+    <!-- before break -->
+    <eval expected="22000"                 xpath="//pageViewport[@nr='9']//flow/block[2]/@bpd"/>
+    <!-- cell 1.1 -->
+    <eval expected="20000"                 xpath="//pageViewport[@nr='9']//flow/block[2]/block[1]/@bpd"/>
+    <eval expected="22000"                 xpath="//pageViewport[@nr='9']//flow/block[2]/block[1]/@bpda"/>
+    <eval expected="(solid,#0000ff,2000)"  xpath="//pageViewport[@nr='9']//flow/block[2]/block[1]/@border-before"/>
+    <eval expected=""                      xpath="//pageViewport[@nr='9']//flow/block[2]/block[1]/@border-after"/>
+    <!-- cell 1.2 -->
+    <eval expected="20000"                 xpath="//pageViewport[@nr='9']//flow/block[2]/block[2]/@bpd"/>
+    <eval expected="22000"                 xpath="//pageViewport[@nr='9']//flow/block[2]/block[2]/@bpda"/>
+    <eval expected="(solid,#ff0000,2000)"  xpath="//pageViewport[@nr='9']//flow/block[2]/block[2]/@border-before"/>
+    <eval expected=""                      xpath="//pageViewport[@nr='9']//flow/block[2]/block[2]/@border-after"/>
+    <!-- after break -->
+    <eval expected="22000"                 xpath="//pageViewport[@nr='10']//flow/block[1]/@bpd"/>
+    <!-- cell 1.1 -->
+    <eval expected="20000"                 xpath="//pageViewport[@nr='10']//flow/block[1]/block[1]/@bpd"/>
+    <eval expected="22000"                 xpath="//pageViewport[@nr='10']//flow/block[1]/block[1]/@bpda"/>
+    <eval expected=""                      xpath="//pageViewport[@nr='10']//flow/block[1]/block[1]/@border-before"/>
+    <eval expected="(solid,#0000ff,2000)"  xpath="//pageViewport[@nr='10']//flow/block[1]/block[1]/@border-after"/>
+    <!-- cell 1.2 -->
+    <eval expected="20000"                 xpath="//pageViewport[@nr='10']//flow/block[1]/block[2]/@bpd"/>
+    <eval expected="22000"                 xpath="//pageViewport[@nr='10']//flow/block[1]/block[2]/@bpda"/>
+    <eval expected=""                      xpath="//pageViewport[@nr='10']//flow/block[1]/block[2]/@border-before"/>
+    <eval expected="(solid,#ff0000,2000)"  xpath="//pageViewport[@nr='10']//flow/block[1]/block[2]/@border-after"/>
+
+  </checks>
+</testcase>
index b85e0ea628720581b5a0847c7a87a857d82c0326..31c1fd8cba7d3b070884c25cb22591aa38a49c4b 100644 (file)
   <fo>
     <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:svg="http://www.w3.org/2000/svg">
       <fo:layout-master-set>
-        <fo:simple-page-master master-name="normal" page-width="5in" page-height="5in">
+        <fo:simple-page-master master-name="normal" page-width="5in" page-height="5in" margin="20pt">
           <fo:region-body/>
         </fo:simple-page-master>
       </fo:layout-master-set>
       <fo:page-sequence master-reference="normal" white-space-collapse="true">
         <fo:flow flow-name="xsl-region-body">
           <fo:block>before the table</fo:block>
-          <fo:table table-layout="fixed" width="100%" break-before="odd-page" break-after="odd-page">
-            <fo:table-column/>
-            <fo:table-column/>
+          <fo:table table-layout="fixed" width="100%" border-collapse="separate" border="4pt solid black"
+            break-before="odd-page" break-after="odd-page">
+            <fo:table-column number-columns-repeated="2" column-width="proportional-column-width(1)"/>
             <fo:table-body>
               <fo:table-row>
-                <fo:table-cell background-color="orange">
-                  <fo:block>cell3</fo:block>
+                <fo:table-cell border="2pt solid blue" background-color="orange">
+                  <fo:block>cell1</fo:block>
                 </fo:table-cell>
-                <fo:table-cell>
-                  <fo:block>cell4</fo:block>
+                <fo:table-cell border="2pt solid red">
+                  <fo:block>cell2</fo:block>
                 </fo:table-cell>
               </fo:table-row>
             </fo:table-body>
   </fo>
   <checks>
     <eval expected="5" xpath="count(//pageViewport)"/>
+    <!-- table -->
+    <eval expected="18400" xpath="//pageViewport[@nr=3]//flow/block[1]/@bpd"/>
+    <!--
+    <eval expected="26400" xpath="//pageViewport[@nr=3]//flow/block[1]/@bpda"/>
+    <eval expected="(solid,#000000,4000)" xpath="//pageViewport[@nr=3]//flow/block[1]/@border-before"/>
+    <eval expected="(solid,#000000,4000)" xpath="//pageViewport[@nr=3]//flow/block[1]/@border-after"/>
+    -->
+    <!-- cell 1 -->
+    <eval expected="14400" xpath="//pageViewport[@nr=3]//flow/block[1]/block[1]/@bpd"/>
+    <eval expected="18400" xpath="//pageViewport[@nr=3]//flow/block[1]/block[1]/@bpda"/>
+    <eval expected="(solid,#0000ff,2000)" xpath="//pageViewport[@nr=3]//flow/block[1]/block[1]/@border-before"/>
+    <eval expected="(solid,#0000ff,2000)" xpath="//pageViewport[@nr=3]//flow/block[1]/block[1]/@border-after"/>
+    <!-- cell 2 -->
+    <eval expected="14400" xpath="//pageViewport[@nr=3]//flow/block[1]/block[2]/@bpd"/>
+    <eval expected="18400" xpath="//pageViewport[@nr=3]//flow/block[1]/block[2]/@bpda"/>
+    <eval expected="(solid,#ff0000,2000)" xpath="//pageViewport[@nr=3]//flow/block[1]/block[2]/@border-before"/>
+    <eval expected="(solid,#ff0000,2000)" xpath="//pageViewport[@nr=3]//flow/block[1]/block[2]/@border-after"/>
   </checks>
 </testcase>
index 8d8e8950b9ebedfdd01012500e1ccca28ad1ce62..ee2116b504bb624b2511b7def5e3564f058ab366 100644 (file)
   </fo>
   <checks>
     <element-list category="breaker" id="skipped-step">
-      <box w="0"/>
-      <penalty w="14400" p="INF"/> <!-- Skipped step has an INFINITE penalty -->
-      <box w="50400"/>
+      <box w="14400"/>
+      <penalty w="0" p="INF"/> <!-- Skipped step has an INFINITE penalty -->
+      <glue w="3600"/>
+      <box w="32400"/>
       <skip>3</skip>
     </element-list>
     <element-list category="breaker" id="backtrack">
-      <box w="0"/>
-      <penalty w="10000"/> <!-- p > 0 && p <= INF -->
-      <box w="18400"/>
+      <box w="2000"/>
+      <penalty w="8000" p="900"/> <!-- p > 0 && p <= INF -->
+      <box w="16400"/>
       <penalty w="0" p="0"/>
       <box w="0"/>
       <penalty w="1600"/> <!-- p = ??? --> <!-- I'm not sure here what the penalty values should be for these two. -->
-      <box w="0"/>
-      <penalty w="11600"/> <!-- p = ??? -->
-      <box w="24400"/>
+      <box w="5000"/>
+      <penalty w="6600"/> <!-- p = ??? -->
+      <box w="19400"/>
       <skip>3</skip>
     </element-list>
   </checks>
index 9d93aaab05da501678cdb18f6fa1443bab094b5b..e9911fb4b79f7312ce44ac304b9eb5037b15331f 100644 (file)
     <eval expected="2" xpath="count(//pageViewport)"/>
     <element-list category="breaker">
       <skip>6</skip>
-      <box w="0"/>
-      <penalty p="900" w="2000"/>
+      <box w="1000"/>
+      <penalty p="900" w="1000"/>
       <box w="14400"/>
-      <penalty p="0" w="2000"/>
+      <penalty p="0" w="0"/>
       <box w="14400"/>
-      <penalty p="0" w="2000"/>
-      <box w="16400"/>
+      <penalty p="0" w="0"/>
+      <box w="15400"/>
       <penalty p="0" w="0"/>
       <skip>16</skip>
     </element-list>