diff options
Diffstat (limited to 'src')
17 files changed, 342 insertions, 295 deletions
diff --git a/src/java/org/apache/fop/fo/flow/table/EffRow.java b/src/java/org/apache/fop/fo/flow/table/EffRow.java index 7989f3d9d..0b00b9620 100644 --- a/src/java/org/apache/fop/fo/flow/table/EffRow.java +++ b/src/java/org/apache/fop/fo/flow/table/EffRow.java @@ -162,10 +162,65 @@ public class EffRow { } } + /** + * Returns true if the enclosing (if any) fo:table-row element of this row, or if any + * of the cells starting on this row, have keep-with-previous set. + * + * @return true if this row must be kept with the previous content + */ + public boolean mustKeepWithPrevious() { + boolean keepWithPrevious = false; + TableRow row = getTableRow(); + if (row != null) { + keepWithPrevious = row.mustKeepWithPrevious(); + } + for (Iterator iter = gridUnits.iterator(); iter.hasNext();) { + GridUnit gu = (GridUnit) iter.next(); + if (gu.isPrimary()) { + keepWithPrevious |= gu.getPrimary().mustKeepWithPrevious(); + } + } + return keepWithPrevious; + } + + /** + * Returns true if the enclosing (if any) fo:table-row element of this row, or if any + * of the cells ending on this row, have keep-with-next set. + * + * @return true if this row must be kept with the next content + */ + public boolean mustKeepWithNext() { + boolean keepWithNext = false; + TableRow row = getTableRow(); + if (row != null) { + keepWithNext = row.mustKeepWithNext(); + } + for (Iterator iter = gridUnits.iterator(); iter.hasNext();) { + GridUnit gu = (GridUnit) iter.next(); + if (!gu.isEmpty() && gu.getColSpanIndex() == 0 && gu.isLastGridUnitRowSpan()) { + keepWithNext |= gu.getPrimary().mustKeepWithNext(); + } + } + return keepWithNext; + } + + /** + * Returns true if this row is enclosed by an fo:table-row element that has + * keep-together set. + * + * @return true if this row must be kept together + */ + public boolean mustKeepTogether() { + TableRow row = getTableRow(); + return row != null && row.mustKeepTogether(); + } /** * Returns the break class for this row. This is a combination of break-before set on * the first children of any cells starting on this row. + * <p><strong>Note:</strong> this method doesn't take into account break-before set on + * the enclosing fo:table-row element, if any, as it must be ignored if the row + * belongs to a group of spanned rows (see XSL-FO 1.1, 7.20.2). * <p><strong>Note:</strong> this works only after getNextKuthElements on the * corresponding TableCellLM have been called!</p> * @@ -187,6 +242,9 @@ public class EffRow { /** * Returns the break class for this row. This is a combination of break-after set on * the last children of any cells ending on this row. + * <p><strong>Note:</strong> this method doesn't take into account break-after set on + * the enclosing fo:table-row element, if any, as it must be ignored if the row + * belongs to a group of spanned rows (see XSL-FO 1.1, 7.20.1). * <p><strong>Note:</strong> this works only after getNextKuthElements on the * corresponding TableCellLM have been called!</p> * diff --git a/src/java/org/apache/fop/fo/flow/table/EmptyGridUnit.java b/src/java/org/apache/fop/fo/flow/table/EmptyGridUnit.java index 583abcaa3..201029ff1 100644 --- a/src/java/org/apache/fop/fo/flow/table/EmptyGridUnit.java +++ b/src/java/org/apache/fop/fo/flow/table/EmptyGridUnit.java @@ -33,7 +33,8 @@ public class EmptyGridUnit extends GridUnit { * @param colIndex column index, 0-based */ EmptyGridUnit(Table table, TableRow row, int colIndex) { - super(table, row, 0, 0); + super(table, 0, 0); + setRow(row); } /** {@inheritDoc} */ diff --git a/src/java/org/apache/fop/fo/flow/table/FixedColRowGroupBuilder.java b/src/java/org/apache/fop/fo/flow/table/FixedColRowGroupBuilder.java index 62cf3e26d..28a30c6f7 100644 --- a/src/java/org/apache/fop/fo/flow/table/FixedColRowGroupBuilder.java +++ b/src/java/org/apache/fop/fo/flow/table/FixedColRowGroupBuilder.java @@ -20,6 +20,7 @@ package org.apache.fop.fo.flow.table; import java.util.ArrayList; +import java.util.Iterator; import java.util.List; import java.util.ListIterator; @@ -80,14 +81,14 @@ class FixedColRowGroupBuilder extends RowGroupBuilder { rows.add(effRow); } int columnIndex = cell.getColumnNumber() - 1; - PrimaryGridUnit pgu = new PrimaryGridUnit(cell, currentTableRow, columnIndex); + PrimaryGridUnit pgu = new PrimaryGridUnit(cell, columnIndex); List row = (List) rows.get(currentRowIndex); row.set(columnIndex, pgu); // TODO GridUnit[] cellRow = new GridUnit[cell.getNumberColumnsSpanned()]; cellRow[0] = pgu; for (int j = 1; j < cell.getNumberColumnsSpanned(); j++) { - GridUnit gu = new GridUnit(pgu, currentTableRow, j, 0); + GridUnit gu = new GridUnit(pgu, j, 0); row.set(columnIndex + j, gu); cellRow[j] = gu; } @@ -96,7 +97,7 @@ class FixedColRowGroupBuilder extends RowGroupBuilder { row = (List) rows.get(currentRowIndex + i); cellRow = new GridUnit[cell.getNumberColumnsSpanned()]; for (int j = 0; j < cell.getNumberColumnsSpanned(); j++) { - GridUnit gu = new GridUnit(pgu, currentTableRow, j, i); + GridUnit gu = new GridUnit(pgu, j, i); row.set(columnIndex + j, gu); cellRow[j] = gu; } @@ -111,21 +112,30 @@ class FixedColRowGroupBuilder extends RowGroupBuilder { } /** {@inheritDoc} */ - void startRow(TableRow tableRow) { + void startTableRow(TableRow tableRow) { currentTableRow = tableRow; } /** {@inheritDoc} */ - void endRow(TableRow row) { - if (currentRowIndex > 0 && row.getBreakBefore() != Constants.EN_AUTO) { - row.attributeWarning("break-before ignored because of row spanning " + void endTableRow() { + assert currentTableRow != null; + if (currentRowIndex > 0 && currentTableRow.getBreakBefore() != Constants.EN_AUTO) { + currentTableRow.attributeWarning("break-before ignored because of row spanning " + "in progress (See XSL 1.1, 7.20.2)"); } - if (currentRowIndex < rows.size() - 1 && row.getBreakAfter() != Constants.EN_AUTO) { - row.attributeWarning("break-after ignored because of row spanning " + if (currentRowIndex < rows.size() - 1 + && currentTableRow.getBreakAfter() != Constants.EN_AUTO) { + currentTableRow.attributeWarning("break-after ignored because of row spanning " + "in progress (See XSL 1.1, 7.20.1)"); } - handleRowEnd(row); + for (Iterator iter = ((List) rows.get(currentRowIndex)).iterator(); iter.hasNext();) { + GridUnit gu = (GridUnit) iter.next(); + // The row hasn't been filled with empty grid units yet + if (gu != null) { + gu.setRow(currentTableRow); + } + } + handleRowEnd(currentTableRow); } /** {@inheritDoc} */ @@ -174,7 +184,7 @@ class FixedColRowGroupBuilder extends RowGroupBuilder { } /** {@inheritDoc} */ - void endTable(TableBody lastTablePart) { + void endTable() { borderResolver.endTable(); } } diff --git a/src/java/org/apache/fop/fo/flow/table/GridUnit.java b/src/java/org/apache/fop/fo/flow/table/GridUnit.java index edf0c99ea..23d1cc001 100644 --- a/src/java/org/apache/fop/fo/flow/table/GridUnit.java +++ b/src/java/org/apache/fop/fo/flow/table/GridUnit.java @@ -76,12 +76,11 @@ public class GridUnit { * Creates a new grid unit. * * @param table the containing table - * @param row the table-row element this grid unit belongs to (if any) * @param colSpanIndex index of this grid unit in the span, in column direction * @param rowSpanIndex index of this grid unit in the span, in row direction */ - protected GridUnit(Table table, TableRow row, int colSpanIndex, int rowSpanIndex) { - this(row, colSpanIndex, rowSpanIndex); + protected GridUnit(Table table, int colSpanIndex, int rowSpanIndex) { + this(colSpanIndex, rowSpanIndex); setBorders(table); } @@ -89,12 +88,11 @@ public class GridUnit { * Creates a new grid unit. * * @param cell table cell which occupies this grid unit - * @param row the table-row element this grid unit belongs to (if any) * @param colSpanIndex index of this grid unit in the span, in column direction * @param rowSpanIndex index of this grid unit in the span, in row direction */ - protected GridUnit(TableCell cell, TableRow row, int colSpanIndex, int rowSpanIndex) { - this(row, colSpanIndex, rowSpanIndex); + protected GridUnit(TableCell cell, int colSpanIndex, int rowSpanIndex) { + this(colSpanIndex, rowSpanIndex); this.cell = cell; setBorders(cell.getTable()); } @@ -103,17 +101,15 @@ public class GridUnit { * Creates a new grid unit. * * @param primary the before-start grid unit of the cell containing this grid unit - * @param row the table-row element this grid unit belongs to (if any) * @param colSpanIndex index of this grid unit in the span, in column direction * @param rowSpanIndex index of this grid unit in the span, in row direction */ - GridUnit(PrimaryGridUnit primary, TableRow row, int colSpanIndex, int rowSpanIndex) { - this(primary.getCell(), row, colSpanIndex, rowSpanIndex); + GridUnit(PrimaryGridUnit primary, int colSpanIndex, int rowSpanIndex) { + this(primary.getCell(), colSpanIndex, rowSpanIndex); this.primary = primary; } - private GridUnit(TableRow row, int colSpanIndex, int rowSpanIndex) { - this.row = row; + private GridUnit(int colSpanIndex, int rowSpanIndex) { this.colSpanIndex = colSpanIndex; this.rowSpanIndex = rowSpanIndex; } @@ -165,6 +161,10 @@ public class GridUnit { return row; } + void setRow(TableRow row) { + this.row = row; + } + public TableBody getBody() { FONode node = getCell(); while (node != null && !(node instanceof TableBody)) { diff --git a/src/java/org/apache/fop/fo/flow/table/PrimaryGridUnit.java b/src/java/org/apache/fop/fo/flow/table/PrimaryGridUnit.java index c95f3f8c3..1a47a7dcf 100644 --- a/src/java/org/apache/fop/fo/flow/table/PrimaryGridUnit.java +++ b/src/java/org/apache/fop/fo/flow/table/PrimaryGridUnit.java @@ -52,6 +52,8 @@ public class PrimaryGridUnit extends GridUnit { private boolean isSeparateBorderModel; private int halfBorderSeparationBPD; + private boolean keepWithPrevious; + private boolean keepWithNext; private int breakBefore = Constants.EN_AUTO; private int breakAfter = Constants.EN_AUTO; @@ -59,11 +61,10 @@ public class PrimaryGridUnit extends GridUnit { * Creates a new primary grid unit. * * @param cell table cell which occupies this grid unit - * @param row the table-row element this grid unit belongs to (if any) * @param colIndex index of the column this grid unit belongs to, zero-based */ - PrimaryGridUnit(TableCell cell, TableRow row, int colIndex) { - super(cell, row, 0, 0); + PrimaryGridUnit(TableCell cell, int colIndex) { + super(cell, 0, 0); this.colIndex = colIndex; this.isSeparateBorderModel = cell.getTable().isSeparateBorderModel(); // TODO this.halfBorderSeparationBPD = cell.getTable().getBorderSeparation().getBPD().getLength() @@ -325,6 +326,40 @@ public class PrimaryGridUnit extends GridUnit { } /** + * Returns true if the first child block (or its descendants) of this cell has + * keep-with-previous. + * + * @return the value of keep-with-previous + */ + public boolean mustKeepWithPrevious() { + return keepWithPrevious; + } + + /** + * Don't use, reserved for TableCellLM. TODO + */ + public void setKeepWithPrevious() { + this.keepWithPrevious = true; + } + + /** + * Returns true if the last child block (or its descendants) of this cell has + * keep-with-next. + * + * @return the value of keep-with-next + */ + public boolean mustKeepWithNext() { + return keepWithNext; + } + + /** + * Don't use, reserved for TableCellLM. TODO + */ + public void setKeepWithNext() { + this.keepWithNext = true; + } + + /** * Returns the class of the before break for the first child element of this cell. * * @return one of {@link Constants#EN_AUTO}, {@link Constants#EN_COLUMN}, {@link diff --git a/src/java/org/apache/fop/fo/flow/table/RowGroupBuilder.java b/src/java/org/apache/fop/fo/flow/table/RowGroupBuilder.java index 3f7549787..c954be711 100644 --- a/src/java/org/apache/fop/fo/flow/table/RowGroupBuilder.java +++ b/src/java/org/apache/fop/fo/flow/table/RowGroupBuilder.java @@ -53,16 +53,14 @@ abstract class RowGroupBuilder { * * @param tableRow the row being started */ - abstract void startRow(TableRow tableRow); + abstract void startTableRow(TableRow tableRow); /** * Receives notification of the end of the current row. If the current row finishes * the row group, the {@link TableBody#addRowGroup(List)} method of the parent table * part will be called. - * - * @param row the row being finished */ - abstract void endRow(TableRow row); + abstract void endTableRow(); /** * Receives notification of the end of the current row, when the source contains no @@ -70,7 +68,7 @@ abstract class RowGroupBuilder { * {@link TableBody#addRowGroup(List)} method of the given table part will be called. * * <p>If the source does contain explicit fo:table-row elements, then the - * {@link #endRow(TableRow)} method will be called instead.</p> + * {@link #endTableRow()} method will be called instead.</p> * * @param part the part containing the current row */ @@ -95,8 +93,7 @@ abstract class RowGroupBuilder { /** * Receives notification of the end of the table. * - * @param lastTablePart the last part of the table * @throws ValidationException if a row-spanning cell overflows one of the table's parts */ - abstract void endTable(TableBody lastTablePart) throws ValidationException; + abstract void endTable() throws ValidationException; } diff --git a/src/java/org/apache/fop/fo/flow/table/Table.java b/src/java/org/apache/fop/fo/flow/table/Table.java index 2b6570dcc..7d6611435 100644 --- a/src/java/org/apache/fop/fo/flow/table/Table.java +++ b/src/java/org/apache/fop/fo/flow/table/Table.java @@ -126,8 +126,8 @@ public class Table extends TableFObj implements ColumnNumberManagerHolder { orphanContentLimit = pList.get(PR_X_ORPHAN_CONTENT_LIMIT).getLength(); if (!blockProgressionDimension.getOptimum(null).isAuto()) { - attributeWarning("only a value of \"auto\" for block-progression-dimension has a well-specified" - + " behavior on fo:table. Falling back to \"auto\""); + attributeWarning("only a value of \"auto\" for block-progression-dimension has a" + + " well-specified behavior on fo:table. Falling back to \"auto\""); // Anyway, the bpd of a table is not used by the layout code } if (tableLayout == EN_AUTO) { @@ -226,11 +226,7 @@ public class Table extends TableFObj implements ColumnNumberManagerHolder { + ",table-body+)"); } if (!inMarker()) { - if (tableFooter != null) { - rowGroupBuilder.endTable(tableFooter); - } else { - rowGroupBuilder.endTable((TableBody) getChildNodes().lastNode()); - } + rowGroupBuilder.endTable(); /* clean up */ for (int i = columns.size(); --i >= 0;) { TableColumn col = (TableColumn) columns.get(i); @@ -290,6 +286,7 @@ public class Table extends TableFObj implements ColumnNumberManagerHolder { } } + /** {@inheritDoc} */ protected void setCollapsedBorders() { createBorder(CommonBorderPaddingBackground.START); createBorder(CommonBorderPaddingBackground.END); diff --git a/src/java/org/apache/fop/fo/flow/table/TableBody.java b/src/java/org/apache/fop/fo/flow/table/TableBody.java index c3642c260..de7bfda84 100644 --- a/src/java/org/apache/fop/fo/flow/table/TableBody.java +++ b/src/java/org/apache/fop/fo/flow/table/TableBody.java @@ -140,7 +140,7 @@ public class TableBody extends TableCellContainer { if (!inMarker()) { RowGroupBuilder rowGroupBuilder = getTable().getRowGroupBuilder(); if (tableRowsFound) { - rowGroupBuilder.endRow(lastRow); + rowGroupBuilder.endTableRow(); } else if (!lastCellEndsRow) { rowGroupBuilder.endRow(this); } @@ -167,9 +167,9 @@ public class TableBody extends TableCellContainer { } else if (localName.equals("table-row")) { tableRowsFound = true; if (tableCellsFound) { - invalidChildError(loc, nsURI, localName, "Either fo:table-rows" + - " or fo:table-cells may be children of an " + getName() + - " but not both"); + invalidChildError(loc, nsURI, localName, "Either fo:table-rows" + + " or fo:table-cells may be children of an " + getName() + + " but not both"); } } else if (localName.equals("table-cell")) { tableCellsFound = true; @@ -198,11 +198,11 @@ public class TableBody extends TableCellContainer { getTable().getRowGroupBuilder().startTablePart(this); } else { columnNumberManager.prepareForNextRow(pendingSpans); - getTable().getRowGroupBuilder().endRow(lastRow); + getTable().getRowGroupBuilder().endTableRow(); } rowsStarted = true; lastRow = (TableRow) child; - getTable().getRowGroupBuilder().startRow(lastRow); + getTable().getRowGroupBuilder().startTableRow(lastRow); break; case FO_TABLE_CELL: if (!rowsStarted) { diff --git a/src/java/org/apache/fop/fo/flow/table/VariableColRowGroupBuilder.java b/src/java/org/apache/fop/fo/flow/table/VariableColRowGroupBuilder.java index 801153ce9..d59870f0a 100644 --- a/src/java/org/apache/fop/fo/flow/table/VariableColRowGroupBuilder.java +++ b/src/java/org/apache/fop/fo/flow/table/VariableColRowGroupBuilder.java @@ -64,19 +64,19 @@ class VariableColRowGroupBuilder extends RowGroupBuilder { } /** {@inheritDoc} */ - void startRow(final TableRow tableRow) { + void startTableRow(final TableRow tableRow) { events.add(new Event() { public void play(RowGroupBuilder rowGroupBuilder) { - rowGroupBuilder.startRow(tableRow); + rowGroupBuilder.startTableRow(tableRow); } }); } /** {@inheritDoc} */ - void endRow(final TableRow row) { + void endTableRow() { events.add(new Event() { public void play(RowGroupBuilder rowGroupBuilder) { - rowGroupBuilder.endRow(row); + rowGroupBuilder.endTableRow(); } }); } @@ -110,11 +110,11 @@ class VariableColRowGroupBuilder extends RowGroupBuilder { } /** {@inheritDoc} */ - void endTable(final TableBody lastTablePart) throws ValidationException { + void endTable() throws ValidationException { RowGroupBuilder delegate = new FixedColRowGroupBuilder(table); for (Iterator eventIter = events.iterator(); eventIter.hasNext();) { ((Event) eventIter.next()).play(delegate); } - delegate.endTable(lastTablePart); + delegate.endTable(); } } diff --git a/src/java/org/apache/fop/layoutmgr/LayoutContext.java b/src/java/org/apache/fop/layoutmgr/LayoutContext.java index beda11fe8..9eb38600b 100644 --- a/src/java/org/apache/fop/layoutmgr/LayoutContext.java +++ b/src/java/org/apache/fop/layoutmgr/LayoutContext.java @@ -133,6 +133,10 @@ public class LayoutContext { /** Amount of space to reserve at the end of each line */ private int lineEndBorderAndPaddingWidth = 0; + private int breakBefore; + + private int breakAfter; + /** * Copy constructor for creating child layout contexts. * @param parentLC the parent layout context to copy from @@ -482,7 +486,54 @@ public class LayoutContext { public void setSpaceAfter(int spaceAfter) { this.spaceAfter = spaceAfter; } - + + /** + * Returns the value of the break before the element whose + * {@link LayoutManager#getNextKnuthElements(LayoutContext, int)} method has just been + * called. + * + * @return one of {@link Constants#EN_AUTO}, {@link Constants#EN_COLUMN}, + * {@link Constants#EN_PAGE}, {@link Constants#EN_EVEN_PAGE}, or + * {@link Constants#EN_ODD_PAGE} + */ + public int getBreakBefore() { + return breakBefore; + } + + /** + * Sets the value of the break before the current element. + * + * @param breakBefore the value of the break-before + * @see #getBreakBefore() + */ + public void setBreakBefore(int breakBefore) { + this.breakBefore = breakBefore; + } + + /** + * Returns the value of the break after the element whose + * {@link LayoutManager#getNextKnuthElements(LayoutContext, int)} method has just been + * called. + * + * @return one of {@link Constants#EN_AUTO}, {@link Constants#EN_COLUMN}, + * {@link Constants#EN_PAGE}, {@link Constants#EN_EVEN_PAGE}, or + * {@link Constants#EN_ODD_PAGE} + */ + public int getBreakAfter() { + return breakAfter; + } + + + /** + * Sets the value of the break after the current element. + * + * @param breakAfter the value of the break-after + * @see #getBreakAfter() + */ + public void setBreakAfter(int breakAfter) { + this.breakAfter = breakAfter; + } + /** {@inheritDoc} */ public String toString() { return "Layout Context:" + @@ -499,7 +550,9 @@ public class LayoutContext { "\nIs Last Area: \t" + isLastArea() + "\nTry Hyphenate: \t" + tryHyphenate() + "\nKeeps: \t[" + (isKeepWithNextPending() ? "keep-with-next" : "") + "][" - + (isKeepWithPreviousPending() ? "keep-with-previous" : "") + "] pending"; + + (isKeepWithPreviousPending() ? "keep-with-previous" : "") + "] pending" + + "\nBreaks: \tforced [" + (breakBefore != Constants.EN_AUTO ? "break-before" : "") + "][" + + (breakAfter != Constants.EN_AUTO ? "break-after" : "") + "]"; } } diff --git a/src/java/org/apache/fop/layoutmgr/table/ActiveCell.java b/src/java/org/apache/fop/layoutmgr/table/ActiveCell.java index c4bff5112..c1e4ae619 100644 --- a/src/java/org/apache/fop/layoutmgr/table/ActiveCell.java +++ b/src/java/org/apache/fop/layoutmgr/table/ActiveCell.java @@ -27,7 +27,6 @@ import org.apache.commons.logging.LogFactory; import org.apache.fop.fo.Constants; import org.apache.fop.fo.flow.table.ConditionalBorder; import org.apache.fop.fo.flow.table.EffRow; -import org.apache.fop.fo.flow.table.GridUnit; import org.apache.fop.fo.flow.table.PrimaryGridUnit; import org.apache.fop.fo.properties.CommonBorderPaddingBackground; import org.apache.fop.layoutmgr.ElementListUtils; @@ -158,10 +157,6 @@ class ActiveCell { makeBoxForWholeRow = true; } } - if (pgu.isLastGridUnitRowSpan() && pgu.getRow() != null) { - makeBoxForWholeRow |= pgu.getRow().mustKeepTogether(); - makeBoxForWholeRow |= tableLM.getTable().mustKeepTogether(); - } if (makeBoxForWholeRow) { elementList = new java.util.ArrayList(1); int height = row.getHeight().opt; @@ -427,12 +422,15 @@ class ActiveCell { */ CellPart createCellPart() { if (nextStep.end + 1 == elementList.size()) { - if (pgu.getFlag(GridUnit.KEEP_WITH_NEXT_PENDING)) { - keepWithNextSignal = true; - } - if (pgu.getRow() != null && pgu.getRow().mustKeepWithNext()) { - keepWithNextSignal = true; - } + keepWithNextSignal = pgu.mustKeepWithNext(); + // TODO if keep-with-next is set on the row, must every cell of the row + // contribute some content from children blocks? + // see http://mail-archives.apache.org/mod_mbox/xmlgraphics-fop-dev/200802.mbox/ + // %3c47BDA379.4050606@anyware-tech.com%3e + // Assuming no, but if yes the following code should enable this behaviour +// if (pgu.getRow() != null && pgu.getRow().mustKeepWithNext()) { +// keepWithNextSignal = true; +// } } int bpBeforeFirst; if (nextStep.start == 0) { diff --git a/src/java/org/apache/fop/layoutmgr/table/CellPart.java b/src/java/org/apache/fop/layoutmgr/table/CellPart.java index 2adb543a9..560b70344 100644 --- a/src/java/org/apache/fop/layoutmgr/table/CellPart.java +++ b/src/java/org/apache/fop/layoutmgr/table/CellPart.java @@ -19,7 +19,6 @@ package org.apache.fop.layoutmgr.table; -import org.apache.fop.fo.flow.table.GridUnit; import org.apache.fop.fo.flow.table.PrimaryGridUnit; /** @@ -126,9 +125,4 @@ class CellPart { return sb.toString(); } - boolean mustKeepWithPrevious() { - return pgu.getFlag(GridUnit.KEEP_WITH_PREVIOUS_PENDING) - || (pgu.getRow() != null && pgu.getRow().mustKeepWithPrevious()); - } - } diff --git a/src/java/org/apache/fop/layoutmgr/table/RowGroupLayoutManager.java b/src/java/org/apache/fop/layoutmgr/table/RowGroupLayoutManager.java index 0127f4d81..c2e26e18d 100644 --- a/src/java/org/apache/fop/layoutmgr/table/RowGroupLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/table/RowGroupLayoutManager.java @@ -32,19 +32,15 @@ import org.apache.fop.fo.flow.table.PrimaryGridUnit; import org.apache.fop.fo.flow.table.TableRow; import org.apache.fop.fo.properties.CommonBorderPaddingBackground; import org.apache.fop.fo.properties.LengthRangeProperty; -import org.apache.fop.layoutmgr.BreakElement; import org.apache.fop.layoutmgr.ElementListObserver; -import org.apache.fop.layoutmgr.KnuthElement; -import org.apache.fop.layoutmgr.KnuthPenalty; import org.apache.fop.layoutmgr.LayoutContext; -import org.apache.fop.layoutmgr.ListElement; import org.apache.fop.layoutmgr.MinOptMaxUtil; import org.apache.fop.traits.MinOptMax; import org.apache.fop.util.BreakUtil; class RowGroupLayoutManager { - private static Log log = LogFactory.getLog(TableContentLayoutManager.class); + private static Log log = LogFactory.getLog(RowGroupLayoutManager.class); private EffRow[] rowGroup; @@ -59,71 +55,30 @@ class RowGroupLayoutManager { this.tableStepper = tableStepper; } - /** - * - * @return one of {@link Constants#EN_AUTO}, {@link Constants#EN_COLUMN}, - * {@link Constants#EN_PAGE}, {@link Constants#EN_EVEN_PAGE}, or - * {@link Constants#EN_ODD_PAGE} - */ - int getBreakBefore() { - TableRow rowFO = rowGroup[0].getTableRow(); - int breakBefore; - if (rowFO == null) { - breakBefore = Constants.EN_AUTO; - } else { - breakBefore = rowFO.getBreakBefore(); - } - return BreakUtil.compareBreakClasses(breakBefore, rowGroup[0].getBreakBefore()); - } - - /** - * - * @return one of {@link Constants#EN_AUTO}, {@link Constants#EN_COLUMN}, - * {@link Constants#EN_PAGE}, {@link Constants#EN_EVEN_PAGE}, or - * {@link Constants#EN_ODD_PAGE} - */ - int getBreakAfter() { - TableRow rowFO = rowGroup[rowGroup.length - 1].getTableRow(); - int breakAfter; - if (rowFO == null) { - breakAfter = Constants.EN_AUTO; - } else { - breakAfter = rowFO.getBreakAfter(); - } - return BreakUtil.compareBreakClasses(breakAfter, - rowGroup[rowGroup.length - 1].getBreakAfter()); - } - public LinkedList getNextKnuthElements(LayoutContext context, int alignment, int bodyType) { LinkedList returnList = new LinkedList(); - - //Reset keep-with-next when remaining inside the table. - //The context flag is only used to propagate keep-with-next to the outside. - //The clearing is ok here because createElementsForRowGroup already handles - //the keep when inside a table. - context.setFlags(LayoutContext.KEEP_WITH_NEXT_PENDING, false); - - //Element list creation createElementsForRowGroup(context, alignment, bodyType, returnList); - //Handle keeps - if (context.isKeepWithNextPending()) { - log.debug("child LM (row group) signals pending keep-with-next"); + context.setFlags(LayoutContext.KEEP_WITH_PREVIOUS_PENDING, + rowGroup[0].mustKeepWithPrevious()); + context.setFlags(LayoutContext.KEEP_WITH_NEXT_PENDING, + rowGroup[rowGroup.length - 1].mustKeepWithNext()); + + int breakBefore = Constants.EN_AUTO; + TableRow firstRow = rowGroup[0].getTableRow(); + if (firstRow != null) { + breakBefore = firstRow.getBreakBefore(); } - if (context.isKeepWithPreviousPending()) { - log.debug("child LM (row group) signals pending keep-with-previous"); - if (returnList.size() > 0) { - //Modify last penalty - ListElement last = (ListElement)returnList.getLast(); - if (last.isPenalty()) { - BreakElement breakPoss = (BreakElement)last; - //Only honor keep if there's no forced break - if (!breakPoss.isForcedBreak()) { - breakPoss.setPenaltyValue(KnuthPenalty.INFINITE); - } - } - } + context.setBreakBefore(BreakUtil.compareBreakClasses(breakBefore, + rowGroup[0].getBreakBefore())); + + int breakAfter = Constants.EN_AUTO; + TableRow lastRow = rowGroup[rowGroup.length - 1].getTableRow(); + if (lastRow != null) { + breakAfter = lastRow.getBreakAfter(); } + context.setBreakAfter(BreakUtil.compareBreakClasses(breakAfter, + rowGroup[rowGroup.length - 1].getBreakAfter())); return returnList; } @@ -162,7 +117,8 @@ class RowGroupLayoutManager { PrimaryGridUnit primary = gu.getPrimary(); if (gu.isPrimary()) { - primary.createCellLM(); // TODO a new LM must be created for every new static-content + // TODO a new LM must be created for every new static-content + primary.createCellLM(); primary.getCellLM().setParent(tableLM); //Determine the table-row if any @@ -198,24 +154,7 @@ class RowGroupLayoutManager { LinkedList elems = primary.getCellLM().getNextKnuthElements( childLC, alignment); ElementListObserver.observe(elems, "table-cell", primary.getCell().getId()); - - if ((elems.size() > 0) - && ((KnuthElement)elems.getLast()).isForcedBreak()) { - // a descendant of this block has break-after - log.debug("Descendant of table-cell signals break: " - + primary.getCellLM().isFinished()); - } - primary.setElements(elems); - - if (childLC.isKeepWithNextPending()) { - log.debug("child LM signals pending keep-with-next"); - primary.setFlag(GridUnit.KEEP_WITH_NEXT_PENDING, true); - } - if (childLC.isKeepWithPreviousPending()) { - log.debug("child LM signals pending keep-with-previous"); - primary.setFlag(GridUnit.KEEP_WITH_PREVIOUS_PENDING, true); - } } //Calculate height of row, see CSS21, 17.5.3 Table height algorithms @@ -284,11 +223,8 @@ class RowGroupLayoutManager { log.debug(" height=" + rowHeights[i] + " explicit=" + explicitRowHeights[i]); } } - LinkedList returnedList = tableStepper.getCombinedKnuthElementsForRowGroup(context, + LinkedList elements = tableStepper.getCombinedKnuthElementsForRowGroup(context, rowGroup, bodyType); - if (returnedList != null) { - returnList.addAll(returnedList); - } - + returnList.addAll(elements); } } diff --git a/src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java b/src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java index fbc118723..289785d68 100644 --- a/src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java @@ -173,7 +173,7 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager log.debug("child LM signals pending keep with next"); } if (contentList.size() == 0 && childLC.isKeepWithPreviousPending()) { - context.setFlags(LayoutContext.KEEP_WITH_PREVIOUS_PENDING); + primaryGridUnit.setKeepWithPrevious(); childLC.setFlags(LayoutContext.KEEP_WITH_PREVIOUS_PENDING, false); } @@ -233,6 +233,9 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager } prevLM = curLM; } + if (context.isKeepWithNextPending()) { + primaryGridUnit.setKeepWithNext(); + } returnedList = new LinkedList(); if (contentList.size() > 0) { diff --git a/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java b/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java index c09b9b076..b9a118e28 100644 --- a/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java @@ -40,7 +40,7 @@ import org.apache.fop.fo.flow.table.TableRow; import org.apache.fop.layoutmgr.BreakElement; import org.apache.fop.layoutmgr.ElementListUtils; import org.apache.fop.layoutmgr.KnuthBox; -import org.apache.fop.layoutmgr.KnuthPenalty; +import org.apache.fop.layoutmgr.KnuthElement; import org.apache.fop.layoutmgr.KnuthPossPosIter; import org.apache.fop.layoutmgr.LayoutContext; import org.apache.fop.layoutmgr.ListElement; @@ -107,7 +107,7 @@ public class TableContentLayoutManager implements PercentBaseContext { ColumnSetup getColumns() { return getTableLM().getColumns(); } - + /** @return the net header height */ protected int getHeaderNetHeight() { return this.headerNetHeight; @@ -208,56 +208,57 @@ public class TableContentLayoutManager implements PercentBaseContext { private LinkedList getKnuthElementsForRowIterator(TableRowIterator iter, LayoutContext context, int alignment, int bodyType) { LinkedList returnList = new LinkedList(); - EffRow[] rowGroup = null; - int breakBetween = Constants.EN_AUTO; - while ((rowGroup = iter.getNextRowGroup()) != null) { + EffRow[] rowGroup = iter.getNextRowGroup(); + // TODO homogenize the handling of keeps and breaks + context.unsetFlags(LayoutContext.KEEP_WITH_PREVIOUS_PENDING + | LayoutContext.KEEP_WITH_NEXT_PENDING); + context.setBreakBefore(Constants.EN_AUTO); + context.setBreakAfter(Constants.EN_AUTO); + boolean keepWithPrevious = false; + int breakBefore = Constants.EN_AUTO; + if (rowGroup != null) { RowGroupLayoutManager rowGroupLM = new RowGroupLayoutManager(getTableLM(), rowGroup, stepper); - // 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(); - breakPoss.setPenaltyValue(-KnuthPenalty.INFINITE); - breakPoss.setBreakClass(breakBetween); - } else { - returnList.add(new BreakElement(new Position(tableLM), - 0, -KnuthPenalty.INFINITE, breakBetween, context)); - } - } + keepWithPrevious = context.isKeepWithPreviousPending(); + boolean keepBetween = context.isKeepWithNextPending(); + breakBefore = context.getBreakBefore(); + int breakBetween = context.getBreakAfter(); returnList.addAll(nextRowGroupElems); - breakBetween = rowGroupLM.getBreakAfter(); - } - // Break after the table's last row - // TODO should eventually be handled at the table level - if (breakBetween != Constants.EN_AUTO) { - if (returnList.size() > 0 && ((ListElement) returnList.getLast()).isPenalty()) { - // May be a glue if the unbroken height is greater than the broken heights - BreakElement breakPoss = (BreakElement) returnList.getLast(); - breakPoss.setPenaltyValue(-KnuthPenalty.INFINITE); - breakPoss.setBreakClass(breakBetween); - } else { - returnList.add(new BreakElement(new Position(tableLM), - 0, -KnuthPenalty.INFINITE, breakBetween, context)); - } - } - if (returnList.size() > 0) { - //Remove the last penalty produced by the combining algorithm (see TableStepper), - //for the last step - ListElement last = (ListElement)returnList.getLast(); - if (last.isPenalty() || last instanceof BreakElement) { - if (!last.isForcedBreak()) { - //Only remove if we don't signal a forced break - returnList.removeLast(); + while ((rowGroup = iter.getNextRowGroup()) != null) { + rowGroupLM = new RowGroupLayoutManager(getTableLM(), rowGroup, stepper); + nextRowGroupElems = rowGroupLM.getNextKnuthElements(context, alignment, bodyType); + int penaltyValue = 0; + keepBetween |= context.isKeepWithPreviousPending(); + if (keepBetween || tableLM.getTable().mustKeepTogether()) { + penaltyValue = KnuthElement.INFINITE; + } + breakBetween = BreakUtil.compareBreakClasses(breakBetween, + context.getBreakBefore()); + if (breakBetween != Constants.EN_AUTO) { + penaltyValue = -KnuthElement.INFINITE; + } + TableHFPenaltyPosition penaltyPos = new TableHFPenaltyPosition(getTableLM()); + int penaltyLen = 0; + if (bodyType == TableRowIterator.BODY) { + if (!getTableLM().getTable().omitHeaderAtBreak()) { + penaltyLen += getHeaderNetHeight(); + penaltyPos.headerElements = getHeaderElements(); + } + if (!getTableLM().getTable().omitFooterAtBreak()) { + penaltyLen += getFooterNetHeight(); + penaltyPos.footerElements = getFooterElements(); + } } + returnList.add(new BreakElement(penaltyPos, + penaltyLen, penaltyValue, breakBetween, context)); + returnList.addAll(nextRowGroupElems); + breakBetween = context.getBreakAfter(); + keepBetween = context.isKeepWithNextPending(); } } + context.setFlags(LayoutContext.KEEP_WITH_PREVIOUS_PENDING, keepWithPrevious); + context.setBreakBefore(breakBefore); //fox:widow-content-limit int widowContentLimit = getTableLM().getTable().getWidowContentLimit().getValue(); diff --git a/src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java b/src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java index 2e366f36d..1cbc3e50a 100644 --- a/src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java +++ b/src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java @@ -19,31 +19,32 @@ package org.apache.fop.layoutmgr.table; +import java.util.Iterator; +import java.util.LinkedList; + import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.apache.fop.area.Area; +import org.apache.fop.area.Block; +import org.apache.fop.datatypes.LengthBase; +import org.apache.fop.fo.Constants; +import org.apache.fop.fo.FONode; +import org.apache.fop.fo.FObj; import org.apache.fop.fo.flow.table.Table; import org.apache.fop.fo.flow.table.TableColumn; import org.apache.fop.layoutmgr.BlockStackingLayoutManager; +import org.apache.fop.layoutmgr.BreakElement; import org.apache.fop.layoutmgr.ConditionalElementListener; import org.apache.fop.layoutmgr.KnuthElement; import org.apache.fop.layoutmgr.KnuthGlue; import org.apache.fop.layoutmgr.LayoutContext; import org.apache.fop.layoutmgr.ListElement; -import org.apache.fop.layoutmgr.NonLeafPosition; import org.apache.fop.layoutmgr.PositionIterator; -import org.apache.fop.layoutmgr.Position; import org.apache.fop.layoutmgr.RelSide; import org.apache.fop.layoutmgr.TraitSetter; -import org.apache.fop.area.Area; -import org.apache.fop.area.Block; import org.apache.fop.traits.MinOptMax; import org.apache.fop.traits.SpaceVal; - -import java.util.Iterator; -import java.util.LinkedList; -import org.apache.fop.datatypes.LengthBase; -import org.apache.fop.fo.FONode; -import org.apache.fop.fo.FObj; +import org.apache.fop.util.BreakUtil; /** * LayoutManager for a table FO. @@ -150,25 +151,11 @@ public class TableLayoutManager extends BlockStackingLayoutManager public int getHalfBorderSeparationIPD() { return halfBorderSeparationIPD; } - - /** - * Handles the Knuth elements at the table level: mainly breaks, spaces and borders - * before and after the table. The Knuth elements for the table cells are handled by - * TableContentLayoutManager. - * - * @see org.apache.fop.layoutmgr.LayoutManager - * @see TableContentLayoutManager#getNextKnuthElements(LayoutContext, int) - */ + + /** {@inheritDoc} */ public LinkedList getNextKnuthElements(LayoutContext context, int alignment) { LinkedList returnList = new LinkedList(); - - if (!breakBeforeServed) { - breakBeforeServed = true; - if (addKnuthElementsForBreakBefore(returnList, context)) { - return returnList; - } - } /* * Compute the IPD and adjust it if necessary (overconstrained) @@ -225,10 +212,7 @@ public class TableLayoutManager extends BlockStackingLayoutManager // Elements for the table-header/footer/body LinkedList contentKnuthElements = null; - LinkedList contentList = new LinkedList(); - //Position returnPosition = new NonLeafPosition(this, null); - //Body prevLM = null; - + contentLM = new TableContentLayoutManager(this); LayoutContext childLC = new LayoutContext(0); /* childLC.setStackLimit( @@ -237,46 +221,7 @@ public class TableLayoutManager extends BlockStackingLayoutManager childLC.setRefIPD(context.getRefIPD()); childLC.copyPendingMarksFrom(context); - if (contentLM == null) { - contentLM = new TableContentLayoutManager(this); - } contentKnuthElements = contentLM.getNextKnuthElements(childLC, alignment); - if (childLC.isKeepWithNextPending()) { - log.debug("TableContentLM signals pending keep-with-next"); - context.setFlags(LayoutContext.KEEP_WITH_NEXT_PENDING); - } - if (childLC.isKeepWithPreviousPending()) { - log.debug("TableContentLM signals pending keep-with-previous"); - context.setFlags(LayoutContext.KEEP_WITH_PREVIOUS_PENDING); - } - - // Check if the table's content starts/ends with a forced break - // TODO this is hacky and will need to be handled better eventually - if (contentKnuthElements.size() > 0) { - ListElement element = (ListElement)contentKnuthElements.getFirst(); - if (element.isForcedBreak()) { - // The first row of the table(-body), or (the content of) one of its cells - // has a forced break-before - int breakBeforeTable = ((Table) fobj).getBreakBefore(); - if (breakBeforeTable == EN_PAGE - || breakBeforeTable == EN_COLUMN - || breakBeforeTable == EN_EVEN_PAGE - || breakBeforeTable == EN_ODD_PAGE) { - // There is already a forced break before the table; remove this one - // to prevent a double break - contentKnuthElements.removeFirst(); - } else { - element.setPosition(new NonLeafPosition(this, null)); - } - } - element = (ListElement)contentKnuthElements.getLast(); - if (element.isForcedBreak()) { - // The last row of the table(-body), or (the content of) one of its cells - // has a forced break-after - element.setPosition(new NonLeafPosition(this, null)); - } - } - //Set index values on elements coming from the content LM Iterator iter = contentKnuthElements.iterator(); while (iter.hasNext()) { @@ -284,19 +229,36 @@ public class TableLayoutManager extends BlockStackingLayoutManager notifyPos(el.getPosition()); } log.debug(contentKnuthElements); - contentList.addAll(contentKnuthElements); - wrapPositionElements(contentList, returnList); + wrapPositionElements(contentKnuthElements, returnList); + + if (mustKeepWithPrevious() || childLC.isKeepWithPreviousPending()) { + context.setFlags(LayoutContext.KEEP_WITH_PREVIOUS_PENDING); + } + if (mustKeepWithNext() || childLC.isKeepWithNextPending()) { + context.setFlags(LayoutContext.KEEP_WITH_NEXT_PENDING); + } + if (getTable().isSeparateBorderModel()) { addKnuthElementsForBorderPaddingAfter(returnList, true); } addKnuthElementsForSpaceAfter(returnList, alignment); - addKnuthElementsForBreakAfter(returnList, context); - if (mustKeepWithNext()) { - context.setFlags(LayoutContext.KEEP_WITH_NEXT_PENDING); + + //addKnuthElementsForBreakBefore(returnList, context); + int breakBefore = BreakUtil.compareBreakClasses(getTable().getBreakBefore(), + childLC.getBreakBefore()); + if (breakBefore != Constants.EN_AUTO) { + returnList.addFirst(new BreakElement(getAuxiliaryPosition(), + 0, -KnuthElement.INFINITE, breakBefore, context)); } - if (mustKeepWithPrevious()) { - context.setFlags(LayoutContext.KEEP_WITH_PREVIOUS_PENDING); + + //addKnuthElementsForBreakAfter(returnList, context); + int breakAfter = BreakUtil.compareBreakClasses(getTable().getBreakAfter(), + childLC.getBreakAfter()); + if (breakAfter != Constants.EN_AUTO) { + returnList.add(new BreakElement(getAuxiliaryPosition(), + 0, -KnuthElement.INFINITE, breakAfter, context)); } + setFinished(true); resetSpaces(); return returnList; diff --git a/src/java/org/apache/fop/layoutmgr/table/TableStepper.java b/src/java/org/apache/fop/layoutmgr/table/TableStepper.java index 2560b3aac..ba67e38e4 100644 --- a/src/java/org/apache/fop/layoutmgr/table/TableStepper.java +++ b/src/java/org/apache/fop/layoutmgr/table/TableStepper.java @@ -174,7 +174,6 @@ public class TableStepper { activateCells(activeCells, 0); calcTotalHeight(); - boolean signalKeepWithNext = false; int cumulateLength = 0; // Length of the content accumulated before the break TableContentPosition lastTCPos = null; LinkedList returnList = new LinkedList(); @@ -202,10 +201,6 @@ public class TableStepper { ActiveCell activeCell = (ActiveCell) iter.next(); CellPart part = activeCell.createCellPart(); cellParts.add(part); - if (returnList.size() == 0 && part.isFirstPart() - && part.mustKeepWithPrevious()) { - context.setFlags(LayoutContext.KEEP_WITH_PREVIOUS_PENDING); - } } //Create elements for step @@ -234,15 +229,23 @@ public class TableStepper { } int p = 0; - signalKeepWithNext = false; + boolean keepWithNext = false; for (Iterator iter = activeCells.iterator(); iter.hasNext();) { ActiveCell activeCell = (ActiveCell) iter.next(); - signalKeepWithNext |= activeCell.keepWithNextSignal(); + keepWithNext |= activeCell.keepWithNextSignal(); } - if (signalKeepWithNext || getTableLM().mustKeepTogether()) { + if (keepWithNext || getTableLM().mustKeepTogether()) { p = KnuthPenalty.INFINITE; } - if (rowFinished && activeRowIndex < rowGroup.length - 1) { + if (!rowFinished) { + if (rowGroup[activeRowIndex].mustKeepTogether()) { + p = KnuthPenalty.INFINITE; + } + } else if (activeRowIndex < rowGroup.length - 1) { + if (rowGroup[activeRowIndex].mustKeepWithNext() + || rowGroup[activeRowIndex + 1].mustKeepWithPrevious()) { + p = KnuthPenalty.INFINITE; + } nextBreakClass = BreakUtil.compareBreakClasses(nextBreakClass, rowGroup[activeRowIndex].getBreakAfter()); nextBreakClass = BreakUtil.compareBreakClasses(nextBreakClass, @@ -264,13 +267,12 @@ public class TableStepper { 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. - context.setFlags(LayoutContext.KEEP_WITH_NEXT_PENDING); - } - if (lastTCPos != null) { + if (!returnList.isEmpty()) { lastTCPos.setFlag(TableContentPosition.LAST_IN_ROWGROUP, true); + // It's not up to TableStepper to decide whether there can/must be a break + // after the row group or not, but to ancestor stacking elements + assert returnList.getLast() instanceof BreakElement; + returnList.removeLast(); } return returnList; } |