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 sp...@apache.org on 2008/02/14 22:57:53 UTC

svn commit: r627882 [9/41] - in /xmlgraphics/fop/branches/Temp_Interleaved_Page_Line_Breaking: ./ examples/embedding/ examples/embedding/java/embedding/ examples/embedding/java/embedding/intermediate/ examples/embedding/xml/xml/ examples/fo/ examples/f...

Modified: xmlgraphics/fop/branches/Temp_Interleaved_Page_Line_Breaking/src/java/org/apache/fop/layoutmgr/table/RowPainter.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_Interleaved_Page_Line_Breaking/src/java/org/apache/fop/layoutmgr/table/RowPainter.java?rev=627882&r1=627881&r2=627882&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_Interleaved_Page_Line_Breaking/src/java/org/apache/fop/layoutmgr/table/RowPainter.java (original)
+++ xmlgraphics/fop/branches/Temp_Interleaved_Page_Line_Breaking/src/java/org/apache/fop/layoutmgr/table/RowPainter.java Thu Feb 14 13:55:44 2008
@@ -26,31 +26,39 @@
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+import org.apache.fop.fo.flow.table.ConditionalBorder;
 import org.apache.fop.fo.flow.table.EffRow;
 import org.apache.fop.fo.flow.table.GridUnit;
 import org.apache.fop.fo.flow.table.PrimaryGridUnit;
 import org.apache.fop.fo.flow.table.TableRow;
-import org.apache.fop.fo.properties.LengthRangeProperty;
 import org.apache.fop.layoutmgr.ElementListUtils;
 import org.apache.fop.layoutmgr.KnuthElement;
 import org.apache.fop.layoutmgr.KnuthPossPosIter;
 import org.apache.fop.layoutmgr.LayoutContext;
 import org.apache.fop.layoutmgr.SpaceResolver;
+import org.apache.fop.traits.BorderProps;
 
 class RowPainter {
     private static Log log = LogFactory.getLog(RowPainter.class);
     /** The fo:table-row containing the currently handled grid rows. */
     private TableRow rowFO = null;
     private int colCount;
-    private int yoffset = 0;
-    private int accumulatedBPD = 0;
+    private int currentRowOffset = 0;
     /** Currently handled row (= last encountered row). */
-    private EffRow lastRow = null;
+    private EffRow currentRow = null;
     private LayoutContext layoutContext;
     /**
      * Index of the first row of the current part present on the current page.
      */
     private int firstRowIndex;
+
+    /**
+     * Index of the very first row on the current page. Needed to properly handle
+     * {@link BorderProps#COLLAPSE_OUTER}. This is not the same as {@link #firstRowIndex}
+     * when the table has headers!
+     */
+    private int firstRowOnPageIndex;
+
     /**
      * Keeps track of the y-offsets of each row on a page.
      * This is particularly needed for spanned cells where you need to know the y-offset
@@ -58,40 +66,27 @@
      */
     private List rowOffsets = new ArrayList();
 
-    //These three variables are our buffer to recombine the individual steps into cells
-    /** Primary grid units corresponding to the currently handled grid units, per row. */
-    private PrimaryGridUnit[] primaryGridUnits;
-    /**
-     * Index, in the corresponding table cell's list of Knuth elements, of the first
-     * element present on the current page, per column.
-     */
-    private int[] start;
-    /**
-     * Index, in the corresponding table cell's list of Knuth elements, of the last
-     * element present on the current page, per column.
-     */
-    private int[] end;
-    /**
-     * Length, for each column, of the elements from the current cell put on the
-     * current page. This is the corresponding area's bpd.
-     */
-    private int[] partBPD;
+    private int[] cellHeights;
+    private boolean[] firstCellOnPage;
+    private CellPart[] firstCellParts;
+    private CellPart[] lastCellParts;
+
     private TableContentLayoutManager tclm;
 
     RowPainter(TableContentLayoutManager tclm, LayoutContext layoutContext) {
         this.tclm = tclm;
         this.layoutContext = layoutContext;
         this.colCount = tclm.getColumns().getColumnCount();
-        this.primaryGridUnits = new PrimaryGridUnit[colCount];
-        this.start = new int[colCount];
-        this.end = new int[colCount];
-        this.partBPD = new int[colCount];
+        this.cellHeights = new int[colCount];
+        this.firstCellOnPage = new boolean[colCount];
+        this.firstCellParts = new CellPart[colCount];
+        this.lastCellParts = new CellPart[colCount];
         this.firstRowIndex = -1;
-        Arrays.fill(end, -1);
+        this.firstRowOnPageIndex = -1;
     }
 
     int getAccumulatedBPD() {
-        return this.accumulatedBPD;
+        return currentRowOffset;
     }
 
     /**
@@ -101,16 +96,24 @@
      * @param tcpos a position representing the row fragment
      */
     void handleTableContentPosition(TableContentPosition tcpos) {
-        if (lastRow != tcpos.row && lastRow != null) {
-            addAreasAndFlushRow(false);
-        }
         if (log.isDebugEnabled()) {
             log.debug("===handleTableContentPosition(" + tcpos);
         }
-        rowFO = tcpos.row.getTableRow();
-        lastRow = 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 = lastRow.getIndex();
+            firstRowIndex = currentRow.getIndex();
+            if (firstRowOnPageIndex < 0) {
+                firstRowOnPageIndex = firstRowIndex;
+            }
         }
         Iterator partIter = tcpos.cellParts.iterator();
         //Iterate over all grid units in the current step
@@ -119,212 +122,204 @@
             if (log.isDebugEnabled()) {
                 log.debug(">" + cellPart);
             }
-            int colIndex = cellPart.pgu.getStartCol();
-            if (primaryGridUnits[colIndex] != cellPart.pgu) {
-                if (primaryGridUnits[colIndex] != null) {
-                    log.warn("Replacing GU in slot " + colIndex
-                            + ". Some content may not be painted.");
-                }
-                primaryGridUnits[colIndex] = cellPart.pgu;
-                start[colIndex] = cellPart.start;
-                end[colIndex] = cellPart.end;
+            int colIndex = cellPart.pgu.getColIndex();
+            if (firstCellParts[colIndex] == null) {
+                firstCellParts[colIndex] = cellPart;
+                cellHeights[colIndex] = cellPart.getBorderPaddingBefore(firstCellOnPage[colIndex]);
             } else {
-                if (cellPart.end < end[colIndex]) {
-                    throw new IllegalStateException("Internal Error: stepper problem");
-                }
-                end[colIndex] = cellPart.end;
+                assert firstCellParts[colIndex].pgu == cellPart.pgu; 
+                cellHeights[colIndex] += cellPart.getConditionalBeforeContentLength();
             }
+            cellHeights[colIndex] += cellPart.getLength();
+            lastCellParts[colIndex] = cellPart;
         }
     }
 
     /**
-     * Create the areas corresponding to the last row. This method is called either
-     * because the row is finished (all of the elements present on this row have been
-     * added), or because this is the last row on the current page, and the part of it
-     * lying on the current page must be drawn.
+     * Creates the areas corresponding to the last row. That is, an area with background
+     * for the row, plus areas for all the cells that finish on the row (not spanning over
+     * further rows).
      * 
-     * @param forcedFlush true if the elements must be drawn even if the row isn't
-     * finished yet (last row on the page), or if the row is the last of the current table
-     * part
-     * @return the height of the (grid) row
+     * @param lastInPart true if the row is the last from its table part to be displayed
+     * on the current page. In which case all the cells must be flushed even if they
+     * aren't finished, plus the proper collapsed borders must be selected (trailing
+     * instead of normal, or rest if the cell is unfinished)
+     * @param lastOnPage true if the row is the very last row of the table that will be
+     * displayed on the current page. In which case collapsed after borders must be drawn
+     * in the outer mode
      */
-    int addAreasAndFlushRow(boolean forcedFlush) {
-        int actualRowHeight = 0;
-
+    void addAreasAndFlushRow(boolean lastInPart, boolean lastOnPage) {
         if (log.isDebugEnabled()) {
-            log.debug("Remembering yoffset for row " + lastRow.getIndex() + ": " + yoffset);
+            log.debug("Remembering yoffset for row " + currentRow.getIndex() + ": "
+                    + currentRowOffset);
         }
-        recordRowOffset(lastRow.getIndex(), yoffset);
+        recordRowOffset(currentRow.getIndex(), currentRowOffset);
 
-        for (int i = 0; i < primaryGridUnits.length; i++) {
-            if ((primaryGridUnits[i] != null)
-                    && (forcedFlush || (end[i] == primaryGridUnits[i].getElements().size() - 1))) {
-                actualRowHeight = Math.max(actualRowHeight, computeSpanHeight(
-                        primaryGridUnits[i], start[i], end[i], i));
+        // Need to compute the actual row height first
+        int actualRowHeight = 0;
+        for (int i = 0; i < colCount; i++) {
+            GridUnit currentGU = currentRow.getGridUnit(i);            
+            if (!currentGU.isEmpty() && currentGU.getColSpanIndex() == 0
+                    && (lastInPart || currentGU.isLastGridUnitRowSpan())
+                    && firstCellParts[i] != null) {
+                // TODO
+                // The last test above is a workaround for the stepping algorithm's
+                // fundamental flaw making it unable to produce the right element list for
+                // multiple breaks inside a same row group.
+                // (see http://wiki.apache.org/xmlgraphics-fop/TableLayout/KnownProblems)
+                // In some extremely rare cases (forced breaks, very small page height), a
+                // TableContentPosition produced during row delaying may end up alone on a
+                // page. It will not contain the CellPart instances for the cells starting
+                // the next row, so firstCellParts[i] will still be null for those ones.
+                int cellHeight = cellHeights[i];
+                cellHeight += lastCellParts[i].getConditionalAfterContentLength();
+                cellHeight += lastCellParts[i].getBorderPaddingAfter(lastInPart);
+                int cellOffset = getRowOffset(Math.max(firstCellParts[i].pgu.getRowIndex(),
+                        firstRowIndex));
+                actualRowHeight = Math.max(actualRowHeight, cellOffset + cellHeight
+                        - currentRowOffset);
             }
         }
-        actualRowHeight += 2 * tclm.getTableLM().getHalfBorderSeparationBPD();
 
-        //Add areas for row
-        tclm.addRowBackgroundArea(rowFO, actualRowHeight, layoutContext.getRefIPD(), yoffset);
-        for (int i = 0; i < primaryGridUnits.length; i++) {
-            GridUnit currentGU = lastRow.getGridUnit(i);            
+        // Then add areas for cells finishing on the current row
+        tclm.addRowBackgroundArea(rowFO, actualRowHeight, layoutContext.getRefIPD(),
+                currentRowOffset);
+        for (int i = 0; i < colCount; i++) {
+            GridUnit currentGU = currentRow.getGridUnit(i);            
             if (!currentGU.isEmpty() && currentGU.getColSpanIndex() == 0
-                    && (forcedFlush || currentGU.isLastGridUnitRowSpan())) {
-                addAreasForCell(currentGU.getPrimary(), start[i], end[i], lastRow, partBPD[i],
-                        actualRowHeight);
-                primaryGridUnits[i] = null;
-                start[i] = 0;
-                end[i] = -1;
-                partBPD[i] = 0;
+                    && (lastInPart || currentGU.isLastGridUnitRowSpan())
+                    && firstCellParts[i] != null) {
+                assert firstCellParts[i].pgu == currentGU.getPrimary();
+                int borderBeforeWhich;
+                if (firstCellParts[i].start == 0) {
+                    if (firstCellOnPage[i]) {
+                        borderBeforeWhich = ConditionalBorder.LEADING_TRAILING;
+                    } else {
+                        borderBeforeWhich = ConditionalBorder.NORMAL;
+                    }
+                } else {
+                    assert firstCellOnPage[i];
+                    borderBeforeWhich = ConditionalBorder.REST;
+                }
+                int borderAfterWhich;
+                if (lastCellParts[i].isLastPart()) {
+                    if (lastInPart) {
+                        borderAfterWhich = ConditionalBorder.LEADING_TRAILING;
+                    } else {
+                        borderAfterWhich = ConditionalBorder.NORMAL;
+                    }
+                } else {
+                    borderAfterWhich = ConditionalBorder.REST;
+                }
+                addAreasForCell(firstCellParts[i].pgu,
+                        firstCellParts[i].start, lastCellParts[i].end,
+                        actualRowHeight, borderBeforeWhich, borderAfterWhich,
+                        lastOnPage);
+                firstCellParts[i] = null;
+                firstCellOnPage[i] = false;
             }
         }
-        yoffset += actualRowHeight;
-        accumulatedBPD += actualRowHeight;
-        if (forcedFlush) {
-            // Either the end of the page is reached, then this was the last call of this
-            // method and we no longer care about lastRow; or the end of a table-part
-            // (header, footer, body) has been reached, and the next row will anyway be
-            // different from the current one, and this is unnecessary to recall this
-            // method in the first lines of handleTableContentPosition, so we may reset
-            // the following variables
-            lastRow = null;
+        currentRowOffset += actualRowHeight;
+        if (lastInPart) {
+            /*
+             * Either the end of the page is reached, then this was the last call of this
+             * method and we no longer care about currentRow; or the end of a table-part
+             * (header, footer, body) has been reached, and the next row will anyway be
+             * different from the current one, and this is unnecessary to call this method
+             * again in the first lines of handleTableContentPosition, so we may reset the
+             * following variables.
+             */
+            currentRow = null;
             firstRowIndex = -1;
             rowOffsets.clear();
+            /*
+             * The current table part has just been handled. Be it the first one or not,
+             * the header or the body, in any case the borders-before of the next row
+             * (i.e., the first row of the next part if any) must be painted in
+             * COLLAPSE_INNER mode. So the firstRowOnPageIndex indicator must be kept
+             * disabled. The following way is not the most elegant one but will be good
+             * enough.
+             */
+            firstRowOnPageIndex = Integer.MAX_VALUE;
         }
-        return actualRowHeight;
     }
 
-    /**
-     * Computes the total height of the part of the given cell spanning on the current
-     * active row, including borders and paddings. The bpd is also stored in partBPD, and
-     * it is ensured that the cell's or row's explicit height is respected. yoffset is
-     * updated accordingly.
-     * 
-     * @param pgu primary grid unit corresponding to the cell
-     * @param start index of the first element of the cell occuring on the current page
-     * @param end index of the last element of the cell occuring on the current page
-     * @param columnIndex column index of the cell
-     * @param bodyType {@link TableRowIterator#HEADER}, {@link TableRowIterator#FOOTER}, or
-     * {@link TableRowIterator#BODY}
-     * @return the cell's height
-     */
-    private int computeSpanHeight(PrimaryGridUnit pgu, int start, int end, int columnIndex) {
-        if (log.isTraceEnabled()) {
-            log.trace("getting len for " + columnIndex + " "
-                    + start + "-" + end);
-        }
-        int actualStart = start;
-        // Skip from the content length calculation glues and penalties occuring at the
-        // beginning of the page
-        while (actualStart <= end && !((KnuthElement)pgu.getElements().get(actualStart)).isBox()) {
-            actualStart++;
-        }
-        int len = ElementListUtils.calcContentLength(
-                pgu.getElements(), actualStart, end);
-        KnuthElement el = (KnuthElement)pgu.getElements().get(end);
-        if (el.isPenalty()) {
-            len += el.getW();
-        }
-        partBPD[columnIndex] = len;
-        if (log.isTraceEnabled()) {
-            log.trace("len of part: " + len);
-        }
-
-        if (start == 0) {
-            LengthRangeProperty bpd = pgu.getCell()
-                    .getBlockProgressionDimension();
-            if (!bpd.getMinimum(tclm.getTableLM()).isAuto()) {
-                int min = bpd.getMinimum(tclm.getTableLM())
-                            .getLength().getValue(tclm.getTableLM());
-                if (min > 0) {
-                    len = Math.max(len, min);
-                }
-            }
-            if (!bpd.getOptimum(tclm.getTableLM()).isAuto()) {
-                int opt = bpd.getOptimum(tclm.getTableLM())
-                            .getLength().getValue(tclm.getTableLM());
-                if (opt > 0) {
-                    len = Math.max(len, opt);
-                }
+    // TODO this is not very efficient and should probably be done another way
+    // this method is only necessary when display-align = center or after, in which case
+    // the exact content length is needed to compute the size of the empty block that will
+    // be used as padding.
+    // This should be handled automatically by a proper use of Knuth elements
+    private int computeContentLength(PrimaryGridUnit pgu, int startIndex, int endIndex) {
+        if (startIndex > endIndex) {
+             // May happen if the cell contributes no content on the current page (empty
+             // cell, in most cases)
+            return 0;
+        } else {
+            int actualStart = startIndex;
+            // Skip from the content length calculation glues and penalties occurring at the
+            // beginning of the page
+            while (actualStart <= endIndex
+                    && !((KnuthElement) pgu.getElements().get(actualStart)).isBox()) {
+                actualStart++;
             }
-            if (pgu.getRow() != null) {
-                bpd = pgu.getRow().getBlockProgressionDimension();
-                if (!bpd.getMinimum(tclm.getTableLM()).isAuto()) {
-                    int min = bpd.getMinimum(tclm.getTableLM()).getLength()
-                                .getValue(tclm.getTableLM());
-                    if (min > 0) {
-                        len = Math.max(len, min);
-                    }
-                }
+            int len = ElementListUtils.calcContentLength(
+                    pgu.getElements(), actualStart, endIndex);
+            KnuthElement el = (KnuthElement)pgu.getElements().get(endIndex);
+            if (el.isPenalty()) {
+                len += el.getW();
             }
+            return len;
         }
-
-        // Add the padding if any
-        len += pgu.getBorders()
-                        .getPaddingBefore(false, pgu.getCellLM());
-        len += pgu.getBorders()
-                        .getPaddingAfter(false, pgu.getCellLM());
-
-        //Now add the borders to the contentLength
-        if (tclm.isSeparateBorderModel()) {
-            len += pgu.getBorders().getBorderBeforeWidth(false);
-            len += pgu.getBorders().getBorderAfterWidth(false);
-        } else {
-            len += pgu.getHalfMaxBeforeBorderWidth();
-            len += pgu.getHalfMaxAfterBorderWidth();
-        }
-        int cellOffset = getRowOffset(Math.max(pgu.getStartRow(), firstRowIndex));
-        len -= yoffset - cellOffset;
-        return len;
     }
 
     private void addAreasForCell(PrimaryGridUnit pgu, int startPos, int endPos,
-            EffRow row, int contentHeight, int rowHeight) {
-        //Determine the first row in this sequence
-        int startRowIndex = Math.max(pgu.getStartRow(), firstRowIndex);
-        int lastRowIndex = lastRow.getIndex();
-
-        // In collapsing-border model, if the cell spans over several columns/rows then
-        // dedicated areas will be created for each grid unit to hold the corresponding
-        // borders. For that we need to know the height of each grid unit, that is of each
-        // grid row spanned over by the cell
+            int rowHeight, int borderBeforeWhich, int borderAfterWhich, boolean lastOnPage) {
+        /*
+         * Determine the index of the first row of this cell that will be displayed on the
+         * current page.
+         */
+        int startRowIndex = Math.max(pgu.getRowIndex(), firstRowIndex);
+        int currentRowIndex = currentRow.getIndex();
+
+        /*
+         * In collapsing-border model, if the cell spans over several columns/rows then
+         * dedicated areas will be created for each grid unit to hold the corresponding
+         * borders. For that we need to know the height of each grid unit, that is of each
+         * grid row spanned over by the cell
+         */
         int[] spannedGridRowHeights = null;
         if (!tclm.getTableLM().getTable().isSeparateBorderModel() && pgu.hasSpanning()) {
-            spannedGridRowHeights = new int[lastRowIndex - startRowIndex + 1];
+            spannedGridRowHeights = new int[currentRowIndex - startRowIndex + 1];
             int prevOffset = getRowOffset(startRowIndex);
-            for (int i = 0; i < lastRowIndex - startRowIndex; i++) {
+            for (int i = 0; i < currentRowIndex - startRowIndex; i++) {
                 int newOffset = getRowOffset(startRowIndex + i + 1);
                 spannedGridRowHeights[i] = newOffset - prevOffset;
                 prevOffset = newOffset;
             }
-            spannedGridRowHeights[lastRowIndex - startRowIndex] = rowHeight;
+            spannedGridRowHeights[currentRowIndex - startRowIndex] = rowHeight;
         }
-
         int cellOffset = getRowOffset(startRowIndex);
-        int effCellHeight = rowHeight;
-        effCellHeight += yoffset - cellOffset;
+        int cellTotalHeight = rowHeight + currentRowOffset - cellOffset;
         if (log.isDebugEnabled()) {
             log.debug("Creating area for cell:");
-            log.debug("  current row: " + row.getIndex());
-            log.debug("  start row: " + pgu.getStartRow() + " " + yoffset + " " + cellOffset);
-            log.debug("  contentHeight: " + contentHeight + " rowHeight=" + rowHeight
-                    + " effCellHeight=" + effCellHeight);
+            log.debug("  start row: " + pgu.getRowIndex() + " " + currentRowOffset + " "
+                    + cellOffset);
+            log.debug(" rowHeight=" + rowHeight + " cellTotalHeight=" + cellTotalHeight);
         }
         TableCellLayoutManager cellLM = pgu.getCellLM();
         cellLM.setXOffset(tclm.getXOffsetOfGridUnit(pgu));
         cellLM.setYOffset(cellOffset);
-        cellLM.setContentHeight(contentHeight);
-        cellLM.setRowHeight(effCellHeight);
-        //cellLM.setRowHeight(row.getHeight().opt);
+        cellLM.setContentHeight(computeContentLength(pgu, startPos, endPos));
+        cellLM.setTotalHeight(cellTotalHeight);
         int prevBreak = ElementListUtils.determinePreviousBreak(pgu.getElements(), startPos);
         if (endPos >= 0) {
             SpaceResolver.performConditionalsNotification(pgu.getElements(),
                     startPos, endPos, prevBreak);
         }
         cellLM.addAreas(new KnuthPossPosIter(pgu.getElements(), startPos, endPos + 1),
-                layoutContext, spannedGridRowHeights, startRowIndex - pgu.getStartRow(),
-                lastRowIndex - pgu.getStartRow() + 1);
+                layoutContext, spannedGridRowHeights, startRowIndex - pgu.getRowIndex(),
+                currentRowIndex - pgu.getRowIndex(), borderBeforeWhich, borderAfterWhich,
+                startRowIndex == firstRowOnPageIndex, lastOnPage);
     }
 
     /**
@@ -342,7 +337,7 @@
          * TableContentPosition will be created for this row. Thus its index will never be
          * recorded by the #handleTableContentPosition method.
          * 
-         * The yoffset for such a row is the same as the next non-empty row. It's needed
+         * The offset of such a row is the same as the next non-empty row. It's needed
          * to correctly offset blocks for cells starting on this row. Hence the loop
          * below.
          */
@@ -359,5 +354,15 @@
      */
     private int getRowOffset(int rowIndex) {
         return ((Integer) rowOffsets.get(rowIndex - firstRowIndex)).intValue();
+    }
+
+    // TODO get rid of that
+    void startBody() {
+        Arrays.fill(firstCellOnPage, true);
+    }
+
+    // TODO get rid of that
+    void endBody() {
+        Arrays.fill(firstCellOnPage, false);
     }
 }

Propchange: xmlgraphics/fop/branches/Temp_Interleaved_Page_Line_Breaking/src/java/org/apache/fop/layoutmgr/table/TableAndCaptionLayoutManager.java
------------------------------------------------------------------------------
--- svn:keywords (original)
+++ svn:keywords Thu Feb 14 13:55:44 2008
@@ -1 +1 @@
-Author Date Id Revision
+Id

Propchange: xmlgraphics/fop/branches/Temp_Interleaved_Page_Line_Breaking/src/java/org/apache/fop/layoutmgr/table/TableCaptionLayoutManager.java
------------------------------------------------------------------------------
--- svn:keywords (original)
+++ svn:keywords Thu Feb 14 13:55:44 2008
@@ -1 +1 @@
-Author Date Id Revision
+Id

Modified: xmlgraphics/fop/branches/Temp_Interleaved_Page_Line_Breaking/src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_Interleaved_Page_Line_Breaking/src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java?rev=627882&r1=627881&r2=627882&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_Interleaved_Page_Line_Breaking/src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java (original)
+++ xmlgraphics/fop/branches/Temp_Interleaved_Page_Line_Breaking/src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java Thu Feb 14 13:55:44 2008
@@ -28,11 +28,13 @@
 import org.apache.fop.area.Trait;
 import org.apache.fop.datatypes.PercentBaseContext;
 import org.apache.fop.fo.FONode;
+import org.apache.fop.fo.flow.table.ConditionalBorder;
 import org.apache.fop.fo.flow.table.GridUnit;
 import org.apache.fop.fo.flow.table.PrimaryGridUnit;
 import org.apache.fop.fo.flow.table.Table;
 import org.apache.fop.fo.flow.table.TableCell;
 import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
+import org.apache.fop.fo.properties.CommonBorderPaddingBackground.BorderInfo;
 import org.apache.fop.layoutmgr.AreaAdditionUtil;
 import org.apache.fop.layoutmgr.BlockLevelLayoutManager;
 import org.apache.fop.layoutmgr.BlockStackingLayoutManager;
@@ -47,6 +49,7 @@
 import org.apache.fop.layoutmgr.PositionIterator;
 import org.apache.fop.layoutmgr.SpaceResolver;
 import org.apache.fop.layoutmgr.TraitSetter;
+import org.apache.fop.traits.BorderProps;
 import org.apache.fop.traits.MinOptMax;
 
 /**
@@ -65,8 +68,6 @@
 
     private Block curBlockArea;
 
-    private int inRowIPDOffset;
-
     private int xoffset;
     private int yoffset;
     private int cellIPD;
@@ -137,7 +138,8 @@
             startIndent /= 2;
             endIndent /= 2;
         }
-        startIndent += getTableCell().getCommonBorderPaddingBackground().getPaddingStart(false, this);
+        startIndent += getTableCell().getCommonBorderPaddingBackground().getPaddingStart(false,
+                this);
         endIndent += getTableCell().getCommonBorderPaddingBackground().getPaddingEnd(false, this);
         return startIndent + endIndent;
     }
@@ -208,7 +210,7 @@
                     // with a SpaceResolver.SpaceHandlingBreakPosition element, having no
                     // LM associated to it. Thus it will stop early instead of adding
                     // areas for following Positions. The above test aims at preventing
-                    // such a situation from occuring. add a null penalty to allow a break
+                    // such a situation from occurring. add a null penalty to allow a break
                     // between blocks
                     contentList.add(new BreakElement(
                             new Position(this), 0, context));
@@ -244,6 +246,16 @@
         }
         //Space resolution
         SpaceResolver.resolveElementList(returnList);
+        if (((KnuthElement) returnList.getFirst()).isForcedBreak()) {
+            primaryGridUnit.setBreakBefore(((KnuthPenalty) returnList.getFirst()).getBreakClass());
+            returnList.removeFirst();
+            assert !returnList.isEmpty();
+        }
+        if (((KnuthElement) returnList.getLast()).isForcedBreak()) {
+            KnuthPenalty p = (KnuthPenalty) returnList.getLast();
+            primaryGridUnit.setBreakAfter(p.getBreakClass());
+            p.setP(0);
+        }
 
         getPSLM().notifyEndOfLayout(((TableCell)getFObj()).getId());
 
@@ -272,15 +284,6 @@
     }
 
     /**
-     * Set the IPD offset of this cell inside the table-row.
-     * This offset is used to determine the absolute position of the cell.
-     * @param off the IPD offset
-     */
-    public void setInRowIPDOffset(int off) {
-        this.inRowIPDOffset = off;
-    }
-
-    /**
      * Set the content height for this cell. This method is used during
      * addAreas() stage.
      *
@@ -291,37 +294,16 @@
     }
 
     /**
-     * Set the row height that contains this cell. This method is used during
-     * addAreas() stage.
-     *
-     * @param h the height of the row
+     * Sets the total height of this cell on the current page. That is, the cell's bpd
+     * plus before and after borders and paddings, plus the table's border-separation.
+     * 
+     * @param h the height of cell
      */
-    public void setRowHeight(int h) {
+    public void setTotalHeight(int h) {
         rowHeight = h;
     }
 
     /**
-     * Returns the bpd of the given grid unit.
-     * @param gu a grid unit belonging to this cell
-     * @return the content height of the grid unit
-     */
-    private int getContentHeight(GridUnit gu) {
-        int bpd = rowHeight;
-        if (isSeparateBorderModel()) {
-            bpd -= gu.getPrimary().getBorders().getBorderBeforeWidth(false);
-            bpd -= gu.getPrimary().getBorders().getBorderAfterWidth(false);
-        } else {
-            bpd -= gu.getPrimary().getHalfMaxBorderWidth();
-        }
-        CommonBorderPaddingBackground cbpb
-            = gu.getCell().getCommonBorderPaddingBackground();
-        bpd -= cbpb.getPaddingBefore(false, this);
-        bpd -= cbpb.getPaddingAfter(false, this);
-        bpd -= 2 * ((TableLayoutManager)getParent()).getHalfBorderSeparationBPD();
-        return bpd;
-    }
-
-    /**
      * Add the areas for the break points. The cell contains block stacking layout
      * managers that add block areas.
      * 
@@ -336,99 +318,151 @@
      * of each spanned grid row
      * @param startRow first grid row on the current page spanned over by the cell,
      * inclusive
-     * @param endRow last grid row on the current page spanned over by the cell, exclusive
+     * @param endRow last grid row on the current page spanned over by the cell, inclusive
+     * @param borderBeforeWhich one of {@link ConditionalBorder#NORMAL},
+     * {@link ConditionalBorder#LEADING_TRAILING} or {@link ConditionalBorder#REST}
+     * @param borderAfterWhich one of {@link ConditionalBorder#NORMAL},
+     * {@link ConditionalBorder#LEADING_TRAILING} or {@link ConditionalBorder#REST}
+     * @param firstOnPage true if the cell will be the very first one on the page, in
+     * which case collapsed before borders must be drawn in the outer mode
+     * @param lastOnPage true if the cell will be the very last one on the page, in which
+     * case collapsed after borders must be drawn in the outer mode
      */
     public void addAreas(PositionIterator parentIter,
                          LayoutContext layoutContext,
                          int[] spannedGridRowHeights,
                          int startRow,
-                         int endRow) {
+                         int endRow,
+                         int borderBeforeWhich,
+                         int borderAfterWhich,
+                         boolean firstOnPage,
+                         boolean lastOnPage) {
         getParentArea(null);
 
         getPSLM().addIDToPage(getTableCell().getId());
 
+        int borderBeforeWidth = primaryGridUnit.getBeforeBorderWidth(startRow, borderBeforeWhich);
+        int borderAfterWidth = primaryGridUnit.getAfterBorderWidth(endRow, borderAfterWhich);
         if (isSeparateBorderModel()) {
             if (!emptyCell || getTableCell().showEmptyCells()) {
-                TraitSetter.addBorders(curBlockArea, getTableCell().getCommonBorderPaddingBackground(),
-                        false, false, false, false, this);
-                TraitSetter.addPadding(curBlockArea, getTableCell().getCommonBorderPaddingBackground(),
-                        false, false, false, false, this);
+                if (borderBeforeWidth > 0) {
+                    int halfBorderSepBPD = getTableCell().getTable().getBorderSeparation().getBPD()
+                            .getLength().getValue() / 2;
+                    adjustYOffset(curBlockArea, halfBorderSepBPD);
+                }
+                TraitSetter.addBorders(curBlockArea,
+                        getTableCell().getCommonBorderPaddingBackground(),
+                        borderBeforeWidth == 0, borderAfterWidth == 0,
+                        false, false, this);
             }
         } else {
+            boolean inFirstColumn = (primaryGridUnit.getColIndex() == 0);
+            boolean inLastColumn = (primaryGridUnit.getColIndex()
+                    + getTableCell().getNumberColumnsSpanned() == getTable()
+                    .getNumberOfColumns());
             if (!primaryGridUnit.hasSpanning()) {
+                adjustYOffset(curBlockArea, -borderBeforeWidth);
                 //Can set the borders directly if there's no span
-                boolean[] outer = new boolean[] {
-                        primaryGridUnit.getFlag(GridUnit.FIRST_IN_TABLE),
-                        primaryGridUnit.getFlag(GridUnit.LAST_IN_TABLE),
-                        primaryGridUnit.getFlag(GridUnit.IN_FIRST_COLUMN),
-                        primaryGridUnit.getFlag(GridUnit.IN_LAST_COLUMN)};
+                boolean[] outer = new boolean[] {firstOnPage, lastOnPage, inFirstColumn,
+                        inLastColumn};
                 TraitSetter.addCollapsingBorders(curBlockArea,
-                        primaryGridUnit.getBorders(), outer, this);
+                        primaryGridUnit.getBorderBefore(borderBeforeWhich),
+                        primaryGridUnit.getBorderAfter(borderAfterWhich),
+                        primaryGridUnit.getBorderStart(),
+                        primaryGridUnit.getBorderEnd(), outer);
             } else {
-                boolean[] outer = new boolean[4];
+                adjustYOffset(curBlockArea, borderBeforeWidth);
+                Block[][] blocks = new Block[getTableCell().getNumberRowsSpanned()][getTableCell()
+                        .getNumberColumnsSpanned()];
+                GridUnit[] gridUnits = (GridUnit[]) primaryGridUnit.getRows().get(startRow);
+                for (int x = 0; x < getTableCell().getNumberColumnsSpanned(); x++) {
+                    GridUnit gu = gridUnits[x];
+                    BorderInfo border = gu.getBorderBefore(borderBeforeWhich);
+                    int borderWidth = border.getRetainedWidth() / 2;
+                    if (borderWidth > 0) {
+                        addBorder(blocks, startRow, x, Trait.BORDER_BEFORE, border, firstOnPage);
+                        adjustYOffset(blocks[startRow][x], -borderWidth);
+                        adjustBPD(blocks[startRow][x], -borderWidth);
+                    }
+                }
+                gridUnits = (GridUnit[]) primaryGridUnit.getRows().get(endRow);
+                for (int x = 0; x < getTableCell().getNumberColumnsSpanned(); x++) {
+                    GridUnit gu = gridUnits[x];
+                    BorderInfo border = gu.getBorderAfter(borderAfterWhich);
+                    int borderWidth = border.getRetainedWidth() / 2;
+                    if (borderWidth > 0) {
+                        addBorder(blocks, endRow, x, Trait.BORDER_AFTER, border, lastOnPage);
+                        adjustBPD(blocks[endRow][x], -borderWidth);
+                    }
+                }
+                for (int y = startRow; y <= endRow; y++) {
+                    gridUnits = (GridUnit[]) primaryGridUnit.getRows().get(y);
+                    BorderInfo border = gridUnits[0].getBorderStart();
+                    int borderWidth = border.getRetainedWidth() / 2;
+                    if (borderWidth > 0) {
+                        addBorder(blocks, y, 0, Trait.BORDER_START, border, inFirstColumn);
+                        adjustXOffset(blocks[y][0], borderWidth);
+                        adjustIPD(blocks[y][0], -borderWidth);
+                    }
+                    border = gridUnits[gridUnits.length - 1].getBorderEnd();
+                    borderWidth = border.getRetainedWidth() / 2;
+                    if (borderWidth > 0) {
+                        addBorder(blocks, y, gridUnits.length - 1, Trait.BORDER_END, border,
+                                inLastColumn);
+                        adjustIPD(blocks[y][gridUnits.length - 1], -borderWidth);
+                    }
+                }
                 int dy = yoffset;
-                for (int y = startRow; y < endRow; y++) {
-                    GridUnit[] gridUnits = (GridUnit[])primaryGridUnit.getRows().get(y);
+                for (int y = startRow; y <= endRow; y++) {
+                    int bpd = spannedGridRowHeights[y - startRow];
                     int dx = xoffset;
                     for (int x = 0; x < gridUnits.length; x++) {
-                        GridUnit gu = gridUnits[x];
-                        if (gu.hasBorders()) {
-                            //Blocks for painting grid unit borders
-                            Block block = new Block();
-                            block.addTrait(Trait.IS_REFERENCE_AREA, Boolean.TRUE);
-                            block.setPositioning(Block.ABSOLUTE);
-    
-                            int bpd = spannedGridRowHeights[y - startRow];
-                            bpd -= gu.getBorders().getBorderBeforeWidth(false) / 2;
-                            bpd -= gu.getBorders().getBorderAfterWidth(false) / 2;
-                            block.setBPD(bpd);
-                            if (log.isTraceEnabled()) {
-                                log.trace("pgu: " + primaryGridUnit + "; gu: " + gu + "; yoffset: "
-                                        + (dy - gu.getBorders().getBorderBeforeWidth(false) / 2)
-                                        + "; bpd: " + bpd);
-                            }
-                            int ipd = gu.getColumn().getColumnWidth().getValue(
-                                    (PercentBaseContext) getParent());
-                            int borderStartWidth = gu.getBorders().getBorderStartWidth(false) / 2;
-                            ipd -= borderStartWidth;
-                            ipd -= gu.getBorders().getBorderEndWidth(false) / 2;
-                            block.setIPD(ipd);
-                            block.setXOffset(dx + borderStartWidth);
-                            block.setYOffset(dy - gu.getBorders().getBorderBeforeWidth(false) / 2);
-                            outer[0] = gu.getFlag(GridUnit.FIRST_IN_TABLE);
-                            outer[1] = gu.getFlag(GridUnit.LAST_IN_TABLE);
-                            outer[2] = gu.getFlag(GridUnit.IN_FIRST_COLUMN);
-                            outer[3] = gu.getFlag(GridUnit.IN_LAST_COLUMN);
-                            TraitSetter.addCollapsingBorders(block, gu.getBorders(), outer, this);
+                        int ipd = getTable().getColumn(primaryGridUnit.getColIndex() + x)
+                                .getColumnWidth().getValue((PercentBaseContext) getParent());
+                        if (blocks[y][x] != null) {
+                            Block block = blocks[y][x];
+                            adjustYOffset(block, dy);
+                            adjustXOffset(block, dx);
+                            adjustIPD(block, ipd);
+                            adjustBPD(block, bpd);
                             parentLM.addChildArea(block);
                         }
-                        dx += gu.getColumn().getColumnWidth().getValue(
-                                (PercentBaseContext) getParent());
+                        dx += ipd;
                     }
-                    dy += spannedGridRowHeights[y - startRow];
+                    dy += bpd;
                 }
             }
         }
-        TraitSetter.addPadding(curBlockArea, primaryGridUnit.getBorders(),
-                false, false, false, false, this);
+
+        CommonBorderPaddingBackground padding = primaryGridUnit.getCell()
+                .getCommonBorderPaddingBackground();
+        TraitSetter.addPadding(curBlockArea,
+                padding,
+                borderBeforeWhich == ConditionalBorder.REST,
+                borderAfterWhich == ConditionalBorder.REST,
+                false, false, this);
+
+        int cellBPD = rowHeight - borderBeforeWidth - borderAfterWidth;
+        cellBPD -= padding.getPaddingBefore(borderBeforeWhich == ConditionalBorder.REST, this);
+        cellBPD -= padding.getPaddingAfter(borderAfterWhich == ConditionalBorder.REST, this);
 
         //Handle display-align
-        int contentBPD = getContentHeight(primaryGridUnit);
-        if (usedBPD < contentBPD) {
+        if (usedBPD < cellBPD) {
             if (getTableCell().getDisplayAlign() == EN_CENTER) {
                 Block space = new Block();
-                space.setBPD((contentBPD - usedBPD) / 2);
+                space.setBPD((cellBPD - usedBPD) / 2);
                 curBlockArea.addBlock(space);
             } else if (getTableCell().getDisplayAlign() == EN_AFTER) {
                 Block space = new Block();
-                space.setBPD((contentBPD - usedBPD));
+                space.setBPD(cellBPD - usedBPD);
                 curBlockArea.addBlock(space);
             }
         }
 
         AreaAdditionUtil.addAreas(this, parentIter, layoutContext);
-
-        curBlockArea.setBPD(contentBPD);
+        // Re-adjust the cell's bpd as it may have been modified by the previous call
+        // for some reason (?)
+        curBlockArea.setBPD(cellBPD);
 
         // Add background after we know the BPD
         if (isSeparateBorderModel()) {
@@ -448,6 +482,34 @@
         curBlockArea = null;
     }
 
+    private void addBorder(Block[][] blocks, int i, int j, Integer side, BorderInfo border,
+            boolean outer) {
+        if (blocks[i][j] == null) {
+            blocks[i][j] = new Block();
+            blocks[i][j].addTrait(Trait.IS_REFERENCE_AREA, Boolean.TRUE);
+            blocks[i][j].setPositioning(Block.ABSOLUTE);
+        }
+        blocks[i][j].addTrait(side, new BorderProps(border.getStyle(),
+                border.getRetainedWidth(), border.getColor(),
+                outer ? BorderProps.COLLAPSE_OUTER : BorderProps.COLLAPSE_INNER));
+    }
+
+    private static void adjustXOffset(Block block, int amount) {
+        block.setXOffset(block.getXOffset() + amount);
+    }
+
+    private static void adjustYOffset(Block block, int amount) {
+        block.setYOffset(block.getYOffset() + amount);
+    }
+
+    private static void adjustIPD(Block block, int amount) {
+        block.setIPD(block.getIPD() + amount);
+    }
+
+    private static void adjustBPD(Block block, int amount) {
+        block.setBPD(block.getBPD() + amount);
+    }
+
     /**
      * Return an Area which can contain the passed childArea. The childArea
      * may not yet have any content, but it has essential traits set.
@@ -467,25 +529,10 @@
             curBlockArea.addTrait(Trait.IS_REFERENCE_AREA, Boolean.TRUE);
             TraitSetter.setProducerID(curBlockArea, getTableCell().getId());
             curBlockArea.setPositioning(Block.ABSOLUTE);
-            // set position
-            int borderAdjust = 0;
-            if (!isSeparateBorderModel()) {
-                if (primaryGridUnit.hasSpanning()) {
-                    borderAdjust -= primaryGridUnit.getHalfMaxBeforeBorderWidth();
-                } else {
-                    borderAdjust += primaryGridUnit.getHalfMaxBeforeBorderWidth();
-                }
-            } else {
-                //borderAdjust += primaryGridUnit.getBorders().getBorderBeforeWidth(false);
-            }
-            TableLayoutManager tableLM = (TableLayoutManager)getParent();
-            curBlockArea.setXOffset(xoffset + inRowIPDOffset + startIndent);
-            curBlockArea.setYOffset(yoffset - borderAdjust
-                    + tableLM.getHalfBorderSeparationBPD());
+            curBlockArea.setXOffset(xoffset + startIndent);
+            curBlockArea.setYOffset(yoffset);
             curBlockArea.setIPD(cellIPD);
-            //curBlockArea.setHeight();
 
-            // Set up dimensions
             /*Area parentArea =*/ parentLM.getParentArea(curBlockArea);
             // Get reference IPD from parentArea
             setCurrentArea(curBlockArea); // ??? for generic operations

Propchange: xmlgraphics/fop/branches/Temp_Interleaved_Page_Line_Breaking/src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java
------------------------------------------------------------------------------
--- svn:keywords (original)
+++ svn:keywords Thu Feb 14 13:55:44 2008
@@ -1 +1 @@
-Author Date Id Revision
+Id

Modified: xmlgraphics/fop/branches/Temp_Interleaved_Page_Line_Breaking/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_Interleaved_Page_Line_Breaking/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java?rev=627882&r1=627881&r2=627882&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_Interleaved_Page_Line_Breaking/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java (original)
+++ xmlgraphics/fop/branches/Temp_Interleaved_Page_Line_Breaking/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java Thu Feb 14 13:55:44 2008
@@ -19,6 +19,7 @@
 
 package org.apache.fop.layoutmgr.table;
 
+import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
@@ -32,7 +33,7 @@
 import org.apache.fop.fo.Constants;
 import org.apache.fop.fo.FObj;
 import org.apache.fop.fo.flow.table.EffRow;
-import org.apache.fop.fo.flow.table.GridUnit;
+import org.apache.fop.fo.flow.table.PrimaryGridUnit;
 import org.apache.fop.fo.flow.table.Table;
 import org.apache.fop.fo.flow.table.TableBody;
 import org.apache.fop.fo.flow.table.TableRow;
@@ -47,6 +48,7 @@
 import org.apache.fop.layoutmgr.PositionIterator;
 import org.apache.fop.layoutmgr.TraitSetter;
 import org.apache.fop.layoutmgr.SpaceResolver.SpaceHandlingBreakPosition;
+import org.apache.fop.util.BreakUtil;
 
 /**
  * Layout manager for table contents, particularly managing the creation of combined element lists.
@@ -68,7 +70,7 @@
     private int startXOffset;
     private int usedBPD;
     
-    private TableStepper stepper = new TableStepper(this);
+    private TableStepper stepper;
         
     /**
      * Main constructor
@@ -84,6 +86,7 @@
         if (table.getTableFooter() != null) {
             footerIter = new TableRowIterator(table, TableRowIterator.FOOTER);
         }
+        stepper = new TableStepper(this);
     }
     
     /**
@@ -125,7 +128,7 @@
         return this.footerList;
     }
 
-    /** @see org.apache.fop.layoutmgr.LayoutManager#getNextKnuthElements(LayoutContext, int) */
+    /** {@inheritDoc} */
     public LinkedList getNextKnuthElements(LayoutContext context, int alignment) {
         if (log.isDebugEnabled()) {
             log.debug("==> Columns: " + getTableLM().getColumns());
@@ -210,10 +213,14 @@
         while ((rowGroup = iter.getNextRowGroup()) != null) {
             RowGroupLayoutManager rowGroupLM = new RowGroupLayoutManager(getTableLM(), rowGroup,
                     stepper);
-            if (breakBetween == Constants.EN_AUTO) {
-                // TODO improve
-                breakBetween = rowGroupLM.getBreakBefore();
-            }
+             // TODO
+             // The RowGroupLM.getBreakBefore method will work correctly only after
+             // getNextKnuthElements is called. Indeed TableCellLM will set the values for
+             // breaks on PrimaryGridUnit once it has got the Knuth elements of its
+             // children. This can be changed once all the LMs adopt the same scheme of
+             // querying childrens LMs for breaks instead of producing penalty elements
+            List nextRowGroupElems = rowGroupLM.getNextKnuthElements(context, alignment, bodyType);
+            breakBetween = BreakUtil.compareBreakClasses(breakBetween, rowGroupLM.getBreakBefore());
             if (breakBetween != Constants.EN_AUTO) {
                 if (returnList.size() > 0) {
                     BreakElement breakPoss = (BreakElement) returnList.getLast();
@@ -224,7 +231,7 @@
                             0, -KnuthPenalty.INFINITE, breakBetween, context));
                 }
             }
-            returnList.addAll(rowGroupLM.getNextKnuthElements(context, alignment, bodyType));
+            returnList.addAll(nextRowGroupElems);
             breakBetween = rowGroupLM.getBreakAfter();
         }
         // Break after the table's last row
@@ -271,8 +278,8 @@
      * @param gu the grid unit
      * @return the requested X offset
      */
-    protected int getXOffsetOfGridUnit(GridUnit gu) {
-        int col = gu.getStartCol();
+    protected int getXOffsetOfGridUnit(PrimaryGridUnit gu) {
+        int col = gu.getColIndex();
         return startXOffset + getTableLM().getColumns().getXOffset(col + 1, getTableLM());
     }
     
@@ -321,9 +328,12 @@
             } else if (pos instanceof TableHFPenaltyPosition) {
                 //ignore for now, see special handling below if break is at a penalty
                 //Only if the last position in this part/page us such a position it will be used 
-            } else {
-                //leave order as is for the rest
+            } else if (pos instanceof TableContentPosition) {
                 positions.add(pos);
+            } else {
+                if (log.isDebugEnabled()) {
+                    log.debug("Ignoring position: " + pos);
+                }
             }
         }
         if (lastPos instanceof TableHFPenaltyPosition) {
@@ -349,17 +359,20 @@
             //header positions for the last part are the second-to-last element and need to
             //be handled first before all other TableContentPositions
             PositionIterator nestedIter = new KnuthPossPosIter(headerElements);
-            iterateAndPaintPositions(nestedIter, painter);
+            iterateAndPaintPositions(nestedIter, painter, false);
         }
         
         //Iterate over all steps
         Iterator posIter = positions.iterator();
-        iterateAndPaintPositions(posIter, painter);
+        painter.startBody();
+        // Here we are sure that posIter iterates only over TableContentPosition instances
+        iterateAndPaintPositions(posIter, painter, footerElements == null);
+        painter.endBody();
 
         if (footerElements != null) {
             //Positions for footers are simply added at the end
             PositionIterator nestedIter = new KnuthPossPosIter(footerElements);
-            iterateAndPaintPositions(nestedIter, painter);
+            iterateAndPaintPositions(nestedIter, painter, true);
         }
         
         this.usedBPD += painter.getAccumulatedBPD();
@@ -377,9 +390,12 @@
      * @param iterator iterator over Position elements. Those positions correspond to the
      * elements of the table present on the current page
      * @param painter
+     * @param lastOnPage true if the corresponding part will be the last on the page
+     * (either body or footer, obviously)
      */
-    private void iterateAndPaintPositions(Iterator iterator, RowPainter painter) {
-        List lst = new java.util.ArrayList();
+    private void iterateAndPaintPositions(Iterator iterator, RowPainter painter,
+            boolean lastOnPage) {
+        List lst = new ArrayList();
         boolean firstPos = false;
         TableBody body = null;
         while (iterator.hasNext()) {
@@ -392,12 +408,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
@@ -405,10 +421,6 @@
                     body = null;
                     lst.clear();
                 }
-            } else {
-                if (log.isDebugEnabled()) {
-                    log.debug("Ignoring position: " + pos);
-                }
             }
         }
         if (body != null) {
@@ -417,7 +429,7 @@
             // lastPos is necessarily false
             handleMarkersAndPositions(lst, body, firstPos, false, painter);
         }
-        painter.addAreasAndFlushRow(true);
+        painter.addAreasAndFlushRow(true, lastOnPage);
     }
 
     private void handleMarkersAndPositions(List positions, TableBody body, boolean firstPos,

Propchange: xmlgraphics/fop/branches/Temp_Interleaved_Page_Line_Breaking/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java
------------------------------------------------------------------------------
--- svn:keywords (original)
+++ svn:keywords Thu Feb 14 13:55:44 2008
@@ -1 +1 @@
-Author Date Id Revision
+Id

Modified: xmlgraphics/fop/branches/Temp_Interleaved_Page_Line_Breaking/src/java/org/apache/fop/layoutmgr/table/TableContentPosition.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_Interleaved_Page_Line_Breaking/src/java/org/apache/fop/layoutmgr/table/TableContentPosition.java?rev=627882&r1=627881&r2=627882&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_Interleaved_Page_Line_Breaking/src/java/org/apache/fop/layoutmgr/table/TableContentPosition.java (original)
+++ xmlgraphics/fop/branches/Temp_Interleaved_Page_Line_Breaking/src/java/org/apache/fop/layoutmgr/table/TableContentPosition.java Thu Feb 14 13:55:44 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;
     }
 
     /**

Propchange: xmlgraphics/fop/branches/Temp_Interleaved_Page_Line_Breaking/src/java/org/apache/fop/layoutmgr/table/TableContentPosition.java
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: xmlgraphics/fop/branches/Temp_Interleaved_Page_Line_Breaking/src/java/org/apache/fop/layoutmgr/table/TableHFPenaltyPosition.java
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: xmlgraphics/fop/branches/Temp_Interleaved_Page_Line_Breaking/src/java/org/apache/fop/layoutmgr/table/TableHeaderFooterPosition.java
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: xmlgraphics/fop/branches/Temp_Interleaved_Page_Line_Breaking/src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java
------------------------------------------------------------------------------
--- svn:keywords (original)
+++ svn:keywords Thu Feb 14 13:55:44 2008
@@ -1 +1 @@
-Author Date Id Revision
+Id

Propchange: xmlgraphics/fop/branches/Temp_Interleaved_Page_Line_Breaking/src/java/org/apache/fop/layoutmgr/table/TableRowIterator.java
------------------------------------------------------------------------------
--- svn:keywords (original)
+++ svn:keywords Thu Feb 14 13:55:44 2008
@@ -1 +1 @@
-Author Date Id Revision
+Id

Modified: xmlgraphics/fop/branches/Temp_Interleaved_Page_Line_Breaking/src/java/org/apache/fop/layoutmgr/table/TableStepper.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_Interleaved_Page_Line_Breaking/src/java/org/apache/fop/layoutmgr/table/TableStepper.java?rev=627882&r1=627881&r2=627882&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_Interleaved_Page_Line_Breaking/src/java/org/apache/fop/layoutmgr/table/TableStepper.java (original)
+++ xmlgraphics/fop/branches/Temp_Interleaved_Page_Line_Breaking/src/java/org/apache/fop/layoutmgr/table/TableStepper.java Thu Feb 14 13:55:44 2008
@@ -26,17 +26,16 @@
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.fop.fo.Constants;
-import org.apache.fop.fo.FONode;
 import org.apache.fop.fo.flow.table.EffRow;
 import org.apache.fop.fo.flow.table.GridUnit;
 import org.apache.fop.fo.flow.table.PrimaryGridUnit;
-import org.apache.fop.fo.flow.table.TableRow;
 import org.apache.fop.layoutmgr.BreakElement;
 import org.apache.fop.layoutmgr.KnuthBox;
 import org.apache.fop.layoutmgr.KnuthGlue;
 import org.apache.fop.layoutmgr.KnuthPenalty;
 import org.apache.fop.layoutmgr.LayoutContext;
 import org.apache.fop.layoutmgr.Position;
+import org.apache.fop.util.BreakUtil;
 
 /**
  * This class processes row groups to create combined element lists for tables.
@@ -52,50 +51,69 @@
     /** 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;
-    }
+    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 columnCount number of columns the row group has 
+     * @see #considerRowLastStep(int)
      */
-    private void setup(int columnCount) {
-        this.columnCount = columnCount;
-        this.activeRowIndex = 0;
-        this.previousRowsLength = 0;
-    }
+    private boolean rowHeightSmallerThanFirstStep;
 
     /**
-     * Returns the row currently being processed.
-     *
-     * @return the row currently being processed
+     * The class of the next break. One of {@link Constants#EN_AUTO},
+     * {@link Constants#EN_COLUMN}, {@link Constants#EN_PAGE},
+     * {@link Constants#EN_EVEN_PAGE}, {@link Constants#EN_ODD_PAGE}. Defaults to
+     * EN_AUTO.
      */
-    private EffRow getActiveRow() {
-        return rowGroup[activeRowIndex];
+    private int nextBreakClass;
+
+    /**
+     * Main constructor
+     * @param tclm The parent TableContentLayoutManager
+     */
+    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() {
@@ -110,30 +128,35 @@
 
     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, previousRowsLength, getTableLM()));
+            GridUnit gu = row.getGridUnit(i);
+            if (!gu.isEmpty() && gu.isPrimary()) {
+                activeCellList.add(new ActiveCell((PrimaryGridUnit) gu, row, rowIndex,
+                        previousRowsLength, getTableLM()));
             }
         }
     }
@@ -141,64 +164,60 @@
     /**
      * Creates the combined element list for a row group.
      * @param context Active LayoutContext
-     * @param rowGroup the row group
-     * @param maxColumnCount the maximum number of columns to expect
+     * @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, int maxColumnCount, int bodyType) {
-        this.rowGroup = rowGroup;
-        setup(maxColumnCount);
-        initializeElementLists();
+    public LinkedList getCombinedKnuthElementsForRowGroup(LayoutContext context, EffRow[] rows,
+            int bodyType) {
+        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 */;
 
-            boolean forcedBreak = false;
-            int breakClass = -1;
+            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));
+                }
+            }
+
             //Put all involved grid units into a list
-            List cellParts = new java.util.ArrayList(maxColumnCount);
+            List cellParts = new java.util.ArrayList(columnCount);
             for (Iterator iter = activeCells.iterator(); iter.hasNext();) {
                 ActiveCell activeCell = (ActiveCell) iter.next();
-                if (activeCell.contributesContent()) {
-                    CellPart part = activeCell.createCellPart();
-                    cellParts.add(part);
-                    forcedBreak = activeCell.isLastForcedBreak();
-                    if (forcedBreak) {
-                        breakClass = activeCell.getLastBreakClass();
-                    }
-                    if (returnList.size() == 0 && part.isFirstPart()
-                            && part.mustKeepWithPrevious()) {
-                        context.setFlags(LayoutContext.KEEP_WITH_PREVIOUS_PENDING);
-                    }
+                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);
@@ -215,48 +234,36 @@
             }
 
             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 (rowFinished && activeRowIndex < rowGroup.length - 1) {
+                nextBreakClass = BreakUtil.compareBreakClasses(nextBreakClass,
+                        rowGroup[activeRowIndex].getBreakAfter());
+                nextBreakClass = BreakUtil.compareBreakClasses(nextBreakClass,
+                        rowGroup[activeRowIndex + 1].getBreakBefore());
             }
-            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!");
-                }
+            if (nextBreakClass != Constants.EN_AUTO) {
+                log.trace("Forced break encountered");
                 p = -KnuthPenalty.INFINITE; //Overrides any keeps (see 4.8 in XSL 1.0)
             }
-            returnList.add(new BreakElement(penaltyPos, effPenaltyLen, p, breakClass, context));
+            if (rowHeightSmallerThanFirstStep) {
+                rowHeightSmallerThanFirstStep = false;
+                p = KnuthPenalty.INFINITE;
+            }
+            returnList.add(new BreakElement(penaltyPos, effPenaltyLen, p, nextBreakClass, 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.
@@ -269,23 +276,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();) {
@@ -296,32 +357,113 @@
                 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) {
+        nextBreakClass = Constants.EN_AUTO;
         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;
+            nextBreakClass = BreakUtil.compareBreakClasses(nextBreakClass,
+                    activeCell.signalNextStep(step));
+        }
+    }
+
+    /**
+     * 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.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) {
+            previousRowsLength += rowGroup[activeRowIndex].getHeight().opt;
+            activateCells(nextActiveCells, activeRowIndex + 1);
+            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() {
@@ -333,40 +475,21 @@
         }
     }
 
-    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 */

Propchange: xmlgraphics/fop/branches/Temp_Interleaved_Page_Line_Breaking/src/java/org/apache/fop/layoutmgr/table/TableStepper.java
------------------------------------------------------------------------------
--- svn:keywords (original)
+++ svn:keywords Thu Feb 14 13:55:44 2008
@@ -1 +1 @@
-Author Date Id Revision
+Id

Modified: xmlgraphics/fop/branches/Temp_Interleaved_Page_Line_Breaking/src/java/org/apache/fop/pdf/AbstractPDFStream.java
URL: http://svn.apache.org/viewvc/xmlgraphics/fop/branches/Temp_Interleaved_Page_Line_Breaking/src/java/org/apache/fop/pdf/AbstractPDFStream.java?rev=627882&r1=627881&r2=627882&view=diff
==============================================================================
--- xmlgraphics/fop/branches/Temp_Interleaved_Page_Line_Breaking/src/java/org/apache/fop/pdf/AbstractPDFStream.java (original)
+++ xmlgraphics/fop/branches/Temp_Interleaved_Page_Line_Breaking/src/java/org/apache/fop/pdf/AbstractPDFStream.java Thu Feb 14 13:55:44 2008
@@ -21,8 +21,10 @@
 
 import java.io.IOException;
 import java.io.OutputStream;
+import java.io.Writer;
 
 import org.apache.commons.io.output.CountingOutputStream;
+
 import org.apache.fop.util.CloseBlockerOutputStream;
 
 /**
@@ -169,8 +171,12 @@
      * {@inheritDoc}
      */
     protected int output(OutputStream stream) throws IOException {
-        int length = 0;
         setupFilterList();
+
+        CountingOutputStream cout = new CountingOutputStream(stream);
+        Writer writer = PDFDocument.getWriterFor(cout);
+        writer.write(getObjectID());
+        //int length = 0;
         
         StreamCache encodedStream = null;
         PDFNumber refLength = null;
@@ -184,38 +190,21 @@
             lengthEntry = new Integer(encodedStream.getSize() + 1);
         }
         
-        byte[] p = encode(buildStreamDict(lengthEntry));
-        stream.write(p);
-        length += p.length;
+        populateStreamDict(lengthEntry);
+        writeDictionary(cout, writer);
         
         //Send encoded stream to target OutputStream
+        writer.flush();
         if (encodedStream == null) {
-            int bytesWritten = encodeAndWriteStream(stream, refLength);
-            length += bytesWritten;
+            encodeAndWriteStream(cout, refLength);
         } else {
-            length += outputStreamData(encodedStream, stream);
+            outputStreamData(encodedStream, cout);
             encodedStream.clear(); //Encoded stream can now be discarded
         }
         
-        p = encode("\nendobj\n");
-        stream.write(p);
-        length += p.length;
-        return length;
-    }
-
-    /**
-     * Constructs the dictionary for the stream. Override this method if you
-     * need additional entries.
-     * @param lengthEntry value for the /Length entry
-     * @return the newly constructed dictionary
-     */
-    protected String buildStreamDict(Object lengthEntry) {
-        StringBuffer sb = new StringBuffer();
-        sb.append(getObjectID());
-        populateStreamDict(lengthEntry);
-        
-        writeDictionary(sb);
-        return sb.toString();
+        writer.write("\nendobj\n");
+        writer.flush();
+        return cout.getCount();
     }
 
     /**



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