diff options
author | Vincent Hennebert <vhennebert@apache.org> | 2008-01-23 15:22:05 +0000 |
---|---|---|
committer | Vincent Hennebert <vhennebert@apache.org> | 2008-01-23 15:22:05 +0000 |
commit | 58868131c9b55c3bf8f91cad92304e118ab1de41 (patch) | |
tree | 07ec135eb57c3119b2517370ef14da1e958fc0eb | |
parent | 67c26ead2f80ffd25cd27a84023c2e922f173ce7 (diff) | |
download | xmlgraphics-fop-58868131c9b55c3bf8f91cad92304e118ab1de41.tar.gz xmlgraphics-fop-58868131c9b55c3bf8f91cad92304e118ab1de41.zip |
Added support for conditional borders (and paddings) in tables.
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, 1521 insertions, 670 deletions
diff --git a/src/java/org/apache/fop/fo/flow/table/CollapsingBorderResolver.java b/src/java/org/apache/fop/fo/flow/table/CollapsingBorderResolver.java index 16fc55cfc..235f05042 100644 --- a/src/java/org/apache/fop/fo/flow/table/CollapsingBorderResolver.java +++ b/src/java/org/apache/fop/fo/flow/table/CollapsingBorderResolver.java @@ -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 */ } } diff --git a/src/java/org/apache/fop/fo/flow/table/ConditionalBorder.java b/src/java/org/apache/fop/fo/flow/table/ConditionalBorder.java index 4f3cca046..4313b82a6 100644 --- a/src/java/org/apache/fop/fo/flow/table/ConditionalBorder.java +++ b/src/java/org/apache/fop/fo/flow/table/ConditionalBorder.java @@ -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; diff --git a/src/java/org/apache/fop/fo/flow/table/FixedColRowGroupBuilder.java b/src/java/org/apache/fop/fo/flow/table/FixedColRowGroupBuilder.java index 7df071191..2f8b0bbb8 100644 --- a/src/java/org/apache/fop/fo/flow/table/FixedColRowGroupBuilder.java +++ b/src/java/org/apache/fop/fo/flow/table/FixedColRowGroupBuilder.java @@ -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(); } } diff --git a/src/java/org/apache/fop/fo/flow/table/GridUnit.java b/src/java/org/apache/fop/fo/flow/table/GridUnit.java index d6d622d57..a583697f6 100644 --- a/src/java/org/apache/fop/fo/flow/table/GridUnit.java +++ b/src/java/org/apache/fop/fo/flow/table/GridUnit.java @@ -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(); } /** diff --git a/src/java/org/apache/fop/fo/flow/table/PrimaryGridUnit.java b/src/java/org/apache/fop/fo/flow/table/PrimaryGridUnit.java index ae8db7ba7..684fa58d1 100644 --- a/src/java/org/apache/fop/fo/flow/table/PrimaryGridUnit.java +++ b/src/java/org/apache/fop/fo/flow/table/PrimaryGridUnit.java @@ -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; diff --git a/src/java/org/apache/fop/fo/flow/table/Table.java b/src/java/org/apache/fop/fo/flow/table/Table.java index a915edf87..2b6570dcc 100644 --- a/src/java/org/apache/fop/fo/flow/table/Table.java +++ b/src/java/org/apache/fop/fo/flow/table/Table.java @@ -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(); } diff --git a/src/java/org/apache/fop/layoutmgr/TraitSetter.java b/src/java/org/apache/fop/layoutmgr/TraitSetter.java index f1e5ffdc6..841a94705 100644 --- a/src/java/org/apache/fop/layoutmgr/TraitSetter.java +++ b/src/java/org/apache/fop/layoutmgr/TraitSetter.java @@ -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 { diff --git a/src/java/org/apache/fop/layoutmgr/table/ActiveCell.java b/src/java/org/apache/fop/layoutmgr/table/ActiveCell.java index a1957eb27..4321c32b8 100644 --- a/src/java/org/apache/fop/layoutmgr/table/ActiveCell.java +++ b/src/java/org/apache/fop/layoutmgr/table/ActiveCell.java @@ -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() { diff --git a/src/java/org/apache/fop/layoutmgr/table/CellPart.java b/src/java/org/apache/fop/layoutmgr/table/CellPart.java index bf5ad64cf..f6c292f97 100644 --- a/src/java/org/apache/fop/layoutmgr/table/CellPart.java +++ b/src/java/org/apache/fop/layoutmgr/table/CellPart.java @@ -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} */ diff --git a/src/java/org/apache/fop/layoutmgr/table/RowGroupLayoutManager.java b/src/java/org/apache/fop/layoutmgr/table/RowGroupLayoutManager.java index 3fa40a8fd..199af0fc1 100644 --- a/src/java/org/apache/fop/layoutmgr/table/RowGroupLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/table/RowGroupLayoutManager.java @@ -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; } diff --git a/src/java/org/apache/fop/layoutmgr/table/RowPainter.java b/src/java/org/apache/fop/layoutmgr/table/RowPainter.java index 9a79d7744..f46b503bb 100644 --- a/src/java/org/apache/fop/layoutmgr/table/RowPainter.java +++ b/src/java/org/apache/fop/layoutmgr/table/RowPainter.java @@ -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); + } } diff --git a/src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java b/src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java index 63810e057..421d3d580 100644 --- a/src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java @@ -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; } @@ -272,15 +274,6 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager } /** - * 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,37 +284,16 @@ 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 diff --git a/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java b/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java index 57972078e..344c90e07 100644 --- a/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java @@ -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, diff --git a/src/java/org/apache/fop/layoutmgr/table/TableStepper.java b/src/java/org/apache/fop/layoutmgr/table/TableStepper.java index 35bf4c844..1d9f95ca1 100644 --- a/src/java/org/apache/fop/layoutmgr/table/TableStepper.java +++ b/src/java/org/apache/fop/layoutmgr/table/TableStepper.java @@ -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(); } diff --git a/status.xml b/status.xml index 21c98c9ab..c261f442b 100644 --- a/status.xml +++ b/status.xml @@ -28,6 +28,10 @@ <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. diff --git a/test/fotree/unittests/table/collapsed-conditional-borders_test-generator.py b/test/fotree/unittests/table/collapsed-conditional-borders_test-generator.py index b3b697235..1bd5d441d 100755 --- a/test/fotree/unittests/table/collapsed-conditional-borders_test-generator.py +++ b/test/fotree/unittests/table/collapsed-conditional-borders_test-generator.py @@ -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() diff --git a/test/java/org/apache/fop/fo/flow/table/CollapsedConditionalBorderTestCase.java b/test/java/org/apache/fop/fo/flow/table/CollapsedConditionalBorderTestCase.java index 8037df8ad..e42ee2935 100644 --- a/test/java/org/apache/fop/fo/flow/table/CollapsedConditionalBorderTestCase.java +++ b/test/java/org/apache/fop/fo/flow/table/CollapsedConditionalBorderTestCase.java @@ -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()); diff --git a/test/java/org/apache/fop/fotreetest/FOTreeTestSuite.java b/test/java/org/apache/fop/fotreetest/FOTreeTestSuite.java index 5e492ec75..04752064f 100644 --- a/test/java/org/apache/fop/fotreetest/FOTreeTestSuite.java +++ b/test/java/org/apache/fop/fotreetest/FOTreeTestSuite.java @@ -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 { diff --git a/test/layoutengine/standard-testcases/table-cell_block_break-after.xml b/test/layoutengine/standard-testcases/table-cell_block_break-after.xml index 14c5f3b89..8b595ce3c 100644 --- a/test/layoutengine/standard-testcases/table-cell_block_break-after.xml +++ b/test/layoutengine/standard-testcases/table-cell_block_break-after.xml @@ -66,14 +66,14 @@ <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> diff --git a/test/layoutengine/standard-testcases/table-cell_span-combinations.xml b/test/layoutengine/standard-testcases/table-cell_span-combinations.xml index fc2357e9f..22ccc303d 100644 --- a/test/layoutengine/standard-testcases/table-cell_span-combinations.xml +++ b/test/layoutengine/standard-testcases/table-cell_span-combinations.xml @@ -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> diff --git a/test/layoutengine/standard-testcases/table-row_break-before_break-after_2.xml b/test/layoutengine/standard-testcases/table-row_break-before_break-after_2.xml index 93b495d56..b7f2b7c6f 100644 --- a/test/layoutengine/standard-testcases/table-row_break-before_break-after_2.xml +++ b/test/layoutengine/standard-testcases/table-row_break-before_break-after_2.xml @@ -32,16 +32,15 @@ <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> @@ -53,5 +52,22 @@ </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 index 000000000..a653be423 --- /dev/null +++ b/test/layoutengine/standard-testcases/table_border-collapse_collapse_conditionals.xml @@ -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> diff --git a/test/layoutengine/standard-testcases/table_border-collapse_collapse_spans_1.xml b/test/layoutengine/standard-testcases/table_border-collapse_collapse_spans_1.xml index 5bc7aed33..4a9464bf1 100644 --- a/test/layoutengine/standard-testcases/table_border-collapse_collapse_spans_1.xml +++ b/test/layoutengine/standard-testcases/table_border-collapse_collapse_spans_1.xml @@ -208,6 +208,7 @@ <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"/> @@ -216,6 +217,7 @@ <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"/> @@ -270,6 +272,7 @@ <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"/> @@ -278,6 +281,7 @@ <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"/> @@ -301,6 +305,7 @@ <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"/> @@ -309,6 +314,7 @@ <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"/> @@ -374,6 +380,7 @@ <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"/> @@ -382,6 +389,7 @@ <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"/> diff --git a/test/layoutengine/standard-testcases/table_border-collapse_separate_border-spacing_2.xml b/test/layoutengine/standard-testcases/table_border-collapse_separate_border-spacing_2.xml index bb4746cdd..52f0de812 100644 --- a/test/layoutengine/standard-testcases/table_border-collapse_separate_border-spacing_2.xml +++ b/test/layoutengine/standard-testcases/table_border-collapse_separate_border-spacing_2.xml @@ -134,17 +134,19 @@ <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"/> @@ -154,17 +156,19 @@ <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 index 000000000..227d5563f --- /dev/null +++ b/test/layoutengine/standard-testcases/table_border-collapse_separate_conditionals.xml @@ -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> diff --git a/test/layoutengine/standard-testcases/table_break-before_break-after.xml b/test/layoutengine/standard-testcases/table_break-before_break-after.xml index b85e0ea62..31c1fd8cb 100644 --- a/test/layoutengine/standard-testcases/table_break-before_break-after.xml +++ b/test/layoutengine/standard-testcases/table_break-before_break-after.xml @@ -25,23 +25,23 @@ <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> @@ -53,5 +53,22 @@ </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_bug36403.xml b/test/layoutengine/standard-testcases/table_bug36403.xml index 8d8e8950b..ee2116b50 100644 --- a/test/layoutengine/standard-testcases/table_bug36403.xml +++ b/test/layoutengine/standard-testcases/table_bug36403.xml @@ -79,21 +79,22 @@ </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> diff --git a/test/layoutengine/standard-testcases/table_empty-cells.xml b/test/layoutengine/standard-testcases/table_empty-cells.xml index 9d93aaab0..e9911fb4b 100644 --- a/test/layoutengine/standard-testcases/table_empty-cells.xml +++ b/test/layoutengine/standard-testcases/table_empty-cells.xml @@ -87,13 +87,13 @@ <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> |