From c046ef49bcd7519b816fc1880f97a1fad8db43c9 Mon Sep 17 00:00:00 2001 From: "Andreas L. Delmelle" Date: Tue, 6 Jun 2006 21:52:19 +0000 Subject: [PATCH] Fixes Bugzilla 39560: make sure the interaction between FOs and properties is only performed once git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@412224 13f79535-47bb-0310-9956-ffa450edef68 --- src/java/org/apache/fop/fo/flow/Table.java | 58 +++-- .../org/apache/fop/fo/flow/TableBody.java | 168 ++++++-------- .../org/apache/fop/fo/flow/TableCell.java | 218 ++++++++++-------- .../org/apache/fop/fo/flow/TableFObj.java | 20 +- src/java/org/apache/fop/fo/flow/TableRow.java | 106 ++++----- .../properties/ColumnNumberPropertyMaker.java | 71 ++---- status.xml | 9 +- test/layoutengine/disabled-testcases.xml | 6 - 8 files changed, 315 insertions(+), 341 deletions(-) diff --git a/src/java/org/apache/fop/fo/flow/Table.java b/src/java/org/apache/fop/fo/flow/Table.java index dc14f642d..6f2d7f198 100644 --- a/src/java/org/apache/fop/fo/flow/Table.java +++ b/src/java/org/apache/fop/fo/flow/Table.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2005 The Apache Software Foundation. + * Copyright 1999-2006 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -81,7 +81,7 @@ public class Table extends TableFObj { private boolean tableHeaderFound = false; private boolean tableFooterFound = false; private boolean tableBodyFound = false; - + /** * Default table-column used when no columns are specified. It is used * to handle inheritance (especially visibility) and defaults properly. */ @@ -210,7 +210,8 @@ public class Table extends TableFObj { protected void endOfNode() throws FOPException { if (!tableBodyFound) { missingChildElementError( - "(marker*,table-column*,table-header?,table-footer?,table-body+)"); + "(marker*,table-column*,table-header?,table-footer?" + + ",table-body+)"); } if (columns != null && !columns.isEmpty()) { for (int i = columns.size(); --i >= 0;) { @@ -228,13 +229,15 @@ public class Table extends TableFObj { protected void addChildNode(FONode child) throws FOPException { if ("fo:table-column".equals(child.getName())) { addColumnNode((TableColumn) child); - } else if ("fo:table-footer".equals(child.getName())) { - tableFooter = (TableBody)child; - } else if ("fo:table-header".equals(child.getName())) { - tableHeader = (TableBody)child; } else { - // add bodies - super.addChildNode(child); + if ("fo:table-footer".equals(child.getName())) { + tableFooter = (TableBody) child; + } else if ("fo:table-header".equals(child.getName())) { + tableHeader = (TableBody) child; + } else { + // add bodies + super.addChildNode(child); + } } } @@ -243,9 +246,9 @@ public class Table extends TableFObj { * used for determining initial values for column-number * * @param col the column to add - * @throws FOPException + * @throws FOPException */ - private void addColumnNode(TableColumn col) throws FOPException { + private void addColumnNode(TableColumn col) { int colNumber = col.getColumnNumber(); int colRepeat = col.getNumberColumnsRepeated(); if (columns == null) { @@ -270,13 +273,9 @@ public class Table extends TableFObj { } } //flag column indices used by this column - for (int i = colNumber - 1; i < colNumber - 1 + colRepeat; i++) { - usedColumnIndices.set(i); - } - //set index for the next column to use - while (usedColumnIndices.get(columnIndex - 1)) { - columnIndex++; - } + int startIndex = colNumber - 1; + int endIndex = startIndex + colRepeat; + flagColumnIndices(startIndex, endIndex); } /** @return true of table-layout="auto" */ @@ -299,7 +298,7 @@ public class Table extends TableFObj { * @return the requested table-body element */ public TableBody getBody(int index) { - return (TableBody)childNodes.get(index); + return (TableBody) childNodes.get(index); } /** @return the body for the table-header. */ @@ -439,7 +438,7 @@ public class Table extends TableFObj { /** * Sets the current column index of the given Table - * (used by TableColumn.bind() in case the column-number + * (used by ColumnNumberPropertyMaker.make() in case the column-number * was explicitly specified) * * @param newIndex the new value for column index @@ -448,4 +447,23 @@ public class Table extends TableFObj { columnIndex = newIndex; } + /** + * @see org.apache.fop.fo.flow.TableFObj#flagColumnIndices(int, int) + */ + protected void flagColumnIndices(int start, int end) { + for (int i = start; i < end; i++) { + usedColumnIndices.set(i); + } + //set index for the next column to use + while (usedColumnIndices.get(columnIndex - 1)) { + columnIndex++; + } + } + + /** + * @see org.apache.fop.fo.flow.TableFObj#existsUsedColumnIndices() + */ + protected boolean existsUsedColumnIndices() { + return (usedColumnIndices != null); + } } diff --git a/src/java/org/apache/fop/fo/flow/TableBody.java b/src/java/org/apache/fop/fo/flow/TableBody.java index e970fb7d9..d0b706e33 100644 --- a/src/java/org/apache/fop/fo/flow/TableBody.java +++ b/src/java/org/apache/fop/fo/flow/TableBody.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2005 The Apache Software Foundation. + * Copyright 1999-2006 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,6 +22,7 @@ package org.apache.fop.fo.flow; import java.util.BitSet; import java.util.Iterator; import java.util.List; +import java.util.ListIterator; import org.xml.sax.Locator; @@ -62,7 +63,7 @@ public class TableBody extends TableFObj { protected List pendingSpans; protected BitSet usedColumnIndices = new BitSet(); private int columnIndex = 1; - private boolean firstRow = true; + protected boolean firstRow = true; /** * @param parent FONode that is the parent of the object @@ -107,10 +108,15 @@ public class TableBody extends TableFObj { getParent().removeChild(this); } } - /* + if (tableCellsFound) { convertCellsToRows(); - }*/ + } + + //reset column index (so that it would be + //correct if the table is cloned during + //marker retrieval) + resetColumnIndex(); //release references savedPropertyList = null; pendingSpans = null; @@ -138,9 +144,10 @@ public class TableBody extends TableFObj { } else if (localName.equals("table-cell")) { tableCellsFound = true; if (tableRowsFound) { - 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 { invalidChildError(loc, nsURI, localName); @@ -150,84 +157,11 @@ public class TableBody extends TableFObj { } } - /** - * @see org.apache.fop.fo.FONode#addChildNode(FONode) - */ - protected void addChildNode(FONode child) throws FOPException { - if (child.getNameId() == FO_TABLE_CELL) { - addCellNode( (TableCell) child); - } else { - super.addChildNode(child); - } - } - - /** - * Adds a cell to the list of child nodes, and updates the columnIndex - * used for determining the initial value of column-number - * - * @param cell cell to add - * @throws FOPException - */ - private void addCellNode(TableCell cell) throws FOPException { - //if firstRow flag is still true, the cell starts a row, - //and there was a previous cell that didn't explicitly - //end the previous row => set firstRow flag to false - if (firstRow && cell.startsRow() && !lastCellEndedRow()) { - firstRow = false; - } - int rowSpan = cell.getNumberRowsSpanned(); - int colSpan = cell.getNumberColumnsSpanned(); - //if there were no explicit columns, pendingSpans - //will not be properly initialized for the first row - if (firstRow && getTable().columns == null) { - if (pendingSpans == null) { - pendingSpans = new java.util.ArrayList(); - } - for (int i = colSpan; --i >= 0;) { - pendingSpans.add(null); - } - } - //if the current cell spans more than one row, - //update pending span list for the next row - if (rowSpan > 1) { - for (int i = colSpan; --i >= 0;) { - pendingSpans.set(columnIndex - 1 + i, - new PendingSpan(rowSpan)); - } - } - //flag column indices used by this cell, - //take into account that possibly not all column-numbers - //are used by columns in the parent table (if any), - //so a cell spanning three columns, might actually - //take up more than three columnIndices... - int startIndex = columnIndex - 1; - int endIndex = startIndex + colSpan; - if (getTable().columns != null) { - List cols = getTable().columns; - int tmpIndex = endIndex; - for (int i = startIndex; i <= tmpIndex; ++i) { - if (i < cols.size() && cols.get(i) == null) { - endIndex++; - } - } - } - for (int i = startIndex; i < endIndex; i++) { - usedColumnIndices.set(i); - } - setNextColumnIndex(); - super.addChildNode(cell); - if (cell.endsRow()) { - if (firstRow) { - firstRow = false; - } - resetColumnIndex(); - } - } - /** * If table-cells are used as direct children of a table-body|header|footer * they are replaced in this method by proper table-rows. - * @throws FOPException if there's a problem binding the TableRows properties. + * @throws FOPException if there's a problem binding the TableRow's + * properties. */ private void convertCellsToRows() throws FOPException { //getLogger().debug("Converting cells to rows..."); @@ -236,14 +170,15 @@ public class TableBody extends TableFObj { Iterator i = cells.iterator(); TableRow row = null; while (i.hasNext()) { - TableCell cell = (TableCell)i.next(); + TableCell cell = (TableCell) i.next(); if (cell.startsRow() && (row != null)) { childNodes.add(row); row = null; } if (row == null) { row = new TableRow(this); - PropertyList pList = new StaticPropertyList(row, savedPropertyList); + PropertyList pList = new StaticPropertyList(row, + savedPropertyList); pList.setWritingMode(); row.bind(pList); } @@ -282,8 +217,9 @@ public class TableBody extends TableFObj { * @return true if the given table row is the first row of this body. */ public boolean isFirst(TableRow obj) { - return (childNodes.size() > 0) - && (childNodes.get(0) == obj); + return (childNodes == null + || (!childNodes.isEmpty() + && childNodes.get(0) == obj)); } /** @@ -291,15 +227,20 @@ public class TableBody extends TableFObj { * @return true if the given table row is the first row of this body. */ public boolean isLast(TableRow obj) { - return (childNodes.size() > 0) - && (childNodes.get(childNodes.size() - 1) == obj); + return (childNodes == null + || (childNodes.size() > 0 + && childNodes.get(childNodes.size() - 1) == obj)); } /** - * Initializes pending spans list; used for correctly + * Initializes list of pending row-spans; used for correctly * assigning initial value for column-number for the * cells of following rows - * + * (note: not literally mentioned in the Rec, but it is assumed + * that, if the first cell in a given row spans two rows, then + * the first cell of the following row will have an initial + * column-number of 2, since the first column is already + * occupied...) */ protected void initPendingSpans() { if (getTable().columns != null) { @@ -308,6 +249,10 @@ public class TableBody extends TableFObj { for (int i = tableCols.size(); --i >= 0;) { pendingSpans.add(null); } + } else { + if (firstRow && pendingSpans == null) { + pendingSpans = new java.util.ArrayList(); + } } } @@ -322,8 +267,8 @@ public class TableBody extends TableFObj { /** * Sets the current column index to a specific value - * (used by TableCell.bind() in case the column-number - * was explicitly specified) + * (used by ColumnNumberPropertyMaker.make() in case the + * column-number was explicitly specified on the cell) * * @param newIndex the new column index */ @@ -384,13 +329,18 @@ public class TableBody extends TableFObj { /** * Checks whether the previous cell had 'ends-row="true"' * - * @return false only if there was a previous cell, which - * had ends-row="false" (implicit or explicit) + * @param currentCell the cell for which the question is asked + * @return true if: + * a) there is a previous cell, which + * had ends-row="true" + * b) there is no previous cell (implicit + * start of row) */ - public boolean lastCellEndedRow() { - if (childNodes != null) { - FONode prevNode = (FONode) childNodes.get(childNodes.size() - 1); - if (prevNode.getNameId() == FO_TABLE_CELL) { + protected boolean lastCellEndedRow(TableCell currentCell) { + if (childNodes != null && childNodes.indexOf(currentCell) > 0) { + FONode prevNode = (FONode) childNodes.get( + childNodes.indexOf(currentCell) - 1); + if (prevNode != null && prevNode.getNameId() == FO_TABLE_CELL) { return ((TableCell) prevNode).endsRow(); } } @@ -399,13 +349,29 @@ public class TableBody extends TableFObj { /** * Checks whether a given column-number is already in use - * for the current row (used by TableCell.bind()); + * for the current row; * * @param colNr the column-number to check * @return true if column-number is already occupied */ public boolean isColumnNumberUsed(int colNr) { return usedColumnIndices.get(colNr - 1); - } + } + + /** + * @see org.apache.fop.fo.flow.TableFObj#flagColumnIndices(int, int) + */ + protected void flagColumnIndices(int start, int end) { + for (int i = start; i < end; i++) { + usedColumnIndices.set(i); + } + setNextColumnIndex(); + } + + /** + * @see org.apache.fop.fo.flow.TableFObj#existsUsedColumnIndices() + */ + protected boolean existsUsedColumnIndices() { + return (usedColumnIndices != null); + } } - diff --git a/src/java/org/apache/fop/fo/flow/TableCell.java b/src/java/org/apache/fop/fo/flow/TableCell.java index 60826da16..8f9282a5d 100644 --- a/src/java/org/apache/fop/fo/flow/TableCell.java +++ b/src/java/org/apache/fop/fo/flow/TableCell.java @@ -18,6 +18,9 @@ package org.apache.fop.fo.flow; +import java.util.BitSet; +import java.util.List; + import org.xml.sax.Locator; import org.apache.fop.apps.FOPException; @@ -94,7 +97,7 @@ public class TableCell extends TableFObj { * Set to true if all content completely laid out. */ private boolean bDone = false; - + /** * @param parent FONode that is the parent of this object */ @@ -111,7 +114,6 @@ public class TableCell extends TableFObj { commonBorderPaddingBackground = pList.getBorderPaddingBackgroundProps(); commonRelativePosition = pList.getRelativePositionProps(); blockProgressionDimension = pList.get(PR_BLOCK_PROGRESSION_DIMENSION).getLengthRange(); - columnNumber = pList.get(PR_COLUMN_NUMBER).getNumeric(); displayAlign = pList.get(PR_DISPLAY_ALIGN).getEnum(); relativeAlign = pList.get(PR_RELATIVE_ALIGN).getEnum(); emptyCells = pList.get(PR_EMPTY_CELLS).getEnum(); @@ -123,6 +125,13 @@ public class TableCell extends TableFObj { numberRowsSpanned = pList.get(PR_NUMBER_ROWS_SPANNED).getNumeric(); startsRow = pList.get(PR_STARTS_ROW).getEnum(); width = pList.get(PR_WIDTH).getLength(); + + //Check to make sure we're not in retrieve-marker context + //TODO: Can this be generalized/extended to other FOs/Properties? + if (((TableFObj) parent).existsUsedColumnIndices()) { + columnNumber = pList.get(PR_COLUMN_NUMBER).getNumeric(); + } + super.bind(pList); } @@ -144,8 +153,8 @@ public class TableCell extends TableFObj { if (getUserAgent().validateStrictly()) { missingChildElementError("marker* (%block;)+"); } else if (childNodes != null && childNodes.size() > 0) { - getLogger().warn("fo:table-cell content that is not enclosed by a " - + "fo:block will be dropped/ignored."); + getLogger().warn("fo:table-cell content that is not " + + "enclosed by a fo:block will be dropped/ignored."); } } if ((startsRow() || endsRow()) @@ -153,9 +162,112 @@ public class TableCell extends TableFObj { getLogger().warn("starts-row/ends-row for fo:table-cells " + "non-applicable for children of an fo:table-row."); } + updateParentColumnIndex(); getFOEventHandler().endCell(this); } + private void updateParentColumnIndex() { + + int rowSpan = getNumberRowsSpanned(); + int colSpan = getNumberColumnsSpanned(); + int columnIndex = ((TableFObj) parent).getCurrentColumnIndex(); + + int i = -1; + while (++i < colSpan) { + //if table has explicit columns and the column-number isn't + //assigned to any column, increment further until the next + //column is encountered + if (getTable().getColumns() != null) { + while (columnIndex <= getTable().getColumns().size() + && !getTable().isColumnNumberUsed(columnIndex)) { + columnIndex++; + } + } + //if column-number is already in use by another cell + //in the current row => error! + if (((TableFObj) parent).isColumnNumberUsed(columnIndex + i)) { + log.error("fo:table-cell overlaps in column " + + (columnIndex + i)); + } + } + + if (parent.getNameId() == FO_TABLE_ROW) { + /* parent is a fo:table-row */ + TableRow row = (TableRow) parent; + TableBody body = (TableBody) parent.getParent(); + + if (body.isFirst(row) && getTable().columns == null ) { + row.pendingSpans.add(null); + if (row.usedColumnIndices == null) { + row.usedColumnIndices = new BitSet(); + } + } + //if the current cell spans more than one row, + //update pending span list for the next row + if (rowSpan > 1) { + for (i = colSpan; --i >= 0;) { + row.pendingSpans.set(columnIndex - 1 + i, + new PendingSpan(rowSpan)); + } + } + } else { + /* parent is (should be) a fo:table-body/-header/-footer */ + TableBody body = (TableBody) parent; + + /* if body.firstRow is still true, and : + * a) the cell starts a row, + * b) there was a previous cell + * c) that previous cell didn't explicitly end the previous row + * => set firstRow flag to false + */ + if (startsRow() && body.firstRow) { + if (!body.lastCellEndedRow(this)) { + body.firstRow = false; + } + } + + /* if there were no explicit columns, pendingSpans + * will not be properly initialized for the first row... + */ + if (body.firstRow && getTable().columns == null) { + for (i = colSpan; --i >= 0;) { + body.pendingSpans.add(null); + } + } + + /* if the current cell spans more than one row, + * update pending span list for the next row + */ + if (rowSpan > 1) { + for (i = colSpan; --i >= 0;) { + body.pendingSpans.set(columnIndex - 1 + i, + new PendingSpan(rowSpan)); + } + } + } + //flag column indices used by this cell, + //take into account that possibly not all column-numbers + //are used by columns in the parent table (if any), + //so a cell spanning three columns, might actually + //take up more than three columnIndices... + int startIndex = columnIndex - 1; + int endIndex = startIndex + colSpan; + if (getTable().columns != null) { + List cols = getTable().columns; + int tmpIndex = endIndex; + for (i = startIndex; i <= tmpIndex; ++i) { + if (i < cols.size() && cols.get(i) == null) { + endIndex++; + } + } + } + ((TableFObj) parent).flagColumnIndices(startIndex, endIndex); + if (endsRow() && parent.getNameId() != FO_TABLE_ROW) { + ((TableBody) parent).firstRow = false; + ((TableBody) parent).resetColumnIndex(); + } + } + /** * @see org.apache.fop.fo.FONode#validateChildNode(Locator, String, String) * XSL Content Model: marker* (%block;)+ @@ -187,102 +299,6 @@ public class TableCell extends TableFObj { startOffset = offset; } - /** - * Calculate cell border and padding, including offset of content - * rectangle from the theoretical grid position. - */ -// TODO This whole method is not used it refers to padding which requires layout -// context to evaluate -// private void calcBorders(CommonBorderPaddingBackground bp) { -// if (this.borderCollapse == EN_SEPARATE) { -// /* -// * Easy case. -// * Cell border is the property specified directly on cell. -// * Offset content rect by half the border-separation value, -// * in addition to the border and padding values. Note: -// * border-separate should only be specified on the table object, -// * but it inherits. -// */ -// int iSep = borderSeparation.getIPD().getLength().getValue(); -// this.startAdjust = iSep / 2 + bp.getBorderStartWidth(false) -// + bp.getPaddingStart(false); -// -// this.widthAdjust = startAdjust + iSep - iSep / 2 -// + bp.getBorderEndWidth(false) -// + bp.getPaddingEnd(false); -// -// // Offset of content rectangle in the block-progression direction -// int bSep = borderSeparation.getBPD().getLength().getValue(); -// this.beforeOffset = bSep / 2 -// + bp.getBorderBeforeWidth(false) -// + bp.getPaddingBefore(false); -// -// } else { -// // System.err.println("Collapse borders"); -// /* -// * Hard case. -// * Cell border is combination of other cell borders, or table -// * border for edge cells. Also seems to border values specified -// * on row and column FO in the table (if I read CR correclty.) -// */ -// -// // Set up before and after borders, taking into account row -// // and table border properties. -// // ??? What about table-body, header,footer -// -// /* -// * We can't calculate before and after because we aren't sure -// * whether this row will be the first or last in its area, due -// * to redoing break decisions (at least in the "new" architecture.) -// * So in the general case, we will calculate two possible values: -// * the first/last one and the "middle" one. -// * Example: border-before -// * 1. If the cell is in the first row in the first table body, it -// * will combine with the last row of the header, or with the -// * top (before) table border if there is no header. -// * 2. Otherwise there are two cases: -// * a. the row is first in its (non-first) Area. -// * The border can combine with either: -// * i. the last row of table-header and its cells, or -// * ii. the table before border (no table-header or it is -// * omitted on non-first Areas). -// * b. the row isn't first in its Area. -// * The border combines with the border of the previous -// * row and the cells which end in that row. -// */ -// -// /* -// * if-first -// * Calculate the effective border of the cell before-border, -// * it's parent row before-border, the last header row after-border, -// * the after border of the cell(s) which end in the last header -// * row. -// */ -// /* -// * if-not-first -// * Calculate the effective border of the cell before-border, -// * it's parent row before-border, the previous row after-border, -// * the after border of the cell(s) which end in the previous -// * row. -// */ -// -// -// /* ivan demakov */ -// int borderStart = bp.getBorderStartWidth(false); -// int borderEnd = bp.getBorderEndWidth(false); -// int borderBefore = bp.getBorderBeforeWidth(false); -// int borderAfter = bp.getBorderAfterWidth(false); -// -// this.startAdjust = borderStart / 2 + bp.getPaddingStart(false); -// -// this.widthAdjust = startAdjust + borderEnd / 2 -// + bp.getPaddingEnd(false); -// this.beforeOffset = borderBefore / 2 + bp.getPaddingBefore(false); -// // Half border height to fix overestimate of area size! -// this.borderHeight = (borderBefore + borderAfter) / 2; -// } -// } - /** * @return the Common Border, Padding, and Background Properties. */ @@ -353,7 +369,7 @@ public class TableCell extends TableFObj { /** * @see org.apache.fop.fo.FObj#getNameId() */ - public int getNameId() { + public final int getNameId() { return FO_TABLE_CELL; } } diff --git a/src/java/org/apache/fop/fo/flow/TableFObj.java b/src/java/org/apache/fop/fo/flow/TableFObj.java index 729d5a5c2..fb2c72e1b 100644 --- a/src/java/org/apache/fop/fo/flow/TableFObj.java +++ b/src/java/org/apache/fop/fo/flow/TableFObj.java @@ -170,5 +170,23 @@ public abstract class TableFObj extends FObj { * @return the Common Border, Padding, and Background Properties. */ public abstract CommonBorderPaddingBackground getCommonBorderPaddingBackground(); - + + /** + * Flags column indices from start to end, + * and updates the current column index. + * Overridden for Table, TableBody, TableRow + * @param start start index + * @param end end index + */ + protected void flagColumnIndices(int start, int end) { + //nop + } + + /** + * Overridden for Table, TableBody, TableRow + * @return true if the usedColumnIndices BitSet exists, and is initialized + */ + protected boolean existsUsedColumnIndices() { + return false; + } } diff --git a/src/java/org/apache/fop/fo/flow/TableRow.java b/src/java/org/apache/fop/fo/flow/TableRow.java index 57da0f190..0827cf779 100644 --- a/src/java/org/apache/fop/fo/flow/TableRow.java +++ b/src/java/org/apache/fop/fo/flow/TableRow.java @@ -1,5 +1,5 @@ /* - * Copyright 1999-2005 The Apache Software Foundation. + * Copyright 1999-2006 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,9 +25,7 @@ import org.xml.sax.Locator; import org.apache.fop.apps.FOPException; import org.apache.fop.datatypes.Length; -import org.apache.fop.datatypes.Numeric; import org.apache.fop.fo.FONode; -import org.apache.fop.fo.FObj; import org.apache.fop.fo.PropertyList; import org.apache.fop.fo.ValidationException; import org.apache.fop.fo.properties.CommonAccessibility; @@ -59,8 +57,8 @@ public class TableRow extends TableFObj { private boolean setup = false; - private List pendingSpans; - private BitSet usedColumnIndices; + protected List pendingSpans; + protected BitSet usedColumnIndices; private int columnIndex = 1; /** @@ -75,7 +73,8 @@ public class TableRow extends TableFObj { */ public void bind(PropertyList pList) throws FOPException { commonAccessibility = pList.getAccessibilityProps(); - blockProgressionDimension = pList.get(PR_BLOCK_PROGRESSION_DIMENSION).getLengthRange(); + blockProgressionDimension + = pList.get(PR_BLOCK_PROGRESSION_DIMENSION).getLengthRange(); commonAural = pList.getAuralProps(); commonBorderPaddingBackground = pList.getBorderPaddingBackgroundProps(); commonRelativePosition = pList.getRelativePositionProps(); @@ -91,7 +90,8 @@ public class TableRow extends TableFObj { } /** - * Adds a cell to this row (skips marker handling done by FObj.addChildNode(). + * Adds a cell to this row (skips marker handling done by + * FObj.addChildNode(). * Used by TableBody during the row building process when only cells are * used as direct children of a table-body/header/footer. * @param cell cell to add. @@ -115,6 +115,12 @@ public class TableRow extends TableFObj { checkId(id); getFOEventHandler().startRow(this); + if (((TableBody) parent).isFirst(this) + && getTable().columns == null ) { + if (pendingSpans == null) { + pendingSpans = new java.util.ArrayList(); + } + } } /** @@ -131,6 +137,7 @@ public class TableRow extends TableFObj { ((TableBody) parent).pendingSpans = pendingSpans; } ((TableBody) parent).resetColumnIndex(); + columnIndex = 1; //release references pendingSpans = null; usedColumnIndices = null; @@ -141,64 +148,14 @@ public class TableRow extends TableFObj { * @see org.apache.fop.fo.FONode#validateChildNode(Locator, String, String) * XSL Content Model: (table-cell+) */ - protected void validateChildNode(Locator loc, String nsURI, String localName) + protected void validateChildNode(Locator loc, String nsURI, + String localName) throws ValidationException { if (!(FO_URI.equals(nsURI) && localName.equals("table-cell"))) { invalidChildError(loc, nsURI, localName); } } - /** - * @see org.apache.fop.fo.FONode#addChildNode(FONode) - */ - protected void addChildNode(FONode child) throws FOPException { - TableCell cell = (TableCell) child; - int rowSpan = cell.getNumberRowsSpanned(); - int colSpan = cell.getNumberColumnsSpanned(); - if (((TableBody) parent).isFirst(this) - && getTable().columns == null ) { - if (pendingSpans == null) { - pendingSpans = new java.util.ArrayList(); - } - pendingSpans.add(null); - if (usedColumnIndices == null) { - usedColumnIndices = new BitSet(); - } - } - //if the current cell spans more than one row, - //update pending span list for the next row - if (rowSpan > 1) { - for (int i = colSpan; --i >= 0;) { - pendingSpans.set(columnIndex - 1 + i, - new PendingSpan(rowSpan)); - } - } - //flag column indices used by this cell, - //take into account that possibly not all column-numbers - //are used by columns in the parent table (if any), - //so a cell spanning three columns, might actually - //take up more than three columnIndices... - int startIndex = columnIndex - 1; - int endIndex = startIndex + colSpan; - if (getTable().columns != null) { - List cols = getTable().columns; - int tmpIndex = endIndex; - for (int i = startIndex; i <= tmpIndex; ++i) { - if (i < cols.size() && cols.get(i) == null) { - endIndex++; - } - } - } - for (int i = startIndex; i < endIndex; i++) { - usedColumnIndices.set(i); - } - //update columnIndex for the next cell - while (usedColumnIndices.get(columnIndex - 1)) { - columnIndex++; - } - super.addChildNode(cell); - } - /** * @return the "id" property. */ @@ -232,7 +189,8 @@ public class TableRow extends TableFObj { } /** - * Convenience method to check if a keep-together constraint is specified. + * Convenience method to check if a keep-together + * constraint is specified. * @return true if keep-together is active. */ public boolean mustKeepTogether() { @@ -241,7 +199,8 @@ public class TableRow extends TableFObj { } /** - * Convenience method to check if a keep-with-next constraint is specified. + * Convenience method to check if a keep-with-next + * constraint is specified. * @return true if keep-with-next is active. */ public boolean mustKeepWithNext() { @@ -250,7 +209,8 @@ public class TableRow extends TableFObj { } /** - * Convenience method to check if a keep-with-previous constraint is specified. + * Convenience method to check if a keep-with-previous + * constraint is specified. * @return true if keep-with-previous is active. */ public boolean mustKeepWithPrevious() { @@ -301,7 +261,7 @@ public class TableRow extends TableFObj { /** * Sets the current column index to a specific value * in case a column-number was explicitly specified - * (used by TableCell.bind()) + * (used by ColumnNumberPropertyMaker.make()) * * @param newIndex new value for column index */ @@ -319,4 +279,24 @@ public class TableRow extends TableFObj { public boolean isColumnNumberUsed(int colNr) { return usedColumnIndices.get(colNr - 1); } + + /** + * @see org.apache.fop.fo.flow.TableFObj#flagColumnIndices(int, int) + */ + protected void flagColumnIndices(int start, int end) { + for (int i = start; i < end; i++) { + usedColumnIndices.set(i); + } + // update columnIndex for the next cell + while (usedColumnIndices.get(columnIndex - 1)) { + columnIndex++; + } + } + + /** + * @see org.apache.fop.fo.flow.TableFObj#existsUsedColumnIndices() + */ + protected boolean existsUsedColumnIndices() { + return (usedColumnIndices != null); + } } diff --git a/src/java/org/apache/fop/fo/properties/ColumnNumberPropertyMaker.java b/src/java/org/apache/fop/fo/properties/ColumnNumberPropertyMaker.java index f425b1a08..21af6657a 100644 --- a/src/java/org/apache/fop/fo/properties/ColumnNumberPropertyMaker.java +++ b/src/java/org/apache/fop/fo/properties/ColumnNumberPropertyMaker.java @@ -18,11 +18,14 @@ package org.apache.fop.fo.properties; +import java.util.Iterator; + import org.apache.fop.fo.Constants; import org.apache.fop.fo.FObj; import org.apache.fop.fo.PropertyList; import org.apache.fop.fo.expr.PropertyException; import org.apache.fop.fo.flow.TableBody; +import org.apache.fop.fo.flow.TableCell; import org.apache.fop.fo.flow.TableFObj; /** @@ -32,40 +35,38 @@ import org.apache.fop.fo.flow.TableFObj; */ public class ColumnNumberPropertyMaker extends NumberProperty.Maker { + /** + * Constructor + * @param propId the id of the property for which the maker should be created + */ public ColumnNumberPropertyMaker(int propId) { super(propId); } /** - * Set default column-number from parent's currentColumnIndex. - * - * @param propertyList - * @return the default value for column-number - * @throws PropertyException + * @see PropertyMaker#make(PropertyList) */ public Property make(PropertyList propertyList) throws PropertyException { FObj fo = propertyList.getFObj(); if (fo.getNameId() == Constants.FO_TABLE_CELL || fo.getNameId() == Constants.FO_TABLE_COLUMN) { - TableFObj parent = (TableFObj) propertyList.getParentFObj(); - int columnIndex = parent.getCurrentColumnIndex(); if (fo.getNameId() == Constants.FO_TABLE_CELL - && parent.getNameId() == Constants.FO_TABLE_BODY) { - boolean startsRow = propertyList.get(Constants.PR_STARTS_ROW) - .getEnum() == Constants.EN_TRUE; - - //cell w/ starts-row="true", but previous cell - //didn't have ends-row="true", so index has still has - //to be reset (for other cases this already happened in - //body.addChildNode()) - if (startsRow && !((TableBody) parent).lastCellEndedRow()) { - //reset column index, and reassign... - ((TableBody) parent).resetColumnIndex(); - columnIndex = parent.getCurrentColumnIndex(); + && fo.getParent().getNameId() != Constants.FO_TABLE_ROW + && (propertyList.get(Constants.PR_STARTS_ROW).getEnum() + == Constants.EN_TRUE)) { + TableBody parent = (TableBody) fo.getParent(); + TableCell prevCell = null; + for (Iterator i = parent.getChildNodes(); + (i != null && i.hasNext());) { + prevCell = (TableCell) i.next(); + } + if (prevCell != null && !prevCell.endsRow()) { + parent.resetColumnIndex(); } } - return new NumberProperty(columnIndex); + return new NumberProperty(((TableFObj) fo.getParent()) + .getCurrentColumnIndex()); } else { throw new PropertyException("column-number property is only allowed" + " on fo:table-cell or fo:table-column, not on " @@ -78,7 +79,8 @@ public class ColumnNumberPropertyMaker extends NumberProperty.Maker { * Return the parent's column index (initial value) in case * of a negative or zero value * - * @see org.apache.fop.fo.properties.PropertyMaker#get(int, PropertyList, boolean, boolean) + * @see org.apache.fop.fo.properties.PropertyMaker#get( + * int, PropertyList, boolean, boolean) */ public Property get(int subpropId, PropertyList propertyList, boolean tryInherit, boolean tryDefault) @@ -97,32 +99,7 @@ public class ColumnNumberPropertyMaker extends NumberProperty.Maker { return new NumberProperty(parent.getCurrentColumnIndex()); } //TODO: check for non-integer value and round - - if (fo.getNameId() == Constants.FO_TABLE_CELL) { - //check if any of the column-numbers occupied by this cell - //are already in use in the current row... - int i = -1; - int colspan = propertyList.get(Constants.PR_NUMBER_COLUMNS_SPANNED) - .getNumeric().getValue(); - while (++i < colspan) { - //if table has explicit columns and the column-number isn't - //assigned to any column, increment further until the next - //column is encountered - if (fo.getTable().getColumns() != null) { - while (columnIndex <= fo.getTable().getColumns().size() - && !fo.getTable().isColumnNumberUsed(columnIndex)) { - columnIndex++; - } - } - //if column-number is already in use by another cell - //in the current row => error! - if (parent.isColumnNumberUsed(columnIndex + i)) { - throw new PropertyException("fo:table-cell overlaps in column " - + (columnIndex + i)); - } - } - } - + //if column-number was explicitly specified, force the parent's current //column index to the specified value, so that the updated index will //be the correct initial value for the next cell/column (see Rec 7.26.8) diff --git a/status.xml b/status.xml index 86108b625..f14694fe1 100644 --- a/status.xml +++ b/status.xml @@ -27,6 +27,11 @@ + + Bugfix: the interaction between the table FOs and properties package in + determining initial values for column-number should be a one-time process, + not repeated when the table is in a marker that is retrieved. + Bugfix: All fonts names were converted unnecessarily to lower case in RTF output. @@ -196,9 +201,9 @@ Bugfix: Text-decoration was not promoted if no text-decoration attribute was specified on a nested element. - + Added support for the from-table-column() function. - (Thanks to gerhard.oettl.at.oesoft.at for the inspiration.) Bugfix: Spanned cells could lead to an false error message about overlapping diff --git a/test/layoutengine/disabled-testcases.xml b/test/layoutengine/disabled-testcases.xml index 5725a4ebd..f505f92a9 100644 --- a/test/layoutengine/disabled-testcases.xml +++ b/test/layoutengine/disabled-testcases.xml @@ -323,12 +323,6 @@ TODO: Same as table-column_first-row-width.xml? http://issues.apache.org/bugzilla/show_bug.cgi?id=35656 - - table in marker (Bug 39560) - table_in_marker_bug39560.xml - When a table is put in a marker and that is referenced using retrieve-marker, an NPE occurs during the cloning process. - http://issues.apache.org/bugzilla/show_bug.cgi?id=39560 - table-cell empty area with marker.xml table-cell_empty_area_with_marker.xml -- 2.39.5