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
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) {
*/
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);
borderAfter.rest = borderAfter.nonLeadingTrailing;
leadingBorders.add(borderAfter);
}
+ /* TODO Temporary hack for resolved borders in header */
+ headerLastRow = previousRow;
+ /* End of temporary hack */
}
void endTable() {
// 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);
private class ResolverInBody extends Resolver {
+ private boolean firstInBody = true;
+
void endRow(List/*<GridUnit>*/ row, TableCellContainer container) {
super.endRow(row, container);
if (firstInTable) {
}
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() {
} 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;
+ }
}
}
}
trailingBorders.add(border);
}
}
- delegate = new ResolverInBody();
+ delegate = resolverInBody;
}
}
delegate.startPart(part);
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 */
}
}
*/
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;
/** 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. */
private BorderResolver borderResolver;
- private boolean inFooter;
-
- private List lastFooterRow;
-
FixedColRowGroupBuilder(Table t) {
super(t);
numberOfColumns = t.getNumberOfColumns();
}
}
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;
/** {@inheritDoc} */
void startTablePart(TableBody part) {
firstInPart = true;
- inFooter = part.isTableFooter();
borderResolver.startPart(part);
}
}
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();
}
}
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;
*/
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;
/** 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;
}
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();
}
}
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;
}
}
/**
- * 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();
}
/**
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;
/** 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.
*
*/
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);
}
}
/**
- * @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. */
*/
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;
* @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);
}
*
* @return the number of columns, implicit or explicit, in this table
*/
- int getNumberOfColumns() {
+ public int getNumberOfColumns() {
return columns.size();
}
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;
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;
* 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);
}
}
}
- 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 {
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;
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. */
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(
}
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();
}
} 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;
+ }
}
/**
* @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;
}
/**
* @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);
}
}
* 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
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;
}
/**
* @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);
}
/**
* @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;
}
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() {
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 {
/** 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 */
}
/** @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} */
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;
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
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;
}
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);
* 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
*/
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() {
*/
void handleTableContentPosition(TableContentPosition tcpos) {
if (tcpos.row != currentRow && currentRow != null) {
- addAreasAndFlushRow(false);
+ addAreasAndFlushRow(false, false);
}
if (log.isDebugEnabled()) {
log.debug("===handleTableContentPosition(" + tcpos);
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
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];
}
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(),
}
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);
}
/**
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);
+ }
}
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;
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;
/**
private Block curBlockArea;
- private int inRowIPDOffset;
-
private int xoffset;
private int yoffset;
private int cellIPD;
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;
}
xoffset = off;
}
- /**
- * Set the IPD offset of this cell inside the table-row.
- * This offset is used to determine the absolute position of the cell.
- * @param off the IPD offset
- */
- public void setInRowIPDOffset(int off) {
- this.inRowIPDOffset = off;
- }
-
/**
* Set the content height for this cell. This method is used during
* addAreas() stage.
}
/**
- * 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.
* 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()) {
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.
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
package org.apache.fop.layoutmgr.table;
+import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
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());
} 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) {
//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();
* @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()) {
body = null;
lst.clear();
}
- } else {
- if (log.isDebugEnabled()) {
- log.debug("Ignoring position: " + pos);
- }
}
}
if (body != null) {
// 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,
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()));
}
}
}
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);
private void removeCellsEndingOnCurrentRow() {
for (Iterator iter = activeCells.iterator(); iter.hasNext();) {
ActiveCell activeCell = (ActiveCell) iter.next();
+ activeCell.endRow(activeRowIndex);
if (activeCell.endsOnRow(activeRowIndex)) {
iter.remove();
}
<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.
]
bordersBefore = None
- resBefore = None
+ resBefore = {}
"""The comma between each table; nothing before the first one."""
separator = ''
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
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
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:
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()
* 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}}
};
/**
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());
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;
suite.addTestSuite(IllegalRowSpanTestCase.class);
suite.addTestSuite(RowGroupBuilderTestCase.class);
suite.addTestSuite(TableColumnColumnNumberTestCase.class);
+ suite.addTestSuite(CollapsedConditionalBorderTestCase.class);
}
private static class FOTreeTestCase extends TestCase {
<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)"/>
<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 -->
<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>
<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">
<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>
<fo:page-sequence master-reference="normal" white-space-collapse="true">
<fo:flow flow-name="xsl-region-body">
<fo:block>before the table</fo:block>
- <fo:table table-layout="fixed" width="100%">
- <fo:table-column/>
- <fo:table-column/>
+ <fo:table table-layout="fixed" width="100%" border-collapse="separate" border="4pt solid black">
+ <fo:table-column number-columns-repeated="2" column-width="proportional-column-width(1)"/>
<fo:table-body>
<fo:table-row break-before="odd-page" break-after="odd-page">
- <fo:table-cell background-color="orange">
- <fo:block>cell3</fo:block>
+ <fo:table-cell border="2pt solid blue" background-color="orange">
+ <fo:block>cell1</fo:block>
</fo:table-cell>
- <fo:table-cell>
- <fo:block>cell4</fo:block>
+ <fo:table-cell border="2pt solid red">
+ <fo:block>cell2</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo>
<checks>
<eval expected="5" xpath="count(//pageViewport)"/>
+ <!-- table -->
+ <eval expected="18400" xpath="//pageViewport[@nr=3]//flow/block[1]/@bpd"/>
+ <!--
+ <eval expected="26400" xpath="//pageViewport[@nr=3]//flow/block[1]/@bpda"/>
+ <eval expected="(solid,#000000,4000)" xpath="//pageViewport[@nr=3]//flow/block[1]/@border-before"/>
+ <eval expected="(solid,#000000,4000)" xpath="//pageViewport[@nr=3]//flow/block[1]/@border-after"/>
+ -->
+ <!-- cell 1 -->
+ <eval expected="14400" xpath="//pageViewport[@nr=3]//flow/block[1]/block[1]/@bpd"/>
+ <eval expected="18400" xpath="//pageViewport[@nr=3]//flow/block[1]/block[1]/@bpda"/>
+ <eval expected="(solid,#0000ff,2000)" xpath="//pageViewport[@nr=3]//flow/block[1]/block[1]/@border-before"/>
+ <eval expected="(solid,#0000ff,2000)" xpath="//pageViewport[@nr=3]//flow/block[1]/block[1]/@border-after"/>
+ <!-- cell 2 -->
+ <eval expected="14400" xpath="//pageViewport[@nr=3]//flow/block[1]/block[2]/@bpd"/>
+ <eval expected="18400" xpath="//pageViewport[@nr=3]//flow/block[1]/block[2]/@bpda"/>
+ <eval expected="(solid,#ff0000,2000)" xpath="//pageViewport[@nr=3]//flow/block[1]/block[2]/@border-before"/>
+ <eval expected="(solid,#ff0000,2000)" xpath="//pageViewport[@nr=3]//flow/block[1]/block[2]/@border-after"/>
</checks>
</testcase>
--- /dev/null
+<?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>
<eval expected="6000" xpath="//flow/block[2]/block[2]/@left-offset"/>
<eval expected="-8000" xpath="//flow/block[2]/block[2]/@top-offset"/>
<eval expected="(solid,#000000,16000,collapse-outer)" xpath="//flow/block[2]/block[2]/@border-before"/>
+ <eval expected="" xpath="//flow/block[2]/block[2]/@border-after"/>
<eval expected="(solid,#ff0000,12000,collapse-outer)" xpath="//flow/block[2]/block[2]/@border-start"/>
<eval expected="(solid,#800080,10000,collapse-inner)" xpath="//flow/block[2]/block[2]/@border-end"/>
<eval expected="92000" xpath="//flow/block[2]/block[3]/@ipd"/>
<eval expected="41800" xpath="//flow/block[2]/block[3]/@bpda"/>
<eval expected="6000" xpath="//flow/block[2]/block[3]/@left-offset"/>
<eval expected="21400" xpath="//flow/block[2]/block[3]/@top-offset"/>
+ <eval expected="" xpath="//flow/block[2]/block[3]/@border-before"/>
<eval expected="(solid,#0000ff,10000,collapse-outer)" xpath="//flow/block[2]/block[3]/@border-after"/>
<eval expected="(solid,#ff0000,12000,collapse-outer)" xpath="//flow/block[2]/block[3]/@border-start"/>
<eval expected="(solid,#008080,4000,collapse-inner)" xpath="//flow/block[2]/block[3]/@border-end"/>
<eval expected="102000" xpath="//flow/block[4]/block[3]/@left-offset"/>
<eval expected="-2000" xpath="//flow/block[4]/block[3]/@top-offset"/>
<eval expected="(solid,#c0c0c0,4000,collapse-outer)" xpath="//flow/block[4]/block[3]/@border-before"/>
+ <eval expected="" xpath="//flow/block[4]/block[3]/@border-after"/>
<eval expected="(solid,#800080,4000,collapse-inner)" xpath="//flow/block[4]/block[3]/@border-start"/>
<eval expected="(solid,#808000,10000,collapse-outer)" xpath="//flow/block[4]/block[3]/@border-end"/>
<eval expected="87000" xpath="//flow/block[4]/block[4]/@ipd"/>
<eval expected="71600" xpath="//flow/block[4]/block[4]/@bpda"/>
<eval expected="108000" xpath="//flow/block[4]/block[4]/@left-offset"/>
<eval expected="26400" xpath="//flow/block[4]/block[4]/@top-offset"/>
+ <eval expected="" xpath="//flow/block[4]/block[4]/@border-before"/>
<eval expected="(solid,#800080,4000,collapse-outer)" xpath="//flow/block[4]/block[4]/@border-after"/>
<eval expected="(solid,#808000,16000,collapse-inner)" xpath="//flow/block[4]/block[4]/@border-start"/>
<eval expected="(solid,#808000,10000,collapse-outer)" xpath="//flow/block[4]/block[4]/@border-end"/>
<eval expected="(solid,#000000,2000,collapse-outer)" xpath="//flow/block[6]/block[1]/@border-before"/>
<eval expected="(solid,#0000ff,4000,collapse-inner)" xpath="//flow/block[6]/block[1]/@border-after"/>
<eval expected="(solid,#ff0000,2000,collapse-outer)" xpath="//flow/block[6]/block[1]/@border-start"/>
+ <eval expected="" xpath="//flow/block[6]/block[6]/@border-end"/>
<eval expected="99000" xpath="//flow/block[6]/block[2]/@ipd"/>
<eval expected="101000" xpath="//flow/block[6]/block[2]/@ipda"/>
<eval expected="23400" xpath="//flow/block[6]/block[2]/@bpd"/>
<eval expected="-1000" xpath="//flow/block[6]/block[2]/@top-offset"/>
<eval expected="(solid,#000000,2000,collapse-outer)" xpath="//flow/block[6]/block[2]/@border-before"/>
<eval expected="(solid,#000000,10000,collapse-inner)" xpath="//flow/block[6]/block[2]/@border-after"/>
+ <eval expected="" xpath="//flow/block[6]/block[2]/@border-start"/>
<eval expected="(solid,#008080,2000,collapse-outer)" xpath="//flow/block[6]/block[2]/@border-end"/>
<eval expected="185000" xpath="//flow/block[6]/block[3]/@ipd"/>
<eval expected="198000" xpath="//flow/block[6]/block[3]/@ipda"/>
<eval expected="(solid,#c0c0c0,15000,collapse-inner)" xpath="//flow/block[8]/block[3]/@border-before"/>
<eval expected="(solid,#000080,6000,collapse-outer)" xpath="//flow/block[8]/block[3]/@border-after"/>
<eval expected="(solid,#800080,6000,collapse-outer)" xpath="//flow/block[8]/block[3]/@border-start"/>
+ <eval expected="" xpath="//flow/block[8]/block[3]/@border-end"/>
<eval expected="97000" xpath="//flow/block[8]/block[4]/@ipd"/>
<eval expected="103000" xpath="//flow/block[8]/block[4]/@ipda"/>
<eval expected="39400" xpath="//flow/block[8]/block[4]/@bpd"/>
<eval expected="34800" xpath="//flow/block[8]/block[4]/@top-offset"/>
<eval expected="(solid,#c0c0c0,15000,collapse-inner)" xpath="//flow/block[8]/block[4]/@border-before"/>
<eval expected="(solid,#000080,6000,collapse-outer)" xpath="//flow/block[8]/block[4]/@border-after"/>
+ <eval expected="" xpath="//flow/block[8]/block[4]/@border-start"/>
<eval expected="(solid,#808000,6000,collapse-outer)" xpath="//flow/block[8]/block[4]/@border-end"/>
<eval expected="144000" xpath="//flow/block[8]/block[5]/@ipd"/>
<eval expected="194000" xpath="//flow/block[8]/block[5]/@ipda"/>
<box w="0"/>
<penalty w="0" p="INF"/>
<glue w="7500"/>
- <box w="15000"/>
- <penalty w="0"/>
- <box w="5000"/>
- <penalty w="5000"/>
- <box w="0"/>
- <penalty w="10000"/>
- <box w="15000"/>
+ <box w="2500"/>
+ <penalty w="10000" p="900"/>
+ <box w="12500"/>
<penalty w="0"/>
+ <box w="7500"/>
+ <penalty w="0" p="900"/>
<box w="0"/>
<penalty w="5000"/>
- <box w="15000"/>
+ <box w="12500"/>
+ <penalty w="0"/>
+ <box w="2500"/>
+ <penalty w="0" p="900"/>
+ <box w="12500"/>
<penalty w="0" p="INF"/>
<glue w="7500"/>
<box w="0"/>
<penalty w="0" p="INF"/>
<glue w="7500"/>
- <box w="15000"/>
- <penalty w="0"/>
- <box w="5000"/>
- <penalty w="5000"/>
- <box w="0"/>
- <penalty w="10000"/>
- <box w="15000"/>
+ <box w="2500"/>
+ <penalty w="10000" p="900"/>
+ <box w="12500"/>
<penalty w="0"/>
+ <box w="7500"/>
+ <penalty w="0" p="900"/>
<box w="0"/>
<penalty w="5000"/>
- <box w="15000"/>
+ <box w="12500"/>
+ <penalty w="0"/>
+ <box w="2500"/>
+ <penalty w="0" p="900"/>
+ <box w="12500"/>
<box w="0"/> <!-- with SpaceHandlingPosition -->
<penalty w="0" p="INF"/>
<glue w="7500"/>
--- /dev/null
+<?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>
<fo>
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:svg="http://www.w3.org/2000/svg">
<fo:layout-master-set>
- <fo:simple-page-master master-name="normal" page-width="5in" page-height="5in">
+ <fo:simple-page-master master-name="normal" page-width="5in" page-height="5in" margin="20pt">
<fo:region-body/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="normal" white-space-collapse="true">
<fo:flow flow-name="xsl-region-body">
<fo:block>before the table</fo:block>
- <fo:table table-layout="fixed" width="100%" break-before="odd-page" break-after="odd-page">
- <fo:table-column/>
- <fo:table-column/>
+ <fo:table table-layout="fixed" width="100%" border-collapse="separate" border="4pt solid black"
+ break-before="odd-page" break-after="odd-page">
+ <fo:table-column number-columns-repeated="2" column-width="proportional-column-width(1)"/>
<fo:table-body>
<fo:table-row>
- <fo:table-cell background-color="orange">
- <fo:block>cell3</fo:block>
+ <fo:table-cell border="2pt solid blue" background-color="orange">
+ <fo:block>cell1</fo:block>
</fo:table-cell>
- <fo:table-cell>
- <fo:block>cell4</fo:block>
+ <fo:table-cell border="2pt solid red">
+ <fo:block>cell2</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo>
<checks>
<eval expected="5" xpath="count(//pageViewport)"/>
+ <!-- table -->
+ <eval expected="18400" xpath="//pageViewport[@nr=3]//flow/block[1]/@bpd"/>
+ <!--
+ <eval expected="26400" xpath="//pageViewport[@nr=3]//flow/block[1]/@bpda"/>
+ <eval expected="(solid,#000000,4000)" xpath="//pageViewport[@nr=3]//flow/block[1]/@border-before"/>
+ <eval expected="(solid,#000000,4000)" xpath="//pageViewport[@nr=3]//flow/block[1]/@border-after"/>
+ -->
+ <!-- cell 1 -->
+ <eval expected="14400" xpath="//pageViewport[@nr=3]//flow/block[1]/block[1]/@bpd"/>
+ <eval expected="18400" xpath="//pageViewport[@nr=3]//flow/block[1]/block[1]/@bpda"/>
+ <eval expected="(solid,#0000ff,2000)" xpath="//pageViewport[@nr=3]//flow/block[1]/block[1]/@border-before"/>
+ <eval expected="(solid,#0000ff,2000)" xpath="//pageViewport[@nr=3]//flow/block[1]/block[1]/@border-after"/>
+ <!-- cell 2 -->
+ <eval expected="14400" xpath="//pageViewport[@nr=3]//flow/block[1]/block[2]/@bpd"/>
+ <eval expected="18400" xpath="//pageViewport[@nr=3]//flow/block[1]/block[2]/@bpda"/>
+ <eval expected="(solid,#ff0000,2000)" xpath="//pageViewport[@nr=3]//flow/block[1]/block[2]/@border-before"/>
+ <eval expected="(solid,#ff0000,2000)" xpath="//pageViewport[@nr=3]//flow/block[1]/block[2]/@border-after"/>
</checks>
</testcase>
</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>
<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>