You are viewing a plain text version of this content. The canonical link for it is here.
Posted to fop-commits@xmlgraphics.apache.org by vh...@apache.org on 2008/02/08 13:11:07 UTC

svn commit: r619854 [1/2] - in /xmlgraphics/fop/trunk: src/java/org/apache/fop/layoutmgr/table/ test/layoutengine/standard-testcases/

Author: vhennebert
Date: Fri Feb  8 04:11:04 2008
New Revision: 619854

URL: http://svn.apache.org/viewvc?rev=619854&view=rev
Log:
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"

Added:
    xmlgraphics/fop/trunk/test/layoutengine/standard-testcases/table_row-delay.xml   (with props)
    xmlgraphics/fop/trunk/test/layoutengine/standard-testcases/table_row-delay_fixed-row-height.xml   (with props)
    xmlgraphics/fop/trunk/test/layoutengine/standard-testcases/table_row-delay_header-footer.xml   (with props)
Modified:
    xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/table/ActiveCell.java
    xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/table/CellPart.java
    xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/table/RowPainter.java
    xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java
    xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/table/TableContentPosition.java
    xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/table/TableStepper.java
    xmlgraphics/fop/trunk/test/layoutengine/standard-testcases/table-body_basic_2.xml
    xmlgraphics/fop/trunk/test/layoutengine/standard-testcases/table_border-collapse_collapse_conditionals.xml
    xmlgraphics/fop/trunk/test/layoutengine/standard-testcases/table_border-collapse_collapse_omitHF.xml
    xmlgraphics/fop/trunk/test/layoutengine/standard-testcases/table_border-collapse_separate_border-spacing_2.xml
    xmlgraphics/fop/trunk/test/layoutengine/standard-testcases/table_border_padding_2.xml
    xmlgraphics/fop/trunk/test/layoutengine/standard-testcases/table_bug36403.xml
    xmlgraphics/fop/trunk/test/layoutengine/standard-testcases/table_bug37270.xml
    xmlgraphics/fop/trunk/test/layoutengine/standard-testcases/table_empty-cells.xml
    xmlgraphics/fop/trunk/test/layoutengine/standard-testcases/table_space-before_space-after_1.xml

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/table/ActiveCell.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/table/ActiveCell.java?rev=619854&r1=619853&r2=619854&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/table/ActiveCell.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/table/ActiveCell.java Fri Feb  8 04:11:04 2008
@@ -22,6 +22,8 @@
 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 @@
  * 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 @@
     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 @@
         /** 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 @@
             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 @@
         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 @@
             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 @@
      * 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 @@
                     // 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 @@
     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 @@
      * 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;
         }
     }
 
+    /**
+     * 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
+    }
+
+    /**
+     * Receives indication that the current row is ending, and that (collapse) borders
+     * must be updated accordingly.
+     * 
+     * @param rowIndex the index of the ending row
+     */
     void endRow(int rowIndex) {
         if (endsOnRow(rowIndex)) {
-            int bpAfterNormal = paddingAfterNormal + borderAfterNormal;
-            int bpAfterLast = paddingAfterNormal
+            bpAfterTrailing = paddingAfterNormal
                     + pgu.getAfterBorderWidth(ConditionalBorder.LEADING_TRAILING);
-            lastCellPart.setLast(bpAfterNormal, bpAfterLast);
+            lastCellPart = true;
         } else {
-            spanIndex++;
-            borderBeforeLeading = pgu.getBeforeBorderWidth(spanIndex, ConditionalBorder.REST);
-            borderAfterTrailing = pgu.getAfterBorderWidth(spanIndex, ConditionalBorder.REST);
-        }
-    }
-
-    /**
-     * 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.
-     */
-    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();
+            bpBeforeLeading = paddingBeforeLeading
+                    + pgu.getBeforeBorderWidth(spanIndex + 1, ConditionalBorder.REST);
         }
     }
 
@@ -316,21 +396,14 @@
     }
 
     /**
-     * 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 @@
                 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() {
@@ -394,6 +459,13 @@
     boolean keepWithNextSignal() {
         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).

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/table/CellPart.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/table/CellPart.java?rev=619854&r1=619853&r2=619854&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/table/CellPart.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/table/CellPart.java Fri Feb  8 04:11:04 2008
@@ -49,6 +49,7 @@
      * @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 @@
      * @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;
@@ -85,12 +87,6 @@
     /** @return true if this part is the last part of a cell */
     boolean isLastPart() {
         return isLast;
-    }
-
-    void setLast(int bpNormal, int bpLast) {
-        isLast = true;
-        bpAfterNormal = bpNormal;
-        bpAfterLast = bpLast;
     }
 
     int getBorderPaddingBefore(boolean firstOnPage) {

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/table/RowPainter.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/table/RowPainter.java?rev=619854&r1=619853&r2=619854&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/table/RowPainter.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/table/RowPainter.java Fri Feb  8 04:11:04 2008
@@ -96,14 +96,19 @@
      * @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) {

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java?rev=619854&r1=619853&r2=619854&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java Fri Feb  8 04:11:04 2008
@@ -403,12 +403,12 @@
                     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

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/table/TableContentPosition.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/table/TableContentPosition.java?rev=619854&r1=619853&r2=619854&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/table/TableContentPosition.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/table/TableContentPosition.java Fri Feb  8 04:11:04 2008
@@ -39,10 +39,12 @@
     /** 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 @@
         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;
     }
 
     /**

Modified: xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/table/TableStepper.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/table/TableStepper.java?rev=619854&r1=619853&r2=619854&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/table/TableStepper.java (original)
+++ xmlgraphics/fop/trunk/src/java/org/apache/fop/layoutmgr/table/TableStepper.java Fri Feb  8 04:11:04 2008
@@ -52,51 +52,62 @@
     /** 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 @@
 
     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 @@
     /**
      * 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 @@
             }
 
             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 @@
     }
 
     /**
-     * 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 size of the increment, -1 if no next step is available (end of row-group reached)
+     * @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 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, &lt; 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 @@
                 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);
+        }
+    }
 
+    /**
+     * 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();
+            activeCell.signalNextStep(step);
+        }
+    }
 
-        //Reset bigger-than-minimum sequences
-        //See http://people.apache.org/~jeremias/fop/NextStepAlgoNotes.pdf
-        rowBacktrackForLastStep = false;
-        skippedStep = false;
+    /**
+     * Determines if the given step will finish the current row, and if so switch to the
+     * last step for this row.
+     * <p>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.</p>
+     * <p>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.</p>
+     * 
+     * @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.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;
+            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 */

Modified: xmlgraphics/fop/trunk/test/layoutengine/standard-testcases/table-body_basic_2.xml
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/test/layoutengine/standard-testcases/table-body_basic_2.xml?rev=619854&r1=619853&r2=619854&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/test/layoutengine/standard-testcases/table-body_basic_2.xml (original)
+++ xmlgraphics/fop/trunk/test/layoutengine/standard-testcases/table-body_basic_2.xml Fri Feb  8 04:11:04 2008
@@ -63,10 +63,6 @@
     <element-list category="breaker">
       <box w="75600"/> <!-- block-container as spacer -->
       <penalty w="0" p="0"/>
-      <box w="0"/>
-      <penalty w="9600" p="&gt;0"/>
-      <box w="0"/>
-      <penalty w="19200" p="&gt;0"/>
       <box w="28800"/>
       <penalty w="0" p="0"/>
       <box w="28800"/>

Modified: xmlgraphics/fop/trunk/test/layoutengine/standard-testcases/table_border-collapse_collapse_conditionals.xml
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/test/layoutengine/standard-testcases/table_border-collapse_collapse_conditionals.xml?rev=619854&r1=619853&r2=619854&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/test/layoutengine/standard-testcases/table_border-collapse_collapse_conditionals.xml (original)
+++ xmlgraphics/fop/trunk/test/layoutengine/standard-testcases/table_border-collapse_collapse_conditionals.xml Fri Feb  8 04:11:04 2008
@@ -34,9 +34,9 @@
 
           <!-- table 1 -->
           <fo:block
-            space-after.minimum="30pt"
-            space-after.optimum="40pt"
-            space-after.maximum="50pt"
+            space-after.minimum="44pt"
+            space-after.optimum="45pt"
+            space-after.maximum="46pt"
             >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"/>

Modified: xmlgraphics/fop/trunk/test/layoutengine/standard-testcases/table_border-collapse_collapse_omitHF.xml
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/test/layoutengine/standard-testcases/table_border-collapse_collapse_omitHF.xml?rev=619854&r1=619853&r2=619854&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/test/layoutengine/standard-testcases/table_border-collapse_collapse_omitHF.xml (original)
+++ xmlgraphics/fop/trunk/test/layoutengine/standard-testcases/table_border-collapse_collapse_omitHF.xml Fri Feb  8 04:11:04 2008
@@ -34,9 +34,9 @@
         <fo:flow flow-name="xsl-region-body">
 
           <fo:block
-            space-after.minimum="20pt"
-            space-after.optimum="30pt"
-            space-after.maximum="40pt"
+            space-after.minimum="25pt"
+            space-after.optimum="35pt"
+            space-after.maximum="45pt"
             >Before the table</fo:block>
           <fo:table width="100%" table-layout="fixed" border="6pt solid black"
             table-omit-header-at-break="true" table-omit-footer-at-break="true">

Modified: xmlgraphics/fop/trunk/test/layoutengine/standard-testcases/table_border-collapse_separate_border-spacing_2.xml
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/test/layoutengine/standard-testcases/table_border-collapse_separate_border-spacing_2.xml?rev=619854&r1=619853&r2=619854&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/test/layoutengine/standard-testcases/table_border-collapse_separate_border-spacing_2.xml (original)
+++ xmlgraphics/fop/trunk/test/layoutengine/standard-testcases/table_border-collapse_separate_border-spacing_2.xml Fri Feb  8 04:11:04 2008
@@ -134,19 +134,17 @@
       <box w="0"/>
       <penalty w="0" p="INF"/>
       <glue w="7500"/>
-      <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="12500"/>
-      <penalty w="0"/>
+      <penalty w="2500" p="0"/>
       <box w="2500"/>
-      <penalty w="0" p="900"/>
-      <box w="12500"/>
+      <penalty w="7500" p="0"/>
+      <box w="7500"/>
+      <penalty w="5000" p="0"/>
+      <box w="5000"/>
+      <penalty w="7500"/>
+      <box w="7500"/>
+      <penalty w="2500"/>
+      <box w="15000"/>
       <penalty w="0" p="INF"/>
       <glue w="7500"/>
 
@@ -156,19 +154,17 @@
       <box w="0"/>
       <penalty w="0" p="INF"/>
       <glue w="7500"/>
-      <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="12500"/>
-      <penalty w="0"/>
+      <penalty w="2500" p="0"/>
       <box w="2500"/>
-      <penalty w="0" p="900"/>
-      <box w="12500"/>
+      <penalty w="7500" p="0"/>
+      <box w="7500"/>
+      <penalty w="5000" p="0"/>
+      <box w="5000"/>
+      <penalty w="7500"/>
+      <box w="7500"/>
+      <penalty w="2500"/>
+      <box w="15000"/>
       <box w="0"/> <!-- with SpaceHandlingPosition -->
       <penalty w="0" p="INF"/>
       <glue w="7500"/>

Modified: xmlgraphics/fop/trunk/test/layoutengine/standard-testcases/table_border_padding_2.xml
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/test/layoutengine/standard-testcases/table_border_padding_2.xml?rev=619854&r1=619853&r2=619854&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/test/layoutengine/standard-testcases/table_border_padding_2.xml (original)
+++ xmlgraphics/fop/trunk/test/layoutengine/standard-testcases/table_border_padding_2.xml Fri Feb  8 04:11:04 2008
@@ -97,17 +97,16 @@
       <penalty w="0" p="INF"/>
       <glue w="25000"/>
       
-      <box w="0"/>
-      
+      <box w="28800"/>
       <penalty w="0" p="INF"/>
       <glue w="25000"/>
-      <penalty w="14400"/> <!-- p is not of interest here -->
+      <penalty w="0"/> <!-- p is not of interest here -->
       <glue w="-50000"/>
       <box w="0"/>
       <penalty w="0" p="INF"/>
       <glue w="25000"/>
       
-      <box w="28800"/>
+      <box w="14400"/>
       
       <penalty w="0" p="INF"/>
       <glue w="25000"/>
@@ -124,7 +123,6 @@
       <skip>8</skip>
       <skip>8</skip>
       <skip>8</skip>
-      <skip>8</skip>
       
       <penalty w="0" p="INF"/>
       <glue w="25000"/>
@@ -148,10 +146,8 @@
       <box w="0"/> <!-- Helper box used to notify the LM for the addAreas stage about the discarded spaces -->
       <penalty w="0" p="INF"/>
       <glue w="25000"/>
-      <box w="0"/>
-      <penalty w="14400"/> <!-- p is not of interest here -->
       <box w="28800"/>
-      <penalty w="0" p="0"/>
+      <penalty w="0"/> <!-- p is not of interest here -->
       <box w="14400"/>
       <penalty w="0" p="0"/>
       <box w="14400"/>

Modified: xmlgraphics/fop/trunk/test/layoutengine/standard-testcases/table_bug36403.xml
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/test/layoutengine/standard-testcases/table_bug36403.xml?rev=619854&r1=619853&r2=619854&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/test/layoutengine/standard-testcases/table_bug36403.xml (original)
+++ xmlgraphics/fop/trunk/test/layoutengine/standard-testcases/table_bug36403.xml Fri Feb  8 04:11:04 2008
@@ -79,22 +79,17 @@
   </fo>
   <checks>
     <element-list category="breaker" id="skipped-step">
-      <box w="14400"/>
-      <penalty w="0" p="INF"/> <!-- Skipped step has an INFINITE penalty -->
-      <glue w="3600"/>
-      <box w="32400"/>
+      <box w="50400"/>
       <skip>3</skip>
     </element-list>
     <element-list category="breaker" id="backtrack">
-      <box w="2000"/>
-      <penalty w="8000" p="900"/> <!-- p > 0 && p <= INF -->
-      <box w="16400"/>
+      <box w="18400"/>
       <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="5000"/>
-      <penalty w="6600"/> <!-- p = ??? -->
-      <box w="19400"/>
+      <penalty w="1600" p="0"/>
+      <box w="0"/>
+      <penalty w="11600"/>
+      <box w="24400"/>
       <skip>3</skip>
     </element-list>
   </checks>

Modified: xmlgraphics/fop/trunk/test/layoutengine/standard-testcases/table_bug37270.xml
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/test/layoutengine/standard-testcases/table_bug37270.xml?rev=619854&r1=619853&r2=619854&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/test/layoutengine/standard-testcases/table_bug37270.xml (original)
+++ xmlgraphics/fop/trunk/test/layoutengine/standard-testcases/table_bug37270.xml Fri Feb  8 04:11:04 2008
@@ -73,9 +73,9 @@
     <!-- Simply check that FOP doesn't fail with an IndexOutOfBoundsException or an NPE -->
     <element-list category="breaker">
       <box w="0"/>
-      <penalty w="14400"/> <!-- p > 0 && p <= INF -->
+      <penalty w="0" p="INF"/>
       <box w="14400"/>
-      <penalty w="14400"/> <!-- p > 0 && p <= INF -->
+      <penalty w="0" p="INF"/>
       <box w="40000"/>
       <skip>3</skip>
     </element-list>

Modified: xmlgraphics/fop/trunk/test/layoutengine/standard-testcases/table_empty-cells.xml
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/trunk/test/layoutengine/standard-testcases/table_empty-cells.xml?rev=619854&r1=619853&r2=619854&view=diff
==============================================================================
--- xmlgraphics/fop/trunk/test/layoutengine/standard-testcases/table_empty-cells.xml (original)
+++ xmlgraphics/fop/trunk/test/layoutengine/standard-testcases/table_empty-cells.xml Fri Feb  8 04:11:04 2008
@@ -87,15 +87,19 @@
     <eval expected="2" xpath="count(//pageViewport)"/>
     <element-list category="breaker">
       <skip>6</skip>
-      <box w="1000"/>
-      <penalty p="900" w="1000"/>
-      <box w="14400"/>
+      <box w="15400"/>
       <penalty p="0" w="0"/>
       <box w="14400"/>
       <penalty p="0" w="0"/>
       <box w="15400"/>
       <penalty p="0" w="0"/>
-      <skip>16</skip>
+      <box w="16400"/>
+      <penalty p="0" w="0"/>
+      <box w="16400"/>
+      <penalty p="0" w="0"/>
+      <box w="16400"/>
+      <penalty p="0" w="0"/>
+      <skip>10</skip>
     </element-list>
   </checks>
 </testcase>



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