From 77c8566a57472e33049c8e02dd753dd79944e2ad Mon Sep 17 00:00:00 2001
From: Vincent Hennebert
Date: Wed, 5 Mar 2008 18:22:06 +0000
Subject: [PATCH] - Fixed the rendering of the area of a table corresponding to
border-separation, which must be filled with the background of the table, and
not the rows. - Improved conformance: even if a table-cell spans several rows
its background must correspond to the first row spanned. - Added support for
background on fo:table-column and fo:table-header/footer/body TODO more
testcases needed, especially tables with collapsing border model and tables
broken over pages
git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@633961 13f79535-47bb-0310-9956-ffa450edef68
---
.../org/apache/fop/layoutmgr/TraitSetter.java | 86 +++-
.../fop/layoutmgr/table/RowPainter.java | 93 ++++-
.../table/TableCellLayoutManager.java | 85 ++--
.../table/TableContentLayoutManager.java | 164 +++-----
.../layoutmgr/table/TableContentPosition.java | 5 +
.../layoutmgr/table/TableLayoutManager.java | 69 ++-
status.xml | 11 +
.../table-cell_conditional-spaces_2.xml | 64 +--
.../table-footer_omit-footer-at-break.xml | 38 +-
.../table-header_omit-header-at-break.xml | 34 +-
.../table-header_table-footer_1.xml | 40 +-
.../table-header_table-footer_2.xml | 46 +-
.../table-row_background-image.xml | 20 +-
.../standard-testcases/table-row_height.xml | 34 +-
.../standard-testcases/table_backgrounds.xml | 392 ++++++++++++++++++
15 files changed, 930 insertions(+), 251 deletions(-)
create mode 100644 test/layoutengine/standard-testcases/table_backgrounds.xml
diff --git a/src/java/org/apache/fop/layoutmgr/TraitSetter.java b/src/java/org/apache/fop/layoutmgr/TraitSetter.java
index 841a94705..189212eb8 100644
--- a/src/java/org/apache/fop/layoutmgr/TraitSetter.java
+++ b/src/java/org/apache/fop/layoutmgr/TraitSetter.java
@@ -280,6 +280,90 @@ public class TraitSetter {
}
}
+ /**
+ * Add background to an area. This method is mainly used by table-related layout
+ * managers to add background for column, body or row. Since the area corresponding to
+ * border-separation must be filled with the table's background, for every cell an
+ * additional area with the same dimensions is created to hold the background for the
+ * corresponding column/body/row. An additional shift must then be added to
+ * background-position-horizontal/vertical to ensure the background images are
+ * correctly placed. Indeed the placement of images must be made WRT the
+ * column/body/row and not the cell.
+ *
+ * Note: The area's IPD and BPD must be set before calling this method.
+ *
+ * TODO the regular
+ * {@link #addBackground(Area, CommonBorderPaddingBackground, PercentBaseContext)}
+ * method should be used instead, and a means to retrieve the original area's
+ * dimensions must be found.
+ *
+ * TODO the placement of images in the x- or y-direction will be incorrect if
+ * background-repeat is set for that direction.
+ *
+ * @param area the area to set the traits on
+ * @param backProps the background properties
+ * @param context Property evaluation context
+ * @param ipdShift horizontal shift to affect to the background, in addition to the
+ * value of the background-position-horizontal property
+ * @param bpdShift vertical shift to affect to the background, in addition to the
+ * value of the background-position-vertical property
+ * @param referenceIPD value to use as a reference for percentage calculation
+ * @param referenceBPD value to use as a reference for percentage calculation
+ */
+ public static void addBackground(Area area,
+ CommonBorderPaddingBackground backProps,
+ PercentBaseContext context,
+ int ipdShift, int bpdShift, int referenceIPD, int referenceBPD) {
+ if (!backProps.hasBackground()) {
+ return;
+ }
+ Trait.Background back = new Trait.Background();
+ back.setColor(backProps.backgroundColor);
+
+ if (backProps.getImageInfo() != null) {
+ back.setURL(backProps.backgroundImage);
+ back.setImageInfo(backProps.getImageInfo());
+ back.setRepeat(backProps.backgroundRepeat);
+ if (backProps.backgroundPositionHorizontal != null) {
+ if (back.getRepeat() == Constants.EN_NOREPEAT
+ || back.getRepeat() == Constants.EN_REPEATY) {
+ if (area.getIPD() > 0) {
+ PercentBaseContext refContext = new SimplePercentBaseContext(context,
+ LengthBase.IMAGE_BACKGROUND_POSITION_HORIZONTAL,
+ (referenceIPD - back.getImageInfo().getSize().getWidthMpt()));
+
+ back.setHoriz(ipdShift
+ + backProps.backgroundPositionHorizontal.getValue(refContext));
+ } else {
+ // TODO Area IPD has to be set for this to work
+ log.warn("Horizontal background image positioning ignored"
+ + " because the IPD was not set on the area."
+ + " (Yes, it's a bug in FOP)");
+ }
+ }
+ }
+ if (backProps.backgroundPositionVertical != null) {
+ if (back.getRepeat() == Constants.EN_NOREPEAT
+ || back.getRepeat() == Constants.EN_REPEATX) {
+ if (area.getBPD() > 0) {
+ PercentBaseContext refContext = new SimplePercentBaseContext(context,
+ LengthBase.IMAGE_BACKGROUND_POSITION_VERTICAL,
+ (referenceBPD - back.getImageInfo().getSize().getHeightMpt()));
+ back.setVertical(bpdShift
+ + backProps.backgroundPositionVertical.getValue(refContext));
+ } else {
+ // TODO Area BPD has to be set for this to work
+ log.warn("Vertical background image positioning ignored"
+ + " because the BPD was not set on the area."
+ + " (Yes, it's a bug in FOP)");
+ }
+ }
+ }
+ }
+
+ area.addTrait(Trait.BACKGROUND, back);
+ }
+
/**
* Add background to an area.
* Layout managers that create areas with a background can use this to
@@ -312,7 +396,7 @@ public class TraitSetter {
back.setHoriz(backProps.backgroundPositionHorizontal.getValue(
new SimplePercentBaseContext(context,
LengthBase.IMAGE_BACKGROUND_POSITION_HORIZONTAL,
- (width - back.getImageInfo().getSize().getHeightMpt())
+ (width - back.getImageInfo().getSize().getWidthMpt())
)
));
} else {
diff --git a/src/java/org/apache/fop/layoutmgr/table/RowPainter.java b/src/java/org/apache/fop/layoutmgr/table/RowPainter.java
index 022ff0589..61f6b3aec 100644
--- a/src/java/org/apache/fop/layoutmgr/table/RowPainter.java
+++ b/src/java/org/apache/fop/layoutmgr/table/RowPainter.java
@@ -26,22 +26,23 @@ import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.apache.fop.area.Block;
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.flow.table.TableBody;
+import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
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.layoutmgr.TraitSetter;
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 currentRowOffset = 0;
/** Currently handled row (= last encountered row). */
@@ -71,6 +72,13 @@ class RowPainter {
private CellPart[] firstCellParts;
private CellPart[] lastCellParts;
+ /** y-offset of the current table part. */
+ private int tablePartOffset = 0;
+ /** See {@link RowPainter#registerPartBackgroundArea(Block)}. */
+ private CommonBorderPaddingBackground tablePartBackground;
+ /** See {@link RowPainter#registerPartBackgroundArea(Block)}. */
+ private List tablePartBackgroundAreas;
+
private TableContentLayoutManager tclm;
RowPainter(TableContentLayoutManager tclm, LayoutContext layoutContext) {
@@ -85,6 +93,44 @@ class RowPainter {
this.firstRowOnPageIndex = -1;
}
+ void startTablePart(TableBody tablePart) {
+ CommonBorderPaddingBackground background = tablePart.getCommonBorderPaddingBackground();
+ if (background.hasBackground()) {
+ tablePartBackground = background;
+ if (tablePartBackgroundAreas == null) {
+ tablePartBackgroundAreas = new ArrayList();
+ }
+ }
+ tablePartOffset = currentRowOffset;
+ }
+
+ /**
+ * Signals that the end of the current table part is reached.
+ *
+ * @param lastInBody true if the part is the last table-body element 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 part is the last to be displayed on the current page.
+ * In which case collapsed after borders for the cells on the last row must be drawn
+ * in the outer mode
+ */
+ void endTablePart(boolean lastInBody, boolean lastOnPage) {
+ addAreasAndFlushRow(lastInBody, lastOnPage);
+
+ if (tablePartBackground != null) {
+ TableLayoutManager tableLM = tclm.getTableLM();
+ for (Iterator iter = tablePartBackgroundAreas.iterator(); iter.hasNext();) {
+ Block backgroundArea = (Block) iter.next();
+ TraitSetter.addBackground(backgroundArea, tablePartBackground, tableLM,
+ -backgroundArea.getXOffset(), tablePartOffset - backgroundArea.getYOffset(),
+ tableLM.getContentAreaIPD(), currentRowOffset - tablePartOffset);
+ }
+ tablePartBackground = null;
+ tablePartBackgroundAreas.clear();
+ }
+ }
+
int getAccumulatedBPD() {
return currentRowOffset;
}
@@ -108,7 +154,6 @@ class RowPainter {
currentRow = row;
}
}
- rowFO = currentRow.getTableRow();
if (firstRowIndex < 0) {
firstRowIndex = currentRow.getIndex();
if (firstRowOnPageIndex < 0) {
@@ -148,7 +193,7 @@ class RowPainter {
* displayed on the current page. In which case collapsed after borders must be drawn
* in the outer mode
*/
- void addAreasAndFlushRow(boolean lastInPart, boolean lastOnPage) {
+ private void addAreasAndFlushRow(boolean lastInPart, boolean lastOnPage) {
if (log.isDebugEnabled()) {
log.debug("Remembering yoffset for row " + currentRow.getIndex() + ": "
+ currentRowOffset);
@@ -182,8 +227,6 @@ class RowPainter {
}
// 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
@@ -278,8 +321,20 @@ class RowPainter {
* 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();
+ int startRowIndex;
+ int firstRowHeight;
+ if (pgu.getRowIndex() >= firstRowIndex) {
+ startRowIndex = pgu.getRowIndex();
+ if (startRowIndex < currentRowIndex) {
+ firstRowHeight = getRowOffset(startRowIndex + 1) - getRowOffset(startRowIndex);
+ } else {
+ firstRowHeight = rowHeight;
+ }
+ } else {
+ startRowIndex = firstRowIndex;
+ firstRowHeight = 0;
+ }
/*
* In collapsing-border model, if the cell spans over several columns/rows then
@@ -319,7 +374,25 @@ class RowPainter {
cellLM.addAreas(new KnuthPossPosIter(pgu.getElements(), startPos, endPos + 1),
layoutContext, spannedGridRowHeights, startRowIndex - pgu.getRowIndex(),
currentRowIndex - pgu.getRowIndex(), borderBeforeWhich, borderAfterWhich,
- startRowIndex == firstRowOnPageIndex, lastOnPage);
+ startRowIndex == firstRowOnPageIndex, lastOnPage, this, firstRowHeight);
+ }
+
+
+ /**
+ * Registers the given area, that will be used to render the part of
+ * table-header/footer/body background covered by a table-cell. If percentages are
+ * used to place the background image, the final bpd of the (fraction of) table part
+ * that will be rendered on the current page must be known. The traits can't then be
+ * set when the areas for the cell are created since at that moment this bpd is yet
+ * unknown. So they will instead be set in
+ * {@link #addAreasAndFlushRow(boolean, boolean)}.
+ *
+ * @param backgroundArea the block of the cell's dimensions that will hold the part
+ * background
+ */
+ void registerPartBackgroundArea(Block backgroundArea) {
+ tclm.getTableLM().addBackgroundArea(backgroundArea);
+ tablePartBackgroundAreas.add(backgroundArea);
}
/**
@@ -357,11 +430,13 @@ class RowPainter {
}
// TODO get rid of that
+ /** Signals that the first table-body instance has started. */
void startBody() {
Arrays.fill(firstCellOnPage, true);
}
// TODO get rid of that
+ /** Signals that the last table-body instance has ended. */
void endBody() {
Arrays.fill(firstCellOnPage, false);
}
diff --git a/src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java b/src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java
index 289785d68..8e92a233b 100644
--- a/src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/table/TableCellLayoutManager.java
@@ -27,12 +27,14 @@ import org.apache.fop.area.Area;
import org.apache.fop.area.Block;
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.TableBody;
import org.apache.fop.fo.flow.table.TableCell;
+import org.apache.fop.fo.flow.table.TableColumn;
+import org.apache.fop.fo.flow.table.TableRow;
import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
import org.apache.fop.fo.properties.CommonBorderPaddingBackground.BorderInfo;
import org.apache.fop.layoutmgr.AreaAdditionUtil;
@@ -71,7 +73,7 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager
private int xoffset;
private int yoffset;
private int cellIPD;
- private int rowHeight;
+ private int totalHeight;
private int usedBPD;
private int borderAndPaddingBPD;
private boolean emptyCell = true;
@@ -116,11 +118,7 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager
* @return the table owning this cell
*/
public Table getTable() {
- FONode node = fobj.getParent();
- while (!(node instanceof Table)) {
- node = node.getParent();
- }
- return (Table)node;
+ return getTableCell().getTable();
}
@@ -303,7 +301,7 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager
* @param h the height of cell
*/
public void setTotalHeight(int h) {
- rowHeight = h;
+ totalHeight = h;
}
/**
@@ -330,6 +328,10 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager
* 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
+ * @param painter painter
+ * @param firstRowHeight height of the first row spanned by this cell (may be zero if
+ * this row is placed on a previous page). Used to calculate the placement of the
+ * row's background image if any
*/
public void addAreas(PositionIterator parentIter,
LayoutContext layoutContext,
@@ -339,13 +341,24 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager
int borderBeforeWhich,
int borderAfterWhich,
boolean firstOnPage,
- boolean lastOnPage) {
+ boolean lastOnPage,
+ RowPainter painter,
+ int firstRowHeight) {
getParentArea(null);
getPSLM().addIDToPage(getTableCell().getId());
int borderBeforeWidth = primaryGridUnit.getBeforeBorderWidth(startRow, borderBeforeWhich);
int borderAfterWidth = primaryGridUnit.getAfterBorderWidth(endRow, borderAfterWhich);
+
+ CommonBorderPaddingBackground padding = primaryGridUnit.getCell()
+ .getCommonBorderPaddingBackground();
+ int cellBPD = totalHeight - borderBeforeWidth - borderAfterWidth;
+ cellBPD -= padding.getPaddingBefore(borderBeforeWhich == ConditionalBorder.REST, this);
+ cellBPD -= padding.getPaddingAfter(borderAfterWhich == ConditionalBorder.REST, this);
+
+ addBackgroundAreas(painter, firstRowHeight, borderBeforeWidth, cellBPD);
+
if (isSeparateBorderModel()) {
if (!emptyCell || getTableCell().showEmptyCells()) {
if (borderBeforeWidth > 0) {
@@ -437,18 +450,12 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager
}
}
- 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
if (usedBPD < cellBPD) {
if (getTableCell().getDisplayAlign() == EN_CENTER) {
@@ -468,16 +475,9 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager
curBlockArea.setBPD(cellBPD);
// Add background after we know the BPD
- if (isSeparateBorderModel()) {
- if (!emptyCell || getTableCell().showEmptyCells()) {
- TraitSetter.addBackground(curBlockArea,
- getTableCell().getCommonBorderPaddingBackground(),
- this);
- }
- } else {
+ if (!isSeparateBorderModel() || !emptyCell || getTableCell().showEmptyCells()) {
TraitSetter.addBackground(curBlockArea,
- getTableCell().getCommonBorderPaddingBackground(),
- this);
+ getTableCell().getCommonBorderPaddingBackground(), this);
}
flush();
@@ -485,6 +485,32 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager
curBlockArea = null;
}
+ /** Adds background areas for the column, body and row, if any. */
+ private void addBackgroundAreas(RowPainter painter, int firstRowHeight, int borderBeforeWidth,
+ int cellBPD) {
+ TableColumn column = getTable().getColumn(primaryGridUnit.getColIndex());
+ if (column.getCommonBorderPaddingBackground().hasBackground()) {
+ Block colBackgroundArea = getBackgroundArea(cellBPD, borderBeforeWidth);
+ ((TableLayoutManager) parentLM).registerColumnBackgroundArea(column, colBackgroundArea,
+ -startIndent);
+ }
+
+ TableBody body = primaryGridUnit.getTableBody();
+ if (body.getCommonBorderPaddingBackground().hasBackground()) {
+ painter.registerPartBackgroundArea(getBackgroundArea(cellBPD, borderBeforeWidth));
+ }
+
+ TableRow row = primaryGridUnit.getRow();
+ if (row != null && row.getCommonBorderPaddingBackground().hasBackground()) {
+ Block rowBackgroundArea = getBackgroundArea(cellBPD, borderBeforeWidth);
+ ((TableLayoutManager) parentLM).addBackgroundArea(rowBackgroundArea);
+ TraitSetter.addBackground(rowBackgroundArea, row.getCommonBorderPaddingBackground(),
+ (TableLayoutManager) parentLM,
+ -xoffset - startIndent, -borderBeforeWidth,
+ parentLM.getContentAreaIPD(), firstRowHeight);
+ }
+ }
+
private void addBorder(Block[][] blocks, int i, int j, Integer side, BorderInfo border,
boolean outer) {
if (blocks[i][j] == null) {
@@ -513,6 +539,17 @@ public class TableCellLayoutManager extends BlockStackingLayoutManager
block.setBPD(block.getBPD() + amount);
}
+ private Block getBackgroundArea(int bpd, int borderBeforeWidth) {
+ Block block = new Block();
+ TraitSetter.setProducerID(block, getTable().getId());
+ block.setPositioning(Block.ABSOLUTE);
+ block.setIPD(cellIPD);
+ block.setBPD(bpd);
+ block.setXOffset(xoffset + startIndent);
+ block.setYOffset(yoffset + borderBeforeWidth);
+ return block;
+ }
+
/**
* Return an Area which can contain the passed childArea. The childArea
* may not yet have any content, but it has essential traits set.
diff --git a/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java b/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java
index 5fad1e4c5..7cdeb79d5 100644
--- a/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/table/TableContentLayoutManager.java
@@ -27,8 +27,6 @@ import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-import org.apache.fop.area.Block;
-import org.apache.fop.area.Trait;
import org.apache.fop.datatypes.PercentBaseContext;
import org.apache.fop.fo.Constants;
import org.apache.fop.fo.FObj;
@@ -36,7 +34,6 @@ import org.apache.fop.fo.flow.table.EffRow;
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;
import org.apache.fop.layoutmgr.BreakElement;
import org.apache.fop.layoutmgr.ElementListUtils;
import org.apache.fop.layoutmgr.KnuthBox;
@@ -46,7 +43,6 @@ import org.apache.fop.layoutmgr.LayoutContext;
import org.apache.fop.layoutmgr.ListElement;
import org.apache.fop.layoutmgr.Position;
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;
@@ -293,7 +289,7 @@ public class TableContentLayoutManager implements PercentBaseContext {
this.usedBPD = 0;
RowPainter painter = new RowPainter(this, layoutContext);
- List positions = new java.util.ArrayList();
+ List tablePositions = new ArrayList();
List headerElements = null;
List footerElements = null;
Position firstPos = null;
@@ -330,7 +326,7 @@ public class TableContentLayoutManager implements PercentBaseContext {
//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 if (pos instanceof TableContentPosition) {
- positions.add(pos);
+ tablePositions.add(pos);
} else {
if (log.isDebugEnabled()) {
log.debug("Ignoring position: " + pos);
@@ -359,21 +355,23 @@ public class TableContentLayoutManager implements PercentBaseContext {
if (headerElements != null) {
//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, false);
+ addHeaderFooterAreas(headerElements, tableLM.getTable().getTableHeader(), painter,
+ false);
}
- //Iterate over all steps
- Iterator posIter = positions.iterator();
- painter.startBody();
- // Here we are sure that posIter iterates only over TableContentPosition instances
- iterateAndPaintPositions(posIter, painter, footerElements == null);
- painter.endBody();
+ if (tablePositions.isEmpty()) {
+ // TODO make sure this actually never happens
+ log.error("tablePositions empty."
+ + " Please send your FO file to fop-users@xmlgraphics.apache.org");
+ } else {
+ // Here we are sure that posIter iterates only over TableContentPosition instances
+ addBodyAreas(tablePositions.iterator(), painter, footerElements == null);
+ }
if (footerElements != null) {
//Positions for footers are simply added at the end
- PositionIterator nestedIter = new KnuthPossPosIter(footerElements);
- iterateAndPaintPositions(nestedIter, painter, true);
+ addHeaderFooterAreas(footerElements, tableLM.getTable().getTableFooter(), painter,
+ true);
}
this.usedBPD += painter.getAccumulatedBPD();
@@ -384,105 +382,73 @@ public class TableContentLayoutManager implements PercentBaseContext {
}
}
+ private void addHeaderFooterAreas(List elements, TableBody part, RowPainter painter,
+ boolean lastOnPage) {
+ List lst = new ArrayList(elements.size());
+ for (Iterator iter = new KnuthPossPosIter(elements); iter.hasNext();) {
+ Position pos = (Position) iter.next();
+ /*
+ * Unlike for the body the Positions associated to the glues generated by
+ * TableStepper haven't been removed yet.
+ */
+ if (pos instanceof TableContentPosition) {
+ lst.add((TableContentPosition) pos);
+ }
+ }
+ addTablePartAreas(lst, painter, part, true, true, true, lastOnPage);
+ }
+
/**
- * Iterates over a part of the table (header, footer, body) and paints the related
- * elements.
+ * Iterates over the positions corresponding to the table's body (which may contain
+ * several table-body elements!) and adds the corresponding areas.
*
- * @param iterator iterator over Position elements. Those positions correspond to the
- * elements of the table present on the current page
+ * @param iterator iterator over TableContentPosition elements. Those positions
+ * correspond to the elements of the body 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)
+ * @param lastOnPage true if the table has no footer (then the last line of the table
+ * that will be present on the page belongs to the body)
*/
- private void iterateAndPaintPositions(Iterator iterator, RowPainter painter,
+ private void addBodyAreas(Iterator iterator, RowPainter painter,
boolean lastOnPage) {
+ painter.startBody();
List lst = new ArrayList();
- boolean firstPos = false;
- TableBody body = null;
+ TableContentPosition pos = (TableContentPosition) iterator.next();
+ boolean isFirstPos = pos.getFlag(TableContentPosition.FIRST_IN_ROWGROUP)
+ && pos.getRow().getFlag(EffRow.FIRST_IN_PART);
+ TableBody body = pos.getTableBody();
+ lst.add(pos);
while (iterator.hasNext()) {
- Position pos = (Position)iterator.next();
- if (pos instanceof TableContentPosition) {
- TableContentPosition tcpos = (TableContentPosition)pos;
- lst.add(tcpos);
- CellPart part = (CellPart)tcpos.cellParts.get(0);
- if (body == null) {
- body = part.pgu.getTableBody();
- }
- if (tcpos.getFlag(TableContentPosition.FIRST_IN_ROWGROUP)
- && tcpos.getRow().getFlag(EffRow.FIRST_IN_PART)) {
- firstPos = true;
-
- }
- if (tcpos.getFlag(TableContentPosition.LAST_IN_ROWGROUP)
- && tcpos.getRow().getFlag(EffRow.LAST_IN_PART)) {
- log.trace("LAST_IN_ROWGROUP + LAST_IN_PART");
- handleMarkersAndPositions(lst, body, firstPos, true, painter);
- //reset
- firstPos = false;
- body = null;
- lst.clear();
- }
+ pos = (TableContentPosition) iterator.next();
+ if (pos.getTableBody() != body) {
+ addTablePartAreas(lst, painter, body, isFirstPos, true, false, false);
+ isFirstPos = true;
+ lst.clear();
+ body = pos.getTableBody();
}
+ lst.add(pos);
}
- if (body != null) {
- // Entering this block means that the end of the current table-part hasn't
- // been reached (otherwise it would have been caught by the test above). So
- // lastPos is necessarily false
- handleMarkersAndPositions(lst, body, firstPos, false, painter);
- }
- painter.addAreasAndFlushRow(true, lastOnPage);
- }
-
- private void handleMarkersAndPositions(List positions, TableBody body, boolean firstPos,
- boolean lastPos, RowPainter painter) {
- getTableLM().getCurrentPV().addMarkers(body.getMarkers(),
- true, firstPos, lastPos);
- int size = positions.size();
- for (int i = 0; i < size; i++) {
- painter.handleTableContentPosition((TableContentPosition)positions.get(i));
- }
- getTableLM().getCurrentPV().addMarkers(body.getMarkers(),
- false, firstPos, lastPos);
+ boolean isLastPos = pos.getFlag(TableContentPosition.LAST_IN_ROWGROUP)
+ && pos.getRow().getFlag(EffRow.LAST_IN_PART);
+ addTablePartAreas(lst, painter, body, isFirstPos, isLastPos, true, lastOnPage);
+ painter.endBody();
}
/**
- * Get the area for a row for background.
- * @param row the table-row object or null
- * @return the row area or null if there's no background to paint
+ * Adds the areas corresponding to a single fo:table-header/footer/body element.
*/
- Block getRowArea(TableRow row) {
- if (row == null || !row.getCommonBorderPaddingBackground().hasBackground()) {
- return null;
- } else {
- Block block = new Block();
- block.addTrait(Trait.IS_REFERENCE_AREA, Boolean.TRUE);
- block.setPositioning(Block.ABSOLUTE);
- return block;
+ private void addTablePartAreas(List positions, RowPainter painter, TableBody body,
+ boolean isFirstPos, boolean isLastPos, boolean lastInBody, boolean lastOnPage) {
+ getTableLM().getCurrentPV().addMarkers(body.getMarkers(),
+ true, isFirstPos, isLastPos);
+ painter.startTablePart(body);
+ for (Iterator iter = positions.iterator(); iter.hasNext();) {
+ painter.handleTableContentPosition((TableContentPosition) iter.next());
}
+ getTableLM().getCurrentPV().addMarkers(body.getMarkers(),
+ false, isFirstPos, isLastPos);
+ painter.endTablePart(lastInBody, lastOnPage);
}
- /**
- * Adds the area for the row background if any.
- * @param row row for which to generate the background
- * @param bpd block-progression-dimension of the row
- * @param ipd inline-progression-dimension of the row
- * @param yoffset Y offset at which to paint
- */
- void addRowBackgroundArea(TableRow row, int bpd, int ipd, int yoffset) {
- //Add row background if any
- Block rowBackground = getRowArea(row);
- if (rowBackground != null) {
- rowBackground.setBPD(bpd);
- rowBackground.setIPD(ipd);
- rowBackground.setXOffset(this.startXOffset);
- rowBackground.setYOffset(yoffset);
- getTableLM().addChildArea(rowBackground);
- TraitSetter.addBackground(rowBackground,
- row.getCommonBorderPaddingBackground(), getTableLM());
- }
- }
-
-
/**
* Sets the overall starting x-offset. Used for proper placement of cells.
* @param startXOffset starting x-offset (table's start-indent)
diff --git a/src/java/org/apache/fop/layoutmgr/table/TableContentPosition.java b/src/java/org/apache/fop/layoutmgr/table/TableContentPosition.java
index e702c58a9..db34764b1 100644
--- a/src/java/org/apache/fop/layoutmgr/table/TableContentPosition.java
+++ b/src/java/org/apache/fop/layoutmgr/table/TableContentPosition.java
@@ -22,6 +22,7 @@ package org.apache.fop.layoutmgr.table;
import java.util.List;
import org.apache.fop.fo.flow.table.EffRow;
+import org.apache.fop.fo.flow.table.TableBody;
import org.apache.fop.layoutmgr.LayoutManager;
import org.apache.fop.layoutmgr.Position;
@@ -79,6 +80,10 @@ class TableContentPosition extends Position {
return row;
}
+ TableBody getTableBody() {
+ return ((CellPart) cellParts.get(0)).pgu.getTableBody();
+ }
+
/**
* Returns a flag for this GridUnit.
* @param which the requested flag
diff --git a/src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java b/src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java
index 1cbc3e50a..0b3967643 100644
--- a/src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java
+++ b/src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java
@@ -19,8 +19,10 @@
package org.apache.fop.layoutmgr.table;
+import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
+import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -79,7 +81,27 @@ public class TableLayoutManager extends BlockStackingLayoutManager
private int halfBorderSeparationBPD;
private int halfBorderSeparationIPD;
-
+
+ /** See {@link TableLayoutManager#registerColumnBackgroundArea(TableColumn, Block, int)}. */
+ private List columnBackgroundAreas;
+
+ /**
+ * Temporary holder of column background informations for a table-cell's area.
+ *
+ * @see TableLayoutManager#registerColumnBackgroundArea(TableColumn, Block, int)
+ */
+ private static final class ColumnBackgroundInfo {
+ private TableColumn column;
+ private Block backgroundArea;
+ private int xShift;
+
+ private ColumnBackgroundInfo(TableColumn column, Block backgroundArea, int xShift) {
+ this.column = column;
+ this.backgroundArea = backgroundArea;
+ this.xShift = xShift;
+ }
+ }
+
/**
* Create a new table layout manager.
* @param node the table FO
@@ -263,7 +285,30 @@ public class TableLayoutManager extends BlockStackingLayoutManager
resetSpaces();
return returnList;
}
-
+
+ /**
+ * Registers the given area, that will be used to render the part of column background
+ * covered by a table-cell. If percentages are used to place the background image, the
+ * final bpd of the (fraction of) table that will be rendered on the current page must
+ * be known. The traits can't then be set when the areas for the cell are created
+ * since at that moment this bpd is yet unknown. So they will instead be set in
+ * TableLM's {@link #addAreas(PositionIterator, LayoutContext)} method.
+ *
+ * @param column the table-column element from which the cell gets background
+ * informations
+ * @param backgroundArea the block of the cell's dimensions that will hold the column
+ * background
+ * @param xShift additional amount by which the image must be shifted to be correctly
+ * placed (to counterbalance the cell's start border)
+ */
+ void registerColumnBackgroundArea(TableColumn column, Block backgroundArea, int xShift) {
+ addBackgroundArea(backgroundArea);
+ if (columnBackgroundAreas == null) {
+ columnBackgroundAreas = new ArrayList();
+ }
+ columnBackgroundAreas.add(new ColumnBackgroundInfo(column, backgroundArea, xShift));
+ }
+
/**
* The table area is a reference area that contains areas for
* columns, bodies, rows and the contents are in cells.
@@ -298,6 +343,17 @@ public class TableLayoutManager extends BlockStackingLayoutManager
curBlockArea.setBPD(tableHeight);
+ if (columnBackgroundAreas != null) {
+ for (Iterator iter = columnBackgroundAreas.iterator(); iter.hasNext();) {
+ ColumnBackgroundInfo b = (ColumnBackgroundInfo) iter.next();
+ TraitSetter.addBackground(b.backgroundArea,
+ b.column.getCommonBorderPaddingBackground(), this,
+ b.xShift, -b.backgroundArea.getYOffset(),
+ b.column.getColumnWidth().getValue(this), tableHeight);
+ }
+ columnBackgroundAreas.clear();
+ }
+
if (getTable().isSeparateBorderModel()) {
TraitSetter.addBorders(curBlockArea,
getTable().getCommonBorderPaddingBackground(),
@@ -366,6 +422,15 @@ public class TableLayoutManager extends BlockStackingLayoutManager
}
}
+ /**
+ * Adds the given area to this layout manager's area, without updating the used bpd.
+ *
+ * @param background an area
+ */
+ void addBackgroundArea(Block background) {
+ curBlockArea.addChildArea(background);
+ }
+
/** {@inheritDoc} */
public int negotiateBPDAdjustment(int adj, KnuthElement lastElement) {
// TODO Auto-generated method stub
diff --git a/status.xml b/status.xml
index e622c589f..594b113e1 100644
--- a/status.xml
+++ b/status.xml
@@ -94,6 +94,17 @@
+
+ Added support for background on fo:table-column and fo:table-header/footer/body elements.
+
+
+ Fixed the rendering of the area of a table corresponding to border-separation, which must
+ be filled with the background of the table, and not the rows.
+
+
+ Improved conformance: even if a table-cell spans several rows its background must
+ correspond to the first row spanned.
+
Slight improvement for thin lines in Java2D/AWT output.
diff --git a/test/layoutengine/standard-testcases/table-cell_conditional-spaces_2.xml b/test/layoutengine/standard-testcases/table-cell_conditional-spaces_2.xml
index 1a9940e38..9a0920cf1 100644
--- a/test/layoutengine/standard-testcases/table-cell_conditional-spaces_2.xml
+++ b/test/layoutengine/standard-testcases/table-cell_conditional-spaces_2.xml
@@ -168,94 +168,108 @@
+
-
-
-
+
+
+
-
-
+
+
+
+
-
-
+
+
+
+
-
-
-
+
+
+
-
-
+
+
+
+
-
-
-
+
+
+
+
-
-
+
+
+
-
-
+
+
+
+
-
-
-
+
+
+
-
+
+
-
+
+
-
+
+
diff --git a/test/layoutengine/standard-testcases/table-footer_omit-footer-at-break.xml b/test/layoutengine/standard-testcases/table-footer_omit-footer-at-break.xml
index 7b2cc6904..59c60f72e 100644
--- a/test/layoutengine/standard-testcases/table-footer_omit-footer-at-break.xml
+++ b/test/layoutengine/standard-testcases/table-footer_omit-footer-at-break.xml
@@ -97,35 +97,35 @@
-
-
-
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
-
+
-
-
-
+
+
+
-
-
+
+
-
-
-
-
+
+
+
+
diff --git a/test/layoutengine/standard-testcases/table-header_omit-header-at-break.xml b/test/layoutengine/standard-testcases/table-header_omit-header-at-break.xml
index 6834deeac..5ec211645 100644
--- a/test/layoutengine/standard-testcases/table-header_omit-header-at-break.xml
+++ b/test/layoutengine/standard-testcases/table-header_omit-header-at-break.xml
@@ -32,7 +32,7 @@
-
+
@@ -97,23 +97,23 @@
-
-
-
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
+
+
+
+
@@ -122,8 +122,8 @@
-
-
-
+
+
+
diff --git a/test/layoutengine/standard-testcases/table-header_table-footer_1.xml b/test/layoutengine/standard-testcases/table-header_table-footer_1.xml
index df45e328b..00cbcde54 100644
--- a/test/layoutengine/standard-testcases/table-header_table-footer_1.xml
+++ b/test/layoutengine/standard-testcases/table-header_table-footer_1.xml
@@ -32,7 +32,7 @@
-
+
@@ -82,31 +82,41 @@
-
+
+
+
+
+
+
-
-
-
+
+
+
-
-
-
-
+
+
+
+
-
-
-
-
-
+
-
+
+
+
+
+
+
+
+
+
+
diff --git a/test/layoutengine/standard-testcases/table-header_table-footer_2.xml b/test/layoutengine/standard-testcases/table-header_table-footer_2.xml
index 9cf3db4c0..7716dfe58 100644
--- a/test/layoutengine/standard-testcases/table-header_table-footer_2.xml
+++ b/test/layoutengine/standard-testcases/table-header_table-footer_2.xml
@@ -32,7 +32,7 @@
-
+
@@ -97,40 +97,40 @@
-
-
-
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
+
+
+
+
-
-
-
+
+
+
-
-
+
+
-
-
-
-
+
+
+
+
diff --git a/test/layoutengine/standard-testcases/table-row_background-image.xml b/test/layoutengine/standard-testcases/table-row_background-image.xml
index fa29f1b8e..f4dc65ae7 100644
--- a/test/layoutengine/standard-testcases/table-row_background-image.xml
+++ b/test/layoutengine/standard-testcases/table-row_background-image.xml
@@ -34,10 +34,8 @@
-
-
-
-
+
+
@@ -82,8 +80,20 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test/layoutengine/standard-testcases/table-row_height.xml b/test/layoutengine/standard-testcases/table-row_height.xml
index b158113f6..934afa69f 100644
--- a/test/layoutengine/standard-testcases/table-row_height.xml
+++ b/test/layoutengine/standard-testcases/table-row_height.xml
@@ -81,27 +81,37 @@
-
-
+
+
+
-
+
+
+
+
+
-
-
-
-
+
-
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+
diff --git a/test/layoutengine/standard-testcases/table_backgrounds.xml b/test/layoutengine/standard-testcases/table_backgrounds.xml
new file mode 100644
index 000000000..30564ecf7
--- /dev/null
+++ b/test/layoutengine/standard-testcases/table_backgrounds.xml
@@ -0,0 +1,392 @@
+
+
+
+
+
+
+ This test checks backgrounds on table elements.
+
+
+
+ ../../resources/images/fop-logo-gray-8bit.png
+ ../../resources/images/bgimg72dpi.jpg
+ ../../resources/images/fop-logo-color-24bit.png
+ ../../../examples/fo/graphics/asf-logo.png
+ ../../../examples/fo/graphics/asf-logo.png
+ ../../resources/images/box1.png
+
+
+
+
+
+
+
+
+
+
+
+ Before the table.
+
+
+
+
+
+ Header 1.1
+ Header 1.1
+ Header 1.1
+ Header 1.1
+ Header 1.1
+
+
+ Header 1.2
+ Header 1.2
+ Header 1.2
+ Header 1.2
+ Header 1.2
+
+
+
+
+ Footer 1.1
+ Footer 1.1
+
+
+ Footer 1.2
+ Footer 1.2
+
+
+
+
+
+ Cell 1.1
+ Cell 1.1
+ Cell 1.1
+ Cell 1.1
+
+
+ Cell 1.2
+ Cell 1.2
+
+
+
+
+ Cell 2.2
+
+
+
+
+ Cell 3.1
+ Cell 3.1
+
+
+
+
+ Cell 4.1
+ Cell 4.1
+
+
+ Cell 4.2
+
+
+
+
+
+
+ Cell 5.1
+ Cell 5.1
+ Cell 5.1
+ Cell 5.1
+ Cell 5.1 Line 5
+ Cell 5.1
+ Cell 5.1
+ Cell 5.1
+ Cell 5.1
+ Cell 5.1 Line 10
+ Cell 5.1
+
+
+ Cell 5.2
+ Cell 5.2
+ Cell 5.2
+ Cell 5.2
+
+
+
+
+ Cell 6.2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
--
2.39.5