From 48a9185a60b9374fe0f132fe83d758527ec01788 Mon Sep 17 00:00:00 2001 From: Vincent Hennebert Date: Fri, 8 Feb 2008 12:11:04 +0000 Subject: [PATCH] Removed the 900 penalty mechanism which anyway almost always produced visually bad results. Now the first step for a row is computed so that each cell starting on it can contribute some content. Used a similar mechanism to replace backtracking: the current row is now allowed to grow as long as there is not enough space on the current page to make the next row fit. The next row is "delayed", so this mechanism is called "row-delaying" git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@619854 13f79535-47bb-0310-9956-ffa450edef68 --- .../fop/layoutmgr/table/ActiveCell.java | 310 +++++++---- .../apache/fop/layoutmgr/table/CellPart.java | 12 +- .../fop/layoutmgr/table/RowPainter.java | 15 +- .../table/TableContentLayoutManager.java | 4 +- .../layoutmgr/table/TableContentPosition.java | 25 +- .../fop/layoutmgr/table/TableStepper.java | 420 +++++++++----- .../standard-testcases/table-body_basic_2.xml | 4 - ..._border-collapse_collapse_conditionals.xml | 6 +- .../table_border-collapse_collapse_omitHF.xml | 6 +- ...der-collapse_separate_border-spacing_2.xml | 40 +- .../table_border_padding_2.xml | 12 +- .../standard-testcases/table_bug36403.xml | 17 +- .../standard-testcases/table_bug37270.xml | 4 +- .../standard-testcases/table_empty-cells.xml | 12 +- .../standard-testcases/table_row-delay.xml | 437 +++++++++++++++ .../table_row-delay_fixed-row-height.xml | 161 ++++++ .../table_row-delay_header-footer.xml | 525 ++++++++++++++++++ .../table_space-before_space-after_1.xml | 9 +- 18 files changed, 1675 insertions(+), 344 deletions(-) create mode 100644 test/layoutengine/standard-testcases/table_row-delay.xml create mode 100644 test/layoutengine/standard-testcases/table_row-delay_fixed-row-height.xml create mode 100644 test/layoutengine/standard-testcases/table_row-delay_header-footer.xml diff --git a/src/java/org/apache/fop/layoutmgr/table/ActiveCell.java b/src/java/org/apache/fop/layoutmgr/table/ActiveCell.java index 4321c32b8..671204dfe 100644 --- a/src/java/org/apache/fop/layoutmgr/table/ActiveCell.java +++ b/src/java/org/apache/fop/layoutmgr/table/ActiveCell.java @@ -22,6 +22,8 @@ package org.apache.fop.layoutmgr.table; import java.util.List; import java.util.ListIterator; +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; @@ -36,6 +38,9 @@ import org.apache.fop.layoutmgr.KnuthPenalty; * A cell playing in the construction of steps for a row-group. */ class ActiveCell { + + private static Log log = LogFactory.getLog(ActiveCell.class); + private PrimaryGridUnit pgu; /** Knuth elements for this active cell. */ private List elementList; @@ -45,29 +50,36 @@ class ActiveCell { private int endRowIndex; /** 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 previousRowsLength; /** Total length of this cell's content plus the lengths of the previous rows. */ private int totalLength; /** Length of the Knuth elements already included in the steps. */ private int includedLength; - 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 int bpBeforeNormal; + private int bpBeforeLeading; + private int bpAfterNormal; + private int bpAfterTrailing; + + /** True if the next CellPart that will be created will be the last one for this cell. */ + private boolean lastCellPart; + private boolean keepWithNextSignal; private int spanIndex = 0; - private CellPart lastCellPart; private Step previousStep; private Step nextStep; + /** + * The step following nextStep. Computing it early allows to calculate + * {@link Step#condBeforeContentLength}, thus to easily determine the remaining + * length. That also helps for {@link #increaseCurrentStep(int)}. + */ + private Step afterNextStep; /** * Auxiliary class to store all the informations related to a breaking step. @@ -84,16 +96,13 @@ class ActiveCell { /** 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. + * Length of the optional content at the beginning of the step. That is, content + * that will not appear if this step starts a new page. */ - private int nextCondBeforeContentLength; + private int condBeforeContentLength; 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; } @@ -107,7 +116,12 @@ class ActiveCell { this.contentLength = other.contentLength; this.totalLength = other.totalLength; this.penaltyLength = other.penaltyLength; - this.nextCondBeforeContentLength = other.nextCondBeforeContentLength; + this.condBeforeContentLength = other.condBeforeContentLength; + } + + /** {@inheritDoc} */ + public String toString() { + return "Step: start=" + start + " end=" + end + " length=" + totalLength; } } @@ -116,16 +130,17 @@ class ActiveCell { 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); - + bpBeforeNormal = paddingBeforeNormal + + pgu.getBeforeBorderWidth(0, ConditionalBorder.NORMAL); + bpBeforeLeading = paddingBeforeLeading + + pgu.getBeforeBorderWidth(0, ConditionalBorder.REST); + bpAfterNormal = paddingAfterNormal + pgu.getAfterBorderWidth(ConditionalBorder.NORMAL); + bpAfterTrailing = paddingAfterTrailing + pgu.getAfterBorderWidth(0, ConditionalBorder.REST); boolean makeBoxForWholeRow = false; if (row.getExplicitHeight().min > 0) { boolean contentsSmaller = ElementListUtils.removeLegalBreaks( @@ -142,23 +157,29 @@ class ActiveCell { elementList = new java.util.ArrayList(1); int height = row.getHeight().opt; height -= 2 * tableLM.getHalfBorderSeparationBPD(); - height -= borderBeforeNormal + borderAfterNormal; // TODO conditionals - height -= paddingBeforeNormal + paddingAfterNormal; + height -= bpBeforeNormal + bpAfterNormal; elementList.add(new KnuthBoxCellWithBPD(height)); } else { elementList = pgu.getElements(); } knuthIter = elementList.listIterator(); includedLength = -1; // Avoid troubles with cells having content of zero length - this.previousRowsLength = previousRowsLength; totalLength = previousRowsLength + ElementListUtils.calcContentLength(elementList); endRowIndex = rowIndex + pgu.getCell().getNumberRowsSpanned() - 1; keepWithNextSignal = false; remainingLength = totalLength - previousRowsLength; - nextStep = new Step(previousRowsLength); - previousStep = new Step(nextStep); - goToNextLegalBreak(); + afterNextStep = new Step(previousRowsLength); + previousStep = new Step(afterNextStep); + gotoNextLegalBreak(); + nextStep = new Step(afterNextStep); + if (afterNextStep.end < elementList.size() - 1) { + gotoNextLegalBreak(); + } + } + + PrimaryGridUnit getPrimaryGridUnit() { + return pgu; } /** @@ -175,31 +196,30 @@ class ActiveCell { * Returns the length of this cell's content not yet included in the steps, plus the * cell's borders and paddings if applicable. * - * @param activeRowIndex index of the row currently considered - * @return the remaining length, or zero if the cell doesn't end on the given row. + * @return the remaining length, zero if the cell is finished */ - int getRemainingHeight(int activeRowIndex) { - if (!endsOnRow(activeRowIndex)) { - return 0; - } else if (includedLength == totalLength) { + int getRemainingLength() { + if (includedInLastStep() && (nextStep.end == elementList.size() - 1)) { + // The cell is finished return 0; } else { - return borderBeforeLeading + paddingBeforeLeading + remainingLength - + paddingAfterNormal + borderAfterNormal; + return bpBeforeLeading + remainingLength + bpAfterNormal; } } - private void goToNextLegalBreak() { - nextStep.penaltyLength = 0; + private void gotoNextLegalBreak() { + afterNextStep.penaltyLength = 0; + afterNextStep.condBeforeContentLength = 0; boolean breakFound = false; boolean prevIsBox = false; + boolean boxFound = false; while (!breakFound && knuthIter.hasNext()) { KnuthElement el = (KnuthElement) knuthIter.next(); if (el.isPenalty()) { prevIsBox = false; if (el.getP() < KnuthElement.INFINITE) { // First legal break point - nextStep.penaltyLength = el.getW(); + afterNextStep.penaltyLength = el.getW(); breakFound = true; } } else if (el.isGlue()) { @@ -207,24 +227,83 @@ class ActiveCell { // Second legal break point breakFound = true; } else { - nextStep.contentLength += el.getW(); + afterNextStep.contentLength += el.getW(); + if (!boxFound) { + afterNextStep.condBeforeContentLength += el.getW(); + } } prevIsBox = false; } else { prevIsBox = true; - nextStep.contentLength += el.getW(); + boxFound = true; + afterNextStep.contentLength += el.getW(); } } - 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; + afterNextStep.end = knuthIter.nextIndex() - 1; + afterNextStep.totalLength = bpBeforeNormal + + afterNextStep.contentLength + afterNextStep.penaltyLength + + bpAfterTrailing; + } + + /** + * Returns the minimal step that is needed for this cell to contribute some content. + * + * @return the step for this cell's first legal break + */ + int getFirstStep() { + log.debug(this + ": min first step = " + nextStep.totalLength); + return nextStep.totalLength; + } + + /** + * Returns the last step for this cell. + * + * @return the step including all of the cell's content plus the normal borders and paddings + */ + int getLastStep() { + assert nextStep.end == elementList.size() - 1; + assert nextStep.contentLength == totalLength && nextStep.penaltyLength == 0; + int lastStep = bpBeforeNormal + totalLength + bpAfterNormal; + log.debug(this + ": last step = " + lastStep); + return lastStep; + } + + /** + * Increases the next step up to the given limit. + * + * @param limit the length up to which the next step is allowed to increase + * @see #signalRowFirstStep(int) + * @see #signalRowLastStep(int) + */ + private void increaseCurrentStep(int limit) { + while (afterNextStep.totalLength <= limit) { + nextStep.set(afterNextStep); + if (afterNextStep.end >= elementList.size() - 1) { + break; + } + gotoNextLegalBreak(); + } + } + + /** + * Gets the selected first step for the current row. If this cell's first step is + * smaller, then it may be able to add some more of its content, since there will be + * no break before the given step anyway. + * + * @param firstStep the current row's first step + */ + void signalRowFirstStep(int firstStep) { + increaseCurrentStep(firstStep); + if (log.isTraceEnabled()) { + log.trace(this + ": first step increased to " + nextStep.totalLength); + } + } + + /** See {@link #signalRowFirstStep(int)}. */ + void signalRowLastStep(int lastStep) { + increaseCurrentStep(lastStep); + if (log.isTraceEnabled()) { + log.trace(this + ": next step increased to " + nextStep.totalLength); } } @@ -236,11 +315,15 @@ class ActiveCell { int getNextStep() { if (includedInLastStep()) { previousStep.set(nextStep); - nextStep.start = nextStep.end + 1; - if (!knuthIter.hasNext()) { + if (nextStep.end >= elementList.size() - 1) { + nextStep.start = elementList.size(); return -1; } else { - goToNextLegalBreak(); + nextStep.set(afterNextStep); + nextStep.start = previousStep.end + 1; + if (afterNextStep.end < elementList.size() - 1) { + gotoNextLegalBreak(); + } } } return nextStep.totalLength; @@ -255,52 +338,49 @@ class ActiveCell { * its own step may be included or not. * * @param minStep length of the chosen next step - * @return */ - boolean signalMinStep(int minStep) { + void signalNextStep(int minStep) { if (nextStep.totalLength <= minStep) { includedLength = nextStep.contentLength; - computeRemainingLength(); - return false; - } else { - return borderBeforeNormal + paddingBeforeNormal + previousRowsLength - + paddingAfterTrailing + borderAfterTrailing > minStep; + remainingLength = totalLength - includedLength - afterNextStep.condBeforeContentLength; } } - 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); - } + /** + * Receives indication that the next row is about to start, and that (collapse) + * borders must be updated accordingly. + */ + void nextRowStarts() { + spanIndex++; + // Subtract the old value of bpAfterTrailing... + nextStep.totalLength -= bpAfterTrailing; + afterNextStep.totalLength -= bpAfterTrailing; + + bpAfterTrailing = paddingAfterTrailing + + pgu.getAfterBorderWidth(spanIndex, ConditionalBorder.REST); + + // ... and add the new one + nextStep.totalLength += bpAfterTrailing; + afterNextStep.totalLength += bpAfterTrailing; + // TODO if the new after border is greater than the previous one the next step may + // increase further than the row's first step, which can lead to wrong output in + // some cases } /** - * Computes the length of the cell's content after the current legal break. Discards - * every glue or penalty following the break if needed. The cell's borders and - * paddings are not considered here. + * Receives indication that the current row is ending, and that (collapse) borders + * must be updated accordingly. + * + * @param rowIndex the index of the ending row */ - private void computeRemainingLength() { - 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 - while (knuthIter.nextIndex() > oldIndex) { - knuthIter.previous(); + void endRow(int rowIndex) { + if (endsOnRow(rowIndex)) { + bpAfterTrailing = paddingAfterNormal + + pgu.getAfterBorderWidth(ConditionalBorder.LEADING_TRAILING); + lastCellPart = true; + } else { + bpBeforeLeading = paddingBeforeLeading + + pgu.getBeforeBorderWidth(spanIndex + 1, ConditionalBorder.REST); } } @@ -316,21 +396,14 @@ class ActiveCell { } /** - * Returns true if this cell has already started to contribute some content to the steps. + * Returns true if this cell would be finished after the given step. That is, it would + * be included in the step and the end of its content would be reached. * - * @return true if this cell's first step is inferior or equal to the current one + * @param step the next step + * @return true if this cell finishes at the given step */ - boolean hasStarted() { - return includedLength >= 0; - } - - /** - * Returns true if this cell has contributed all of its content to the steps. - * - * @return true if the end of this cell is reached - */ - boolean isFinished() { - return includedInLastStep() && (nextStep.end == elementList.size() - 1); + boolean finishes(int step) { + return nextStep.totalLength <= step && (nextStep.end == elementList.size() - 1); } /** @@ -348,39 +421,31 @@ class ActiveCell { keepWithNextSignal = true; } } - 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; + bpBeforeFirst = bpBeforeLeading; } - bpAfterNormal = 0; - bpAfterLast = paddingAfterTrailing + borderAfterTrailing; - int length = nextStep.contentLength - previousStep.contentLength - - previousStep.nextCondBeforeContentLength; + int length = nextStep.contentLength - nextStep.condBeforeContentLength + - previousStep.contentLength; if (!includedInLastStep() || nextStep.start == elementList.size()) { - lastCellPart = new CellPart(pgu, nextStep.start, previousStep.end, + return new CellPart(pgu, nextStep.start, previousStep.end, lastCellPart, 0, 0, previousStep.penaltyLength, - bpBeforeNormal, bpBeforeFirst, bpAfterNormal, bpAfterLast); + bpBeforeNormal, bpBeforeFirst, bpAfterNormal, bpAfterTrailing); } else if (nextStep.start == 0 && nextStep.end == 0 && elementList.size() == 1 && elementList.get(0) instanceof KnuthBoxCellWithBPD) { //Special case: Cell with fixed BPD - lastCellPart = new CellPart(pgu, 0, pgu.getElements().size() - 1, - previousStep.nextCondBeforeContentLength, length, nextStep.penaltyLength, - bpBeforeNormal, bpBeforeFirst, bpAfterNormal, bpAfterLast); + return new CellPart(pgu, 0, pgu.getElements().size() - 1, lastCellPart, + nextStep.condBeforeContentLength, length, nextStep.penaltyLength, + bpBeforeNormal, bpBeforeFirst, bpAfterNormal, bpAfterTrailing); } else { - lastCellPart = new CellPart(pgu, nextStep.start, nextStep.end, - previousStep.nextCondBeforeContentLength, length, nextStep.penaltyLength, - bpBeforeNormal, bpBeforeFirst, bpAfterNormal, bpAfterLast); + return new CellPart(pgu, nextStep.start, nextStep.end, lastCellPart, + nextStep.condBeforeContentLength, length, nextStep.penaltyLength, + bpBeforeNormal, bpBeforeFirst, bpAfterNormal, bpAfterTrailing); } - return lastCellPart; } boolean isLastForcedBreak() { @@ -395,6 +460,13 @@ class ActiveCell { return keepWithNextSignal; } + + /** {@inheritDoc} */ + public String toString() { + return "Cell " + (pgu.getRowIndex() + 1) + "." + (pgu.getColIndex() + 1); + } + + /** * Marker class denoting table cells fitting in just one box (no legal break inside). */ diff --git a/src/java/org/apache/fop/layoutmgr/table/CellPart.java b/src/java/org/apache/fop/layoutmgr/table/CellPart.java index f6c292f97..2adb543a9 100644 --- a/src/java/org/apache/fop/layoutmgr/table/CellPart.java +++ b/src/java/org/apache/fop/layoutmgr/table/CellPart.java @@ -49,6 +49,7 @@ class CellPart { * @param pgu Primary grid unit * @param start starting element * @param end ending element + * @param last true if this cell part is the last one for the cell * @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 @@ -58,16 +59,17 @@ class CellPart { * @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 + * @param bpAfterLast 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, boolean last, int condBeforeContentLength, int length, int condAfterContentLength, int bpBeforeNormal, int bpBeforeFirst, int bpAfterNormal, int bpAfterLast) { this.pgu = pgu; this.start = start; this.end = end; + this.isLast = last; this.condBeforeContentLength = condBeforeContentLength; this.length = length; this.condAfterContentLength = condAfterContentLength; @@ -87,12 +89,6 @@ class CellPart { return isLast; } - void setLast(int bpNormal, int bpLast) { - isLast = true; - bpAfterNormal = bpNormal; - bpAfterLast = bpLast; - } - int getBorderPaddingBefore(boolean firstOnPage) { if (firstOnPage) { return bpBeforeFirst; diff --git a/src/java/org/apache/fop/layoutmgr/table/RowPainter.java b/src/java/org/apache/fop/layoutmgr/table/RowPainter.java index 54ac4867a..26880faea 100644 --- a/src/java/org/apache/fop/layoutmgr/table/RowPainter.java +++ b/src/java/org/apache/fop/layoutmgr/table/RowPainter.java @@ -96,14 +96,19 @@ class RowPainter { * @param tcpos a position representing the row fragment */ void handleTableContentPosition(TableContentPosition tcpos) { - if (tcpos.row != currentRow && currentRow != null) { - addAreasAndFlushRow(false, false); - } if (log.isDebugEnabled()) { log.debug("===handleTableContentPosition(" + tcpos); } - rowFO = tcpos.row.getTableRow(); - currentRow = tcpos.row; + if (currentRow == null) { + currentRow = tcpos.getNewPageRow(); + } else { + EffRow row = tcpos.getRow(); + if (row.getIndex() > currentRow.getIndex()) { + addAreasAndFlushRow(false, false); + currentRow = row; + } + } + rowFO = currentRow.getTableRow(); if (firstRowIndex < 0) { firstRowIndex = currentRow.getIndex(); if (firstRowOnPageIndex < 0) { diff --git a/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java b/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java index 1c748a5cf..baf1bd369 100644 --- a/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java @@ -403,12 +403,12 @@ public class TableContentLayoutManager implements PercentBaseContext { body = part.pgu.getBody(); } if (tcpos.getFlag(TableContentPosition.FIRST_IN_ROWGROUP) - && tcpos.row.getFlag(EffRow.FIRST_IN_PART)) { + && tcpos.getRow().getFlag(EffRow.FIRST_IN_PART)) { firstPos = true; } if (tcpos.getFlag(TableContentPosition.LAST_IN_ROWGROUP) - && tcpos.row.getFlag(EffRow.LAST_IN_PART)) { + && tcpos.getRow().getFlag(EffRow.LAST_IN_PART)) { log.trace("LAST_IN_ROWGROUP + LAST_IN_PART"); handleMarkersAndPositions(lst, body, firstPos, true, painter); //reset diff --git a/src/java/org/apache/fop/layoutmgr/table/TableContentPosition.java b/src/java/org/apache/fop/layoutmgr/table/TableContentPosition.java index 68f55d88f..e702c58a9 100644 --- a/src/java/org/apache/fop/layoutmgr/table/TableContentPosition.java +++ b/src/java/org/apache/fop/layoutmgr/table/TableContentPosition.java @@ -39,10 +39,12 @@ class TableContentPosition extends Position { /** the list of CellParts making up this position */ protected List cellParts; /** effective row this position belongs to */ - protected EffRow row; + private EffRow row; /** flags for the position */ protected int flags; + private EffRow newPageRow; + /** * Creates a new TableContentPosition. * @param lm applicable layout manager @@ -54,6 +56,27 @@ class TableContentPosition extends Position { super(lm); this.cellParts = cellParts; this.row = row; + this.newPageRow = row; + } + + /** + * Sets the row corresponding to this position if it starts a new page. In which case, + * if the delay mechanism is on, this is the delayed row that starts the page, and not + * the current row being extended. + * + * @param newPageRow the row that will start the page if this position is the first + * one on that page + */ + void setNewPageRow(EffRow newPageRow) { + this.newPageRow = newPageRow; + } + + EffRow getNewPageRow() { + return newPageRow; + } + + EffRow getRow() { + return row; } /** diff --git a/src/java/org/apache/fop/layoutmgr/table/TableStepper.java b/src/java/org/apache/fop/layoutmgr/table/TableStepper.java index 3e038604a..aa35d0aee 100644 --- a/src/java/org/apache/fop/layoutmgr/table/TableStepper.java +++ b/src/java/org/apache/fop/layoutmgr/table/TableStepper.java @@ -52,51 +52,62 @@ public class TableStepper { /** Number of columns in the row group. */ private int columnCount; private int totalHeight; - private int previousRowsLength = 0; + private int previousRowsLength; private int activeRowIndex; - private boolean rowBacktrackForLastStep; - private boolean skippedStep; + private boolean rowFinished; + + /** Cells spanning the current row. */ private List activeCells = new LinkedList(); + /** Cells that will start the next row. */ + private List nextActiveCells = new LinkedList(); + /** - * Main constructor - * @param tclm The parent TableContentLayoutManager + * True if the next row is being delayed, that is, if cells spanning the current and + * the next row have steps smaller than the next row's first step. In this case the + * next row may be extended to offer additional break possibilities. */ - public TableStepper(TableContentLayoutManager tclm) { - this.tclm = tclm; - this.columnCount = tclm.getTableLM().getTable().getNumberOfColumns(); - } + private boolean delayingNextRow; /** - * Initializes the fields of this instance to handle a new row group. + * The first step for a row. This is the minimal step necessary to include some + * content from all the cells starting the row. + */ + private int rowFirstStep; + + /** + * Flag used to produce an infinite penalty if the height of the current row is + * smaller than the first step for that row (may happen with row-spanning cells). * - * @param rowGroup the new row group to handle + * @see #considerRowLastStep(int) */ - private void setup(EffRow[] rowGroup) { - this.rowGroup = rowGroup; - this.activeRowIndex = 0; - this.previousRowsLength = 0; - } + private boolean rowHeightSmallerThanFirstStep; + /** - * Returns the row currently being processed. - * - * @return the row currently being processed + * Main constructor + * @param tclm The parent TableContentLayoutManager */ - private EffRow getActiveRow() { - return rowGroup[activeRowIndex]; + public TableStepper(TableContentLayoutManager tclm) { + this.tclm = tclm; + this.columnCount = tclm.getTableLM().getTable().getNumberOfColumns(); } /** - * Returns the grid unit at the given column number on the active row. - * - * @param column column number of the grid unit to get - * @return the corresponding grid unit (may be null) - * {@inheritDoc} + * Initializes the fields of this instance to handle a new row group. + * + * @param rows the new row group to handle */ - private GridUnit getActiveGridUnit(int column) { - return getActiveRow().safelyGetGridUnit(column); + private void setup(EffRow[] rows) { + rowGroup = rows; + previousRowsLength = 0; + activeRowIndex = 0; + activeCells.clear(); + nextActiveCells.clear(); + delayingNextRow = false; + rowFirstStep = 0; + rowHeightSmallerThanFirstStep = false; } private void calcTotalHeight() { @@ -111,30 +122,34 @@ public class TableStepper { private int getMaxRemainingHeight() { int maxW = 0; - if (!rowBacktrackForLastStep) { - for (Iterator iter = activeCells.iterator(); iter.hasNext();) { - maxW = Math.max(maxW, - ((ActiveCell) iter.next()).getRemainingHeight(activeRowIndex)); + for (Iterator iter = activeCells.iterator(); iter.hasNext();) { + ActiveCell activeCell = (ActiveCell) iter.next(); + int remain = activeCell.getRemainingLength(); + PrimaryGridUnit pgu = activeCell.getPrimaryGridUnit(); + for (int i = activeRowIndex + 1; i < pgu.getRowIndex() - rowGroup[0].getIndex() + + pgu.getCell().getNumberRowsSpanned(); i++) { + remain -= rowGroup[i].getHeight().opt; } + maxW = Math.max(maxW, remain); } - for (int i = activeRowIndex + (rowBacktrackForLastStep ? 0 : 1); i < rowGroup.length; i++) { + for (int i = activeRowIndex + 1; i < rowGroup.length; i++) { maxW += rowGroup[i].getHeight().opt; } - log.debug("maxRemainingHeight=" + maxW); return maxW; } /** - * Initializes the informations relative to the Knuth elements, to handle a new row in - * the current row group. + * Creates ActiveCell instances for cells starting on the row at the given index. + * + * @param activeCellList the list that will hold the active cells + * @param rowIndex the index of the row from which cells must be activated */ - private void initializeElementLists() { - log.trace("Entering initializeElementLists()"); - EffRow row = getActiveRow(); + private void activateCells(List activeCellList, int rowIndex) { + EffRow row = rowGroup[rowIndex]; 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, + GridUnit gu = row.getGridUnit(i); + if (!gu.isEmpty() && gu.isPrimary()) { + activeCellList.add(new ActiveCell((PrimaryGridUnit) gu, row, rowIndex, previousRowsLength, getTableLM())); } } @@ -143,61 +158,68 @@ public class TableStepper { /** * Creates the combined element list for a row group. * @param context Active LayoutContext - * @param rowGroup the row group + * @param rows the row group * @param bodyType Indicates what type of body is processed (body, header or footer) * @return the combined element list */ - public LinkedList getCombinedKnuthElementsForRowGroup(LayoutContext context, EffRow[] rowGroup, + public LinkedList getCombinedKnuthElementsForRowGroup(LayoutContext context, EffRow[] rows, int bodyType) { - setup(rowGroup); - initializeElementLists(); + setup(rows); + activateCells(activeCells, 0); calcTotalHeight(); boolean signalKeepWithNext = false; - int laststep = 0; - int step; int cumulateLength = 0; // Length of the content accumulated before the break TableContentPosition lastTCPos = null; LinkedList returnList = new LinkedList(); - while ((step = getNextStep()) >= 0) { - int normalRow = activeRowIndex; - int increase = step - laststep; - int penaltyOrGlueLen = step + getMaxRemainingHeight() - totalHeight; - int boxLen = step - cumulateLength - Math.max(0, penaltyOrGlueLen)/* the penalty, if any */; + int laststep = 0; + int step = getFirstStep(); + do { + int maxRemainingHeight = getMaxRemainingHeight(); + int penaltyOrGlueLen = step + maxRemainingHeight - totalHeight; + int boxLen = step - cumulateLength - Math.max(0, penaltyOrGlueLen)/* penalty, if any */; cumulateLength += boxLen + Math.max(0, -penaltyOrGlueLen)/* the glue, if any */; + if (log.isDebugEnabled()) { + log.debug("Next step: " + step + " (+" + (step - laststep) + ")"); + log.debug(" max remaining height: " + maxRemainingHeight); + if (penaltyOrGlueLen >= 0) { + log.debug(" box = " + boxLen + " penalty = " + penaltyOrGlueLen); + } else { + log.debug(" box = " + boxLen + " glue = " + (-penaltyOrGlueLen)); + } + } + boolean forcedBreak = false; int breakClass = -1; //Put all involved grid units into a list List cellParts = new java.util.ArrayList(columnCount); for (Iterator iter = activeCells.iterator(); iter.hasNext();) { ActiveCell activeCell = (ActiveCell) iter.next(); - CellPart part = activeCell.createCellPart(); - cellParts.add(part); if (activeCell.contributesContent()) { forcedBreak = activeCell.isLastForcedBreak(); if (forcedBreak) { breakClass = activeCell.getLastBreakClass(); } } + CellPart part = activeCell.createCellPart(); + cellParts.add(part); if (returnList.size() == 0 && part.isFirstPart() && part.mustKeepWithPrevious()) { context.setFlags(LayoutContext.KEEP_WITH_PREVIOUS_PENDING); } } - //log.debug(">>> guPARTS: " + cellParts); //Create elements for step TableContentPosition tcpos = new TableContentPosition(getTableLM(), - cellParts, rowGroup[normalRow]); + cellParts, rowGroup[activeRowIndex]); + if (delayingNextRow) { + tcpos.setNewPageRow(rowGroup[activeRowIndex + 1]); + } if (returnList.size() == 0) { tcpos.setFlag(TableContentPosition.FIRST_IN_ROWGROUP, true); } lastTCPos = tcpos; - if (log.isDebugEnabled()) { - log.debug(" - backtrack=" + rowBacktrackForLastStep - + " - row=" + activeRowIndex + " - " + tcpos); - } returnList.add(new KnuthBox(boxLen, tcpos, false)); int effPenaltyLen = Math.max(0, penaltyOrGlueLen); @@ -214,48 +236,29 @@ public class TableStepper { } int p = 0; - boolean allCellsHaveContributed = true; signalKeepWithNext = false; for (Iterator iter = activeCells.iterator(); iter.hasNext();) { ActiveCell activeCell = (ActiveCell) iter.next(); - allCellsHaveContributed &= activeCell.hasStarted(); signalKeepWithNext |= activeCell.keepWithNextSignal(); } - if (!allCellsHaveContributed) { - //Not all cells have contributed to a newly started row. The penalty here is - //used to avoid breaks resulting in badly broken tables. - //See also: http://marc.theaimsgroup.com/?t=112248999600005&r=1&w=2 - p = 900; //KnuthPenalty.INFINITE; //TODO Arbitrary value. Please refine. - } if (signalKeepWithNext || getTableLM().mustKeepTogether()) { p = KnuthPenalty.INFINITE; } - if (skippedStep) { - p = KnuthPenalty.INFINITE; - //Need to avoid breaking because borders and/or paddding from other columns would - //not fit in the available space (see getNextStep()) - } if (forcedBreak) { - if (skippedStep) { - log.error("This is a conflict situation. The output may be wrong." - + " Please send your FO file to fop-dev@xmlgraphics.apache.org!"); - } p = -KnuthPenalty.INFINITE; //Overrides any keeps (see 4.8 in XSL 1.0) } + if (rowHeightSmallerThanFirstStep) { + rowHeightSmallerThanFirstStep = false; + p = KnuthPenalty.INFINITE; + } returnList.add(new BreakElement(penaltyPos, effPenaltyLen, p, breakClass, context)); if (penaltyOrGlueLen < 0) { returnList.add(new KnuthGlue(-penaltyOrGlueLen, 0, 0, new Position(null), true)); } - if (log.isDebugEnabled()) { - log.debug("step=" + step + " (+" + increase + ")" - + " box=" + boxLen - + " penalty=" + penaltyOrGlueLen - + " effPenalty=" + effPenaltyLen); - } - laststep = step; - } + step = getNextStep(); + } while (step >= 0); if (signalKeepWithNext) { //Last step signalled a keep-with-next. Since the last penalty will be removed, //we have to signal the still pending last keep-with-next using the LayoutContext. @@ -268,23 +271,77 @@ public class TableStepper { } /** - * Finds the smallest increment leading to the next legal break inside the row-group. + * Returns the first step for the current row group. + * + * @return the first step for the current row group + */ + private int getFirstStep() { + computeRowFirstStep(activeCells); + signalRowFirstStep(); + int minStep = considerRowLastStep(rowFirstStep); + signalNextStep(minStep); + return minStep; + } + + /** + * Returns the next break possibility. * - * @return the size of the increment, -1 if no next step is available (end of row-group reached) + * @return the next step */ private int getNextStep() { - log.trace("Entering getNextStep"); - //Check for forced break conditions - /* - if (isBreakCondition()) { - return -1; - }*/ + if (rowFinished) { + if (activeRowIndex == rowGroup.length - 1) { + // The row group is finished, no next step + return -1; + } + rowFinished = false; + removeCellsEndingOnCurrentRow(); + log.trace("Delaying next row"); + delayingNextRow = true; + } + if (delayingNextRow) { + int minStep = computeMinStep(); + if (minStep < 0 || minStep >= rowFirstStep + || minStep > rowGroup[activeRowIndex].getExplicitHeight().max) { + if (log.isTraceEnabled()) { + log.trace("Step = " + minStep); + } + delayingNextRow = false; + minStep = rowFirstStep; + switchToNextRow(); + signalRowFirstStep(); + minStep = considerRowLastStep(minStep); + } + signalNextStep(minStep); + return minStep; + } else { + int minStep = computeMinStep(); + minStep = considerRowLastStep(minStep); + signalNextStep(minStep); + return minStep; + } + } - //set starting points - goToNextRowIfCurrentFinished(); + /** + * Computes the minimal necessary step to make the next row fit. That is, so such as + * cell on the next row can contribute some content. + * + * @param cells the cells occupying the next row (may include cells starting on + * previous rows and spanning over this one) + */ + private void computeRowFirstStep(List cells) { + for (Iterator iter = cells.iterator(); iter.hasNext();) { + ActiveCell activeCell = (ActiveCell) iter.next(); + rowFirstStep = Math.max(rowFirstStep, activeCell.getFirstStep()); + } + } - //Get next possible sequence for each cell - //Determine smallest possible step + /** + * Computes the next minimal step. + * + * @return the minimal step from the active cells, < 0 if there is no such step + */ + private int computeMinStep() { int minStep = Integer.MAX_VALUE; boolean stepFound = false; for (Iterator iter = activeCells.iterator(); iter.hasNext();) { @@ -295,78 +352,149 @@ public class TableStepper { minStep = Math.min(minStep, nextStep); } } - if (!stepFound) { + if (stepFound) { + return minStep; + } else { return -1; } + } + /** + * Signals the first step to the active cells, to allow them to add more content to + * the step if possible. + * + * @see ActiveCell#signalRowFirstStep(int) + */ + private void signalRowFirstStep() { + for (Iterator iter = activeCells.iterator(); iter.hasNext();) { + ActiveCell activeCell = (ActiveCell) iter.next(); + activeCell.signalRowFirstStep(rowFirstStep); + } + } - //Reset bigger-than-minimum sequences - //See http://people.apache.org/~jeremias/fop/NextStepAlgoNotes.pdf - rowBacktrackForLastStep = false; - skippedStep = false; + /** + * Signals the next selected step to the active cells. + * + * @param step the next step + */ + private void signalNextStep(int step) { for (Iterator iter = activeCells.iterator(); iter.hasNext();) { ActiveCell activeCell = (ActiveCell) iter.next(); - if (activeCell.signalMinStep(minStep)) { - if (activeRowIndex == 0) { - log.debug(" First row. Skip this step."); - skippedStep = true; - } else { - log.debug(" row-span situation: backtracking to last row"); - //Stay on the previous row for another step because borders and padding on - //columns may make their contribution to the step bigger than the addition - //of the next element for this step would make the step to grow. - rowBacktrackForLastStep = true; + activeCell.signalNextStep(step); + } + } + + /** + * Determines if the given step will finish the current row, and if so switch to the + * last step for this row. + *

If the row is finished then the after borders for the cell may change (their + * conditionalities no longer apply for the cells ending on the current row). Thus the + * final step may grow with respect to the given one.

+ *

In more rare occasions, the given step may correspond to the first step of a + * row-spanning cell, and may be greater than the height of the current row (consider, + * for example, an unbreakable cell spanning three rows). In such a case the returned + * step will correspond to the row height and a flag will be set to produce an + * infinite penalty for this step. This will prevent the breaking algorithm from + * choosing this break, but still allow to create the appropriate TableContentPosition + * for the cells ending on the current row.

+ * + * @param step the next step + * @return the updated step if any + */ + private int considerRowLastStep(int step) { + rowFinished = true; + for (Iterator iter = activeCells.iterator(); iter.hasNext();) { + ActiveCell activeCell = (ActiveCell) iter.next(); + if (activeCell.endsOnRow(activeRowIndex)) { + rowFinished &= activeCell.finishes(step); + } + } + if (rowFinished) { + if (log.isTraceEnabled()) { + log.trace("Step = " + step); + log.trace("Row finished, computing last step"); + } + int maxStep = 0; + for (Iterator iter = activeCells.iterator(); iter.hasNext();) { + ActiveCell activeCell = (ActiveCell) iter.next(); + if (activeCell.endsOnRow(activeRowIndex)) { + maxStep = Math.max(maxStep, activeCell.getLastStep()); + } + } + if (log.isTraceEnabled()) { + log.trace("Max step: " + maxStep); + } + for (Iterator iter = activeCells.iterator(); iter.hasNext();) { + ActiveCell activeCell = (ActiveCell) iter.next(); + activeCell.endRow(activeRowIndex); + if (!activeCell.endsOnRow(activeRowIndex)) { + activeCell.signalRowLastStep(maxStep); } } + if (maxStep < step) { + log.trace("Row height smaller than first step, produced penalty will be infinite"); + rowHeightSmallerThanFirstStep = true; + } + step = maxStep; + prepareNextRow(); } + return step; + } - return minStep; + /** + * Pre-activates the cells that will start the next row, and computes the first step + * for that row. + */ + private void prepareNextRow() { + if (activeRowIndex < rowGroup.length - 1) { + TableRow rowFO = rowGroup[activeRowIndex].getTableRow(); + if (rowFO != null && rowFO.getBreakAfter() != Constants.EN_AUTO) { + log.warn(FONode.decorateWithContextInfo( + "break-after ignored on table-row because of row spanning " + + "in progress (See XSL 1.0, 7.19.1)", rowFO)); + } + previousRowsLength += rowGroup[activeRowIndex].getHeight().opt; + activateCells(nextActiveCells, activeRowIndex + 1); + rowFO = rowGroup[activeRowIndex + 1].getTableRow(); + if (rowFO != null && rowFO.getBreakBefore() != Constants.EN_AUTO) { + log.warn(FONode.decorateWithContextInfo( + "break-before ignored on table-row because of row spanning " + + "in progress (See XSL 1.0, 7.19.2)", rowFO)); + } + if (log.isTraceEnabled()) { + log.trace("Computing first step for row " + (activeRowIndex + 2)); + } + computeRowFirstStep(nextActiveCells); + if (log.isTraceEnabled()) { + log.trace("Next first step = " + rowFirstStep); + } + } } private void removeCellsEndingOnCurrentRow() { for (Iterator iter = activeCells.iterator(); iter.hasNext();) { ActiveCell activeCell = (ActiveCell) iter.next(); - activeCell.endRow(activeRowIndex); if (activeCell.endsOnRow(activeRowIndex)) { iter.remove(); } } } - private void goToNextRowIfCurrentFinished() { - // We assume that the current grid row is finished. If this is not the case this - // boolean will be reset - boolean currentGridRowFinished = true; + /** + * Actually switches to the next row, increasing activeRowIndex and transferring to + * activeCells the cells starting on the next row. + */ + private void switchToNextRow() { + activeRowIndex++; + if (log.isTraceEnabled()) { + log.trace("Switching to row " + (activeRowIndex + 1)); + } for (Iterator iter = activeCells.iterator(); iter.hasNext();) { ActiveCell activeCell = (ActiveCell) iter.next(); - if (activeCell.endsOnRow(activeRowIndex)) { - currentGridRowFinished &= activeCell.isFinished(); - } - } - - if (currentGridRowFinished) { - removeCellsEndingOnCurrentRow(); - if (activeRowIndex < rowGroup.length - 1) { - TableRow rowFO = getActiveRow().getTableRow(); - if (rowFO != null && rowFO.getBreakAfter() != Constants.EN_AUTO) { - log.warn(FONode.decorateWithContextInfo( - "break-after ignored on table-row because of row spanning " - + "in progress (See XSL 1.0, 7.19.1)", rowFO)); - } - previousRowsLength += rowGroup[activeRowIndex].getHeight().opt; - activeRowIndex++; - if (log.isDebugEnabled()) { - log.debug("===> new row: " + activeRowIndex); - } - initializeElementLists(); - rowFO = getActiveRow().getTableRow(); - if (rowFO != null && rowFO.getBreakBefore() != Constants.EN_AUTO) { - log.warn(FONode.decorateWithContextInfo( - "break-before ignored on table-row because of row spanning " - + "in progress (See XSL 1.0, 7.19.2)", rowFO)); - } - } + activeCell.nextRowStarts(); } + activeCells.addAll(nextActiveCells); + nextActiveCells.clear(); } /** @return the table layout manager */ diff --git a/test/layoutengine/standard-testcases/table-body_basic_2.xml b/test/layoutengine/standard-testcases/table-body_basic_2.xml index dbea5e4dd..0e7b1fbd1 100644 --- a/test/layoutengine/standard-testcases/table-body_basic_2.xml +++ b/test/layoutengine/standard-testcases/table-body_basic_2.xml @@ -63,10 +63,6 @@ - - - - diff --git a/test/layoutengine/standard-testcases/table_border-collapse_collapse_conditionals.xml b/test/layoutengine/standard-testcases/table_border-collapse_collapse_conditionals.xml index a653be423..37eed9dd0 100644 --- a/test/layoutengine/standard-testcases/table_border-collapse_collapse_conditionals.xml +++ b/test/layoutengine/standard-testcases/table_border-collapse_collapse_conditionals.xml @@ -34,9 +34,9 @@ Before the table diff --git a/test/layoutengine/standard-testcases/table_border-collapse_collapse_omitHF.xml b/test/layoutengine/standard-testcases/table_border-collapse_collapse_omitHF.xml index d13b257c9..db873b4a4 100644 --- a/test/layoutengine/standard-testcases/table_border-collapse_collapse_omitHF.xml +++ b/test/layoutengine/standard-testcases/table_border-collapse_collapse_omitHF.xml @@ -34,9 +34,9 @@ Before the table diff --git a/test/layoutengine/standard-testcases/table_border-collapse_separate_border-spacing_2.xml b/test/layoutengine/standard-testcases/table_border-collapse_separate_border-spacing_2.xml index 52f0de812..b66379be3 100644 --- a/test/layoutengine/standard-testcases/table_border-collapse_separate_border-spacing_2.xml +++ b/test/layoutengine/standard-testcases/table_border-collapse_separate_border-spacing_2.xml @@ -134,19 +134,17 @@ - - - - - - - - - + - - + + + + + + + + @@ -156,19 +154,17 @@ - - - - - - - - - + - - + + + + + + + + diff --git a/test/layoutengine/standard-testcases/table_border_padding_2.xml b/test/layoutengine/standard-testcases/table_border_padding_2.xml index 0e9a9e21f..590c455f8 100644 --- a/test/layoutengine/standard-testcases/table_border_padding_2.xml +++ b/test/layoutengine/standard-testcases/table_border_padding_2.xml @@ -97,17 +97,16 @@ and threw it up on high and caught it; and this ball was her favorite plaything. - - + - + - + @@ -124,7 +123,6 @@ and threw it up on high and caught it; and this ball was her favorite plaything. 8 8 8 - 8 @@ -148,10 +146,8 @@ and threw it up on high and caught it; and this ball was her favorite plaything. - - - + diff --git a/test/layoutengine/standard-testcases/table_bug36403.xml b/test/layoutengine/standard-testcases/table_bug36403.xml index ee2116b50..1626a6f8d 100644 --- a/test/layoutengine/standard-testcases/table_bug36403.xml +++ b/test/layoutengine/standard-testcases/table_bug36403.xml @@ -79,22 +79,17 @@ - - - - + 3 - - - + - - - - + + + + 3 diff --git a/test/layoutengine/standard-testcases/table_bug37270.xml b/test/layoutengine/standard-testcases/table_bug37270.xml index e2554d40a..0d4d3dae1 100644 --- a/test/layoutengine/standard-testcases/table_bug37270.xml +++ b/test/layoutengine/standard-testcases/table_bug37270.xml @@ -73,9 +73,9 @@ - + - + 3 diff --git a/test/layoutengine/standard-testcases/table_empty-cells.xml b/test/layoutengine/standard-testcases/table_empty-cells.xml index e9911fb4b..a8ea5a5c7 100644 --- a/test/layoutengine/standard-testcases/table_empty-cells.xml +++ b/test/layoutengine/standard-testcases/table_empty-cells.xml @@ -87,15 +87,19 @@ 6 - - - + - 16 + + + + + + + 10 diff --git a/test/layoutengine/standard-testcases/table_row-delay.xml b/test/layoutengine/standard-testcases/table_row-delay.xml new file mode 100644 index 000000000..a5d88cf46 --- /dev/null +++ b/test/layoutengine/standard-testcases/table_row-delay.xml @@ -0,0 +1,437 @@ + + + + + +

+ Tests for the row delaying mechanism. +

+
+ + + + + + + + + + + + 1. Before the table. + + + + + + Cell 1.1 Line 1 + Cell 1.1 Line 2 + Cell 1.1 Line 3 + Cell 1.1 Line 4 + + + Cell 1.2 + + + Cell 1.3 + + + + + Cell 2.2 + + + Cell 2.3 + Cell 2.3 + + + + + Cell 3.1 + Cell 3.1 + + + Cell 3.2 + Cell 3.2 + + + Cell 3.3 + Cell 3.3 + + + + + + + + + + + 2. Before the table. + + + + + + Cell 1.1 Line 1 + Cell 1.1 Line 2 + Cell 1.1 Line 3 + Cell 1.1 Line 4 + Cell 1.1 Line 5 + Cell 1.1 Line 6 + + + Cell 1.2 + + + Cell 1.3 Line 1 + Cell 1.3 Line 2 + Cell 1.3 Line 3 + Cell 1.3 Line 4 + Cell 1.3 Line 5 + Cell 1.3 Line 6 + + + + + Cell 2.2 + Cell 2.2 + + + + + + + + + + + 3. Before the table. + + + + + + Cell 1.1 Line 1 + Cell 1.1 Line 2 + Cell 1.1 Line 3 + Cell 1.1 Line 4 + Cell 1.1 Line 5 + Cell 1.1 Line 6 + + + Cell 1.2 + + + Cell 1.3 Line 1 + Cell 1.3 Line 2 + Cell 1.3 Line 3 + Cell 1.3 Line 4 + Cell 1.3 Line 5 + Cell 1.3 Line 6 + + + + + Cell 2.2 + Cell 2.2 + + + + + + + + + + + 4. Before the table. + + + + + + Cell 1.1 Line 1 + Cell 1.1 Line 2 + Cell 1.1 Line 3 + Cell 1.1 Line 4 + Cell 1.1 Line 5 + Cell 1.1 Line 6 + + + Cell 1.2 + + + Cell 1.3 Line 1 + Cell 1.3 Line 2 + Cell 1.3 Line 3 + Cell 1.3 Line 4 + Cell 1.3 Line 5 + Cell 1.3 Line 6 + + + + + Cell 2.2 + Cell 2.2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/test/layoutengine/standard-testcases/table_row-delay_fixed-row-height.xml b/test/layoutengine/standard-testcases/table_row-delay_fixed-row-height.xml new file mode 100644 index 000000000..70990de62 --- /dev/null +++ b/test/layoutengine/standard-testcases/table_row-delay_fixed-row-height.xml @@ -0,0 +1,161 @@ + + + + + +

+ Tests the row delaying mechanism when a row has a forced height. +

+
+ + + + + + + + + + + Before the table. + + + + + + Cell 1.1 Line 1 + Cell 1.1 Line 2 + Cell 1.1 Line 3 + Cell 1.1 Line 4 + Cell 1.1 Line 5 + Cell 1.1 Line 6 + + + Cell 1.2 + + + Cell 1.3 Line 1 + Cell 1.3 Line 2 + Cell 1.3 Line 3 + Cell 1.3 Line 4 + Cell 1.3 Line 5 + Cell 1.3 Line 6 + + + + + Cell 2.2 + Cell 2.2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + + + + + + + + + + + + 3 + + +
diff --git a/test/layoutengine/standard-testcases/table_row-delay_header-footer.xml b/test/layoutengine/standard-testcases/table_row-delay_header-footer.xml new file mode 100644 index 000000000..e36f53834 --- /dev/null +++ b/test/layoutengine/standard-testcases/table_row-delay_header-footer.xml @@ -0,0 +1,525 @@ + + + + + +

+ Tests the row delaying mechanism in presence of headers and footers. +

+
+ + + + + + + + + + + + 1. Before the table. + + + + + Header 1.1 + + + Header 1.2 + + + Header 1.3 + + + + + Footer 1.1 + + + Footer 1.2 + + + Footer 1.3 + + + + + + Cell 1.1 Line 1 + Cell 1.1 Line 2 + Cell 1.1 Line 3 + Cell 1.1 Line 4 + + + Cell 1.2 + + + Cell 1.3 + + + + + Cell 2.2 + + + Cell 2.3 + Cell 2.3 + + + + + Cell 3.1 + Cell 3.1 + + + Cell 3.2 + Cell 3.2 + + + Cell 3.3 + Cell 3.3 + + + + + + + + + + + 2. Before the table. + + + + + Header 1.1 + + + Header 1.2 + + + Header 1.3 + + + + + Footer 1.1 + + + Footer 1.2 + + + Footer 1.3 + + + + + + Cell 1.1 Line 1 + Cell 1.1 Line 2 + Cell 1.1 Line 3 + Cell 1.1 Line 4 + Cell 1.1 Line 5 + Cell 1.1 Line 6 + + + Cell 1.2 + + + Cell 1.3 Line 1 + Cell 1.3 Line 2 + Cell 1.3 Line 3 + Cell 1.3 Line 4 + Cell 1.3 Line 5 + Cell 1.3 Line 6 + + + + + Cell 2.2 + Cell 2.2 + + + + + + + + + + + 3. Before the table. + + + + + Header 1.1 + + + Header 1.2 + + + Header 1.3 + + + + + Footer 1.1 + + + Footer 1.2 + + + Footer 1.3 + + + + + + Cell 1.1 Line 1 + Cell 1.1 Line 2 + Cell 1.1 Line 3 + Cell 1.1 Line 4 + Cell 1.1 Line 5 + Cell 1.1 Line 6 + + + Cell 1.2 + + + Cell 1.3 Line 1 + Cell 1.3 Line 2 + Cell 1.3 Line 3 + Cell 1.3 Line 4 + Cell 1.3 Line 5 + Cell 1.3 Line 6 + + + + + Cell 2.2 + Cell 2.2 + + + + + + + + + + + 4. Before the table. + + + + + Header 1.1 + + + Header 1.2 + + + Header 1.3 + + + + + Footer 1.1 + + + Footer 1.2 + + + Footer 1.3 + + + + + + Cell 1.1 Line 1 + Cell 1.1 Line 2 + Cell 1.1 Line 3 + Cell 1.1 Line 4 + Cell 1.1 Line 5 + Cell 1.1 Line 6 + + + Cell 1.2 + + + Cell 1.3 Line 1 + Cell 1.3 Line 2 + Cell 1.3 Line 3 + Cell 1.3 Line 4 + Cell 1.3 Line 5 + Cell 1.3 Line 6 + + + + + Cell 2.2 + Cell 2.2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/test/layoutengine/standard-testcases/table_space-before_space-after_1.xml b/test/layoutengine/standard-testcases/table_space-before_space-after_1.xml index 8b0f18359..6c05f3514 100644 --- a/test/layoutengine/standard-testcases/table_space-before_space-after_1.xml +++ b/test/layoutengine/standard-testcases/table_space-before_space-after_1.xml @@ -95,11 +95,11 @@ Two blocks, testing conditionality="discard". - + - + - + @@ -110,7 +110,6 @@ Two blocks, testing conditionality="discard". 2 2 2 - 2 @@ -137,8 +136,6 @@ Two blocks, testing conditionality="discard".
- - -- 2.39.5