浏览代码

First real step towards collapsing table borders.

border-collapse="collapse" rules implemented but not fully tested, yet.
Collapsing of borders works only for start and end borders, yet, and there only for non-spanned cells.
CellLM is now prepared to get the full list of grid unit it occupies (necessary for collapsed border painting).
Row.CellInfo extracted and renamed to GridUnit.
WIP...


git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@198450 13f79535-47bb-0310-9956-ffa450edef68
tags/Root_Temp_KnuthStylePageBreaking
Jeremias Maerki 19 年前
父节点
当前提交
1cf6596be0

+ 18
- 0
src/java/org/apache/fop/fo/flow/TableBody.java 查看文件

@@ -152,5 +152,23 @@ public class TableBody extends FObj {
public int getNameId() {
return FO_TABLE_BODY;
}

/**
* @param obj table row in question
* @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);
}

/**
* @param obj table row in question
* @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);
}
}


+ 61
- 3
src/java/org/apache/fop/fo/properties/CommonBorderPaddingBackground.java 查看文件

@@ -75,7 +75,7 @@ public class CommonBorderPaddingBackground implements Cloneable {
/** the "end" edge */
public static final int END = 3;

private static class BorderInfo implements Cloneable {
public static class BorderInfo implements Cloneable {
private int mStyle; // Enum for border style
private ColorType mColor; // Border color
private CondLengthProperty mWidth;
@@ -85,11 +85,52 @@ public class CommonBorderPaddingBackground implements Cloneable {
mWidth = width;
mColor = color;
}
public int getStyle() {
return this.mStyle;
}
public ColorType getColor() {
return this.mColor;
}
public CondLengthProperty getWidth() {
return this.mWidth;
}

public int getRetainedWidth() {
if ((mStyle == Constants.EN_NONE)
|| (mStyle == Constants.EN_HIDDEN)) {
return 0;
} else {
return mWidth.getLengthValue();
}
}
/** @see java.lang.Object#toString() */
public String toString() {
StringBuffer sb = new StringBuffer("BorderInfo");
sb.append(" {");
sb.append(mStyle);
sb.append(", ");
sb.append(mColor);
sb.append(", ");
sb.append(mWidth);
sb.append("}");
return sb.toString();
}
}

private BorderInfo[] borderInfo = new BorderInfo[4];
private CondLengthProperty[] padding = new CondLengthProperty[4];

/**
* Construct a CommonBorderPaddingBackground object.
*/
public CommonBorderPaddingBackground() {
}
/**
* Construct a CommonBorderPaddingBackground object.
* @param pList The PropertyList to get properties from.
@@ -159,12 +200,29 @@ public class CommonBorderPaddingBackground implements Cloneable {
// If style = none, force width to 0, don't get Color (spec 7.7.20)
int style = pList.get(styleProp).getEnum();
if (style != Constants.EN_NONE) {
borderInfo[side] = new BorderInfo(style,
setBorderInfo(new BorderInfo(style,
pList.get(widthProp).getCondLength(),
pList.get(colorProp).getColorType());
pList.get(colorProp).getColorType()), side);
}
}
/**
* Sets a border.
* @param info the border information
* @param side the side to apply the info to
*/
public void setBorderInfo(BorderInfo info, int side) {
this.borderInfo[side] = info;
}
/**
* @param side the side to retrieve
* @return the border info for a side
*/
public BorderInfo getBorderInfo(int side) {
return this.borderInfo[side];
}
/**
* @return the background image as a preloaded FopImage, null if there is
* no background image.

+ 5
- 3
src/java/org/apache/fop/layoutmgr/LayoutManagerMapping.java 查看文件

@@ -313,7 +313,7 @@ public class LayoutManagerMapping implements LayoutManagerMaker {

public static class TableLayoutManagerMaker extends Maker {
private List getColumnLayoutManagerList(Table table) {
private List getColumnLayoutManagerList(Table table, TableLayoutManager tlm) {
List columnLMs = null;
List columns = table.getColumns();
if (columns != null) {
@@ -329,7 +329,9 @@ public class LayoutManagerMapping implements LayoutManagerMaker {
while (colnum > columnLMs.size()) {
columnLMs.add(null);
}
columnLMs.set(colnum - 1, new Column(col));
Column colLM = new Column(col);
colLM.setParent(tlm);
columnLMs.set(colnum - 1, colLM);
colnum++;
}
}
@@ -350,7 +352,7 @@ public class LayoutManagerMapping implements LayoutManagerMaker {
public void make(FONode node, List lms) {
Table table = (Table) node;
TableLayoutManager tlm = new TableLayoutManager(table);
List columnLMs = getColumnLayoutManagerList(table);
List columnLMs = getColumnLayoutManagerList(table, tlm);
if (columnLMs != null) {
tlm.setColumns(columnLMs);
}

+ 5
- 0
src/java/org/apache/fop/layoutmgr/table/Body.java 查看文件

@@ -61,6 +61,11 @@ public class Body extends BlockStackingLayoutManager {
fobj = node;
}

/** @return the table-body|header|footer FO */
public TableBody getFObj() {
return this.fobj;
}
/**
* Set the columns from the table.
*

+ 43
- 5
src/java/org/apache/fop/layoutmgr/table/Cell.java 查看文件

@@ -21,6 +21,7 @@ package org.apache.fop.layoutmgr.table;
import org.apache.fop.fo.FONode;
import org.apache.fop.fo.flow.Table;
import org.apache.fop.fo.flow.TableCell;
import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
import org.apache.fop.fo.properties.LengthRangeProperty;
import org.apache.fop.layoutmgr.BlockStackingLayoutManager;
import org.apache.fop.layoutmgr.LayoutManager;
@@ -59,9 +60,14 @@ public class Cell extends BlockStackingLayoutManager {
private int cellIPD;
private int rowHeight;
private int usedBPD;
private int startBorderWidth;
private int endBorderWidth;
private int borderAndPaddingBPD;
private boolean emptyCell = true;

/** List of Lists containing GridUnit instances, one List per row. */
private List rows = new java.util.ArrayList();
/**
* Create a new Cell layout manager.
* @node table-cell FO for which to create the LM
@@ -102,10 +108,34 @@ public class Cell extends BlockStackingLayoutManager {
return (Table)node;
}

/**
* Called by Row LM to register the grid units occupied by this cell for a row.
* @param spannedGridUnits a List of GridUnits
*/
public void addGridUnitsFromRow(List spannedGridUnits) {
log.debug("Getting another row, " + spannedGridUnits.size() + " grid units");
this.rows.add(spannedGridUnits);
}

private int getIPIndents() {
int iIndents = 0;
iIndents += fobj.getCommonBorderPaddingBackground().getBorderStartWidth(false);
iIndents += fobj.getCommonBorderPaddingBackground().getBorderEndWidth(false);
startBorderWidth = 0;
endBorderWidth = 0;
for (int i = 0; i < rows.size(); i++) {
List gridUnits = (List)rows.get(i);
startBorderWidth = Math.max(startBorderWidth,
((GridUnit)gridUnits.get(0)).
effBorders.getBorderStartWidth(false));
endBorderWidth = Math.max(endBorderWidth,
((GridUnit)gridUnits.get(gridUnits.size() - 1)).
effBorders.getBorderEndWidth(false));
}
//iIndents += fobj.getCommonBorderPaddingBackground().getBorderStartWidth(false);
iIndents += startBorderWidth;
//iIndents += fobj.getCommonBorderPaddingBackground().getBorderEndWidth(false);
iIndents += endBorderWidth;
if (!fobj.isSeparateBorderModel()) {
iIndents /= 2;
}
@@ -277,8 +307,15 @@ public class Cell extends BlockStackingLayoutManager {
TraitSetter.addBackground(curBlockArea, fobj.getCommonBorderPaddingBackground());
//TODO Set these booleans right
boolean[] outer = new boolean[] {false, false, false, false};
TraitSetter.addCollapsingBorders(curBlockArea,
fobj.getCommonBorderPaddingBackground(), outer);
if (rows.size() == 1 && ((List)rows.get(0)).size() == 1) {
//Can set the borders directly if there's no span
CommonBorderPaddingBackground effBorders =
((GridUnit)((List)rows.get(0)).get(0)).effBorders;
TraitSetter.addCollapsingBorders(curBlockArea,
effBorders, outer);
} else {
log.warn("TODO Add collapsed border painting for spanned cells");
}
}

//Handle display-align
@@ -339,7 +376,7 @@ public class Cell extends BlockStackingLayoutManager {
curBlockArea.addTrait(Trait.IS_REFERENCE_AREA, Boolean.TRUE);
curBlockArea.setPositioning(Block.ABSOLUTE);
int indent = 0;
indent += fobj.getCommonBorderPaddingBackground().getBorderStartWidth(false);
indent += startBorderWidth;
if (!fobj.isSeparateBorderModel()) {
indent /= 2;
}
@@ -390,5 +427,6 @@ public class Cell extends BlockStackingLayoutManager {
childBreaks.clear();
}
}

}


+ 121
- 0
src/java/org/apache/fop/layoutmgr/table/CollapsingBorderModel.java 查看文件

@@ -0,0 +1,121 @@
/*
* Copyright 2005 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.layoutmgr.table;

import org.apache.fop.fo.Constants;
import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
import org.apache.fop.fo.properties.CommonBorderPaddingBackground.BorderInfo;

/**
* This class is a superclass for the two collapsing border models defined
* in the XSL 1.0 specification.
*/
public abstract class CollapsingBorderModel {

/** Indicates that the cell is/starts in the first row being painted on a particular page */
public static final int FIRST_ROW_IN_TABLE_PART = 1;
/** Indicates that the cell is/ends in the last row being painted on a particular page */
public static final int LAST_ROW_IN_TABLE_PART = 2;
/** Indicates that the cell is/starts in the first row of a body/table-header/table-footer */
public static final int FIRST_ROW_IN_GROUP = 4;
/** Indicates that the cell is/end in the last row of a body/table-header/table-footer */
public static final int LAST_ROW_IN_GROUP = 8;
private static CollapsingBorderModel collapse = null;
private static CollapsingBorderModel collapseWithPrecedence = null;
/**
* @param cellLM the cell
* @return the border model for the cell
*/
public static CollapsingBorderModel getBorderModelFor(int borderCollapse) {
switch (borderCollapse) {
case Constants.EN_COLLAPSE:
if (collapse == null) {
collapse = new CollapsingBorderModelEyeCatching();
}
return collapse;
case Constants.EN_COLLAPSE_WITH_PRECEDENCE:
if (collapseWithPrecedence == null) {
//collapseWithPrecedence = new CollapsingBorderModelWithPrecedence();
}
return collapseWithPrecedence;
default:
throw new IllegalArgumentException("Illegal border-collapse mode.");
}
}
/**
* @param side the side on the current cell
* @return the adjacent side on the neighbouring cell
*/
public static int getOtherSide(int side) {
switch (side) {
case CommonBorderPaddingBackground.BEFORE:
return CommonBorderPaddingBackground.AFTER;
case CommonBorderPaddingBackground.AFTER:
return CommonBorderPaddingBackground.BEFORE;
case CommonBorderPaddingBackground.START:
return CommonBorderPaddingBackground.END;
case CommonBorderPaddingBackground.END:
return CommonBorderPaddingBackground.START;
default:
throw new IllegalArgumentException("Illegal parameter: side");
}
}
/**
* @param side the side to investigate
* @return true if the adjacent cell is before or after
*/
protected boolean isVerticalRelation(int side) {
return (side == CommonBorderPaddingBackground.BEFORE
|| side == CommonBorderPaddingBackground.AFTER);
}

/**
* See rule 4 in 6.7.10 for the collapsing border model.
* @param style the border style to get the preference value for
* @return the preference value of the style
*/
public int getPreferenceValue(int style) {
switch (style) {
case Constants.EN_DOUBLE: return 0;
case Constants.EN_SOLID: return -1;
case Constants.EN_DASHED: return -2;
case Constants.EN_DOTTED: return -3;
case Constants.EN_RIDGE: return -4;
case Constants.EN_OUTSET: return -5;
case Constants.EN_GROOVE: return -6;
case Constants.EN_INSET: return -6;
default: throw new IllegalStateException("Illegal border style: " + style);
}
}
/**
* Determines the winning BorderInfo.
* @param current cell info of the current element
* @param neighbour cell info of the neighbouring element
* @return the winning BorderInfo
*/
public abstract BorderInfo determineWinner(
GridUnit current, GridUnit neighbour, int side, int flags);
}

+ 298
- 0
src/java/org/apache/fop/layoutmgr/table/CollapsingBorderModelEyeCatching.java 查看文件

@@ -0,0 +1,298 @@
/*
* Copyright 2005 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.layoutmgr.table;

import org.apache.fop.fo.Constants;
import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
import org.apache.fop.fo.properties.CommonBorderPaddingBackground.BorderInfo;

/**
* Implements the normal "collapse" border model defined in 6.7.10 in XSL 1.0.
*
* TODO Column groups are not yet checked in this algorithm!
*/
public class CollapsingBorderModelEyeCatching extends CollapsingBorderModel {

private static final int BEFORE = CommonBorderPaddingBackground.BEFORE;
private static final int AFTER = CommonBorderPaddingBackground.AFTER;
private static final int START = CommonBorderPaddingBackground.START;
private static final int END = CommonBorderPaddingBackground.END;
public BorderInfo determineWinner(GridUnit currentGridUnit,
GridUnit otherGridUnit, int side, int flags) {
final boolean vertical = isVerticalRelation(side);
final int otherSide = getOtherSide(side);
//Get cells
Cell currentCell = currentGridUnit.layoutManager;
Cell otherCell = null;
if (otherGridUnit != null) {
otherCell = otherGridUnit.layoutManager;
}
//Get rows
Row currentRow = currentGridUnit.row;
Row otherRow = null;
if (vertical && otherCell != null) {
otherRow = otherGridUnit.row;
}
//get bodies
Body currentBody = (Body)currentRow.getParent();
Body otherBody = null;
if (otherRow != null) {
otherBody = (Body)otherRow.getParent();
}

//get columns
Column currentColumn = (Column)currentGridUnit.column;
Column otherColumn = null;
if (otherGridUnit != null) {
otherColumn = (Column)otherGridUnit.column;
}
//TODO get column groups
//Get table
TableLayoutManager table = (TableLayoutManager)currentBody.getParent();
//----------------------------------------------------------------------
//We're creating two arrays containing the applicable BorderInfos for
//each cell in question.
//0 = cell, 1 = row, 2 = row group (body), 3 = column,
//4 = col group (spanned column, see 6.7.3), 5 = table

BorderInfo[] current = new BorderInfo[6];
BorderInfo[] other = new BorderInfo[6];
//cell
current[0] = currentGridUnit.getOriginalBorderInfoForCell(side);
if (otherGridUnit != null) {
other[0] = otherGridUnit.getOriginalBorderInfoForCell(otherSide);
}
if (side == BEFORE
|| side == AFTER
|| (currentColumn.isFirst() && side == START)
|| (currentColumn.isLast() && side == END)) {
//row
current[1] = currentRow.getFObj().getCommonBorderPaddingBackground().getBorderInfo(side);
}
if (otherRow != null) {
//row
other[1] = otherRow.getFObj().getCommonBorderPaddingBackground().getBorderInfo(otherSide);
}
if ((side == BEFORE && currentRow.isFirstInBody())
|| (side == AFTER && currentRow.isLastInBody())
|| (currentColumn.isFirst() && side == START)
|| (currentColumn.isLast() && side == END)) {
//row group (=body, table-header or table-footer)
current[2] = currentBody.getFObj().getCommonBorderPaddingBackground().getBorderInfo(side);
}
if ((otherSide == BEFORE && otherRow.isFirstInBody())
|| (otherSide == AFTER && otherRow.isLastInBody())) {
//row group (=body, table-header or table-footer)
other[2] = otherBody.getFObj().getCommonBorderPaddingBackground().getBorderInfo(otherSide);
}
if ((side == BEFORE && otherGridUnit == null)
|| (side == AFTER && otherGridUnit == null)
|| (side == START)
|| (side == END)) {
//column
current[3] = currentColumn.getFObj().getCommonBorderPaddingBackground().getBorderInfo(side);
}
if (otherColumn != null) {
//column
other[3] = otherColumn.getFObj().getCommonBorderPaddingBackground().getBorderInfo(otherSide);
}
//TODO current[4] and other[4] for column groups
if (otherGridUnit == null) {
//table
current[5] = table.getTable().getCommonBorderPaddingBackground().getBorderInfo(side);
}
//other[6] is always null, since it's always the same table
BorderInfo resolved = null;
// *** Rule 1 ***
resolved = doRule1(current, other);
if (resolved != null) {
return resolved;
}
// *** Rule 2 ***
if (!doRule2(current, other)) {
return null; //paint no border
}
// *** Rule 3 ***
resolved = doRule3(current, other);
if (resolved != null) {
return resolved;
}
// *** Rule 4 ***
resolved = doRule4(current, other);
if (resolved != null) {
return resolved;
}
// *** Rule 5 ***
resolved = doRule5(current, other);
if (resolved != null) {
return resolved;
}
return null; //no winner, no border
}

private BorderInfo doRule1(BorderInfo[] current, BorderInfo[] other) {
for (int i = 0; i < current.length - 1; i++) {
if ((current[i] != null) && (current[i].getStyle() == Constants.EN_HIDDEN)) {
return current[i];
}
if ((other[i] != null) && (other[i].getStyle() == Constants.EN_HIDDEN)) {
return other[i];
}
}
return null;
}
private boolean doRule2(BorderInfo[] current, BorderInfo[] other) {
boolean found = false;
for (int i = 0; i < current.length - 1; i++) {
if ((current[i] != null) && (current[i].getStyle() != Constants.EN_NONE)) {
found = true;
break;
}
if ((other[i] != null) && (other[i].getStyle() != Constants.EN_NONE)) {
found = true;
break;
}
}
return found;
}

private BorderInfo doRule3(BorderInfo[] current, BorderInfo[] other) {
int width = 0;
//Find max border width
for (int i = 0; i < current.length - 1; i++) {
if ((current[i] != null) && (current[i].getRetainedWidth() > width)) {
width = current[i].getRetainedWidth();
}
if ((other[i] != null) && (other[i].getRetainedWidth() > width)) {
width = other[i].getRetainedWidth();
}
}
BorderInfo widest = null;
int count = 0;
//See if there's only one with the widest border
for (int i = 0; i < current.length - 1; i++) {
if ((current[i] != null) && (current[i].getRetainedWidth() == width)) {
count++;
if (widest == null) {
widest = current[i];
}
break;
} else {
current[i] = null; //Discard the narrower ones
}
if ((other[i] != null) && (other[i].getRetainedWidth() == width)) {
count++;
if (widest == null) {
widest = other[i];
}
break;
} else {
other[i] = null; //Discard the narrower ones
}
}
if (count == 1) {
return widest;
} else {
return null;
}
}

private BorderInfo doRule4(BorderInfo[] current, BorderInfo[] other) {
int pref = getPreferenceValue(Constants.EN_INSET); //Lowest preference
//Find highest preference value
for (int i = 0; i < current.length - 1; i++) {
if (current[i] != null) {
int currPref = getPreferenceValue(current[i].getStyle());
if (currPref > pref) {
pref = currPref;
break;
}
}
if (other[i] != null) {
int currPref = getPreferenceValue(other[i].getStyle());
if (currPref > pref) {
pref = currPref;
break;
}
}
}
BorderInfo preferred = null;
int count = 0;
//See if there's only one with the preferred border style
for (int i = 0; i < current.length - 1; i++) {
if (current[i] != null) {
int currPref = getPreferenceValue(current[i].getStyle());
if (currPref == pref) {
count++;
if (preferred == null) {
preferred = current[i];
}
break;
}
} else {
current[i] = null; //Discard the ones that are not preferred
}
if (other[i] != null) {
int currPref = getPreferenceValue(other[i].getStyle());
if (currPref == pref) {
count++;
if (preferred == null) {
preferred = other[i];
}
break;
}
} else {
other[i] = null; //Discard the ones that are not preferred
}
}
if (count == 1) {
return preferred;
} else {
return null;
}
}

private BorderInfo doRule5(BorderInfo[] current, BorderInfo[] other) {
for (int i = 0; i < current.length - 1; i++) {
if (current[i] != null) {
return current[i];
}
if (other[i] != null) {
return other[i];
}
}
return null;
}

}

+ 30
- 2
src/java/org/apache/fop/layoutmgr/table/Column.java 查看文件

@@ -1,5 +1,5 @@
/*
* Copyright 1999-2004 The Apache Software Foundation.
* Copyright 1999-2005 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.
@@ -24,6 +24,7 @@ import org.apache.fop.layoutmgr.BreakPoss;
import org.apache.fop.layoutmgr.LayoutContext;
import org.apache.fop.layoutmgr.PositionIterator;
import org.apache.fop.layoutmgr.TraitSetter;
import org.apache.fop.fo.flow.TableCell;
import org.apache.fop.fo.flow.TableColumn;
import org.apache.fop.area.Area;
import org.apache.fop.area.Block;
@@ -35,17 +36,36 @@ import org.apache.fop.area.Block;
* column properties.
*/
public class Column extends AbstractLayoutManager {
private TableColumn fobj;
private Length columnWidth;

/**
* Create a new column layout manager.
* @param node the table-column FO
*/
public Column(TableColumn node) {
super(node);
fobj = node;
columnWidth = fobj.getColumnWidth();
}

/** @return the table-column FO */
public TableColumn getFObj() {
return this.fobj;
}
/** @return true if the column is the first column */
public boolean isFirst() {
return ((TableLayoutManager)getParent()).isFirst(this);
}
/** @return true if the column is the last column */
public boolean isLast() {
return ((TableLayoutManager)getParent()).isLast(this);
}
/**
* Get the next break possibility.
* Columns do not create or return any areas.
@@ -80,13 +100,21 @@ public class Column extends AbstractLayoutManager {
return null;
}

/**
* Overrides the default column-with coming from the FO.
* @param width the new width to use
*/
public void setWidth(Length width) {
this.columnWidth = width;
}
/**
* Get the width of this column.
*
* @return the width of the column
*/
public Length getWidth() {
return fobj.getColumnWidth();
return columnWidth;
}

/**

+ 131
- 0
src/java/org/apache/fop/layoutmgr/table/GridUnit.java 查看文件

@@ -0,0 +1,131 @@
/*
* Copyright 2005 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id$ */

package org.apache.fop.layoutmgr.table;

import org.apache.fop.fo.flow.Table;
import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
import org.apache.fop.fo.properties.CommonBorderPaddingBackground.BorderInfo;


public class GridUnit {
/** layout manager for the cell occupying this grid unit, may be null */
public Cell layoutManager;
/** layout manager for the column that this grid unit belongs to */
public Column column;
/** layout manager for the row that this grid unit belongs to */
public Row row;
/** index of grid unit within cell in column direction */
public int colSpanIndex;
/** index of grid unit within cell in row direction */
public int rowSpanIndex;
/** effective borders for a cell slot (used for collapsing border model) */
public CommonBorderPaddingBackground effBorders;
public GridUnit(Cell layoutManager, int colSpanIndex) {
this.layoutManager = layoutManager;
this.colSpanIndex = colSpanIndex;
this.rowSpanIndex = 0;
}
public GridUnit(Cell layoutManager) {
this(layoutManager, 0);
}

/** @return true if the grid unit is the primary of a cell */
public boolean isPrimaryGridUnit() {
return (colSpanIndex == 0) && (rowSpanIndex == 0);
}
/** @return true if the grid unit is the last in column spanning direction */
public boolean isLastGridUnitColSpan() {
if (layoutManager != null) {
return (colSpanIndex == layoutManager.getFObj().getNumberColumnsSpanned() - 1);
} else {
return true;
}
}
/** @return true if the grid unit is the last in column spanning direction */
public boolean isLastGridUnitRowSpan() {
if (layoutManager != null) {
return (rowSpanIndex == layoutManager.getFObj().getNumberRowsSpanned() - 1);
} else {
return true;
}
}
/** @return true if the cell is part of a span in column direction */
public boolean isColSpan() {
return (colSpanIndex > 0);
}

public BorderInfo getOriginalBorderInfoForCell(int side) {
if (layoutManager != null) {
return layoutManager.getFObj().getCommonBorderPaddingBackground().getBorderInfo(side);
} else {
return null;
}
}
/**
* Assign the borders from the given cell to this cell info. Used in
* case of separate border model.
* @param current cell to take the borders from
*/
public void assignBorder(Cell current) {
if (current != null) {
this.effBorders = current.getFObj().getCommonBorderPaddingBackground();
}
}
/**
* Assign the borders directly.
* @param borders the borders to use
*/
public void assignBorder(CommonBorderPaddingBackground borders) {
if (borders != null) {
this.effBorders = borders;
}
}
/**
* Resolve collapsing borders for the given cell and store the resulting
* borders in this cell info. Use in case of the collapsing border model.
* @param current cell to resolve borders for
* @param before cell before the current cell, if any
* @param after cell after the current cell, if any
* @param start cell preceeding the current cell, if any
* @param end cell succeeding of the current cell, if any
*/
public static void resolveBorder(Table table,
CommonBorderPaddingBackground target,
GridUnit current, GridUnit other, int side) {
if (current == null) {
return;
}
CollapsingBorderModel borderModel = CollapsingBorderModel.getBorderModelFor(
table.getBorderCollapse());
target.setBorderInfo(
borderModel.determineWinner(current, other,
side, 0), side);
}
}

+ 130
- 88
src/java/org/apache/fop/layoutmgr/table/Row.java 查看文件

@@ -20,8 +20,10 @@ package org.apache.fop.layoutmgr.table;

import org.apache.fop.fo.FONode;
import org.apache.fop.fo.flow.Table;
import org.apache.fop.fo.flow.TableBody;
import org.apache.fop.fo.flow.TableCell;
import org.apache.fop.fo.flow.TableRow;
import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
import org.apache.fop.fo.properties.LengthRangeProperty;
import org.apache.fop.layoutmgr.BlockStackingLayoutManager;
import org.apache.fop.layoutmgr.LayoutManager;
@@ -52,16 +54,9 @@ import java.util.ListIterator;
*/
public class Row extends BlockStackingLayoutManager {
/** Used by CellInfo: Indicates start of cell. */
public static final int CI_START_OF_CELL = 0;
/** Used by CellInfo: Indicates part of a spanned cell in column direction. */
public static final int CI_COL_SPAN = 1;
/** Used by CellInfo: Indicates part of a spanned cell in row direction. */
public static final int CI_ROW_SPAN = 2;
private TableRow fobj;
private List cellList = null;
private List gridUnits = null;
private List columns = null;
private int referenceIPD;
private int rowHeight;
@@ -85,6 +80,11 @@ public class Row extends BlockStackingLayoutManager {
fobj = node;
}

/** @return the table-row FO */
public TableRow getFObj() {
return this.fobj;
}
/**
* @return the table owning this row
*/
@@ -105,8 +105,32 @@ public class Row extends BlockStackingLayoutManager {
columns = cols;
}

private void setupCells() {
cellList = new java.util.ArrayList();
/** @return true if this is the layout manager for the first row in a body. */
public boolean isFirstInBody() {
return ((TableBody)getFObj().getParent()).isFirst(getFObj());
}
/** @return true if this is the layout manager for the last row in a body. */
public boolean isLastInBody() {
return ((TableBody)getFObj().getParent()).isLast(getFObj());
}
/**
* Gets the Column at a given index.
* @param index index of the column (index must be >= 1)
* @return the requested Column
*/
private Column getColumn(int index) {
int size = columns.size();
if (index > size - 1) {
return (Column)columns.get(size - 1);
} else {
return (Column)columns.get(index - 1);
}
}
private void prepareGridUnits() {
gridUnits = new java.util.ArrayList();
List availableCells = new java.util.ArrayList();
// add cells to list
while (childLMiter.hasNext()) {
@@ -125,55 +149,108 @@ public class Row extends BlockStackingLayoutManager {
if (cell.hasColumnNumber()) {
colnum = cell.getColumnNumber();
}
while (colnum > cellList.size()) {
cellList.add(null);
while (colnum > gridUnits.size()) {
gridUnits.add(null);
}
if (cellList.get(colnum - 1) != null) {
if (gridUnits.get(colnum - 1) != null) {
log.error("Overlapping cell at position " + colnum);
}
//Add cell info for primary slot
cellList.set(colnum - 1, new CellInfo(cellLM));
GridUnit info = new GridUnit(cellLM);
info.row = this;
gridUnits.set(colnum - 1, info);
info.column = getColumn(colnum);
//Add cell infos on spanned slots if any
for (int j = 1; j < cell.getNumberColumnsSpanned(); j++) {
colnum++;
if (colnum > cellList.size()) {
cellList.add(new CellInfo(CI_COL_SPAN));
GridUnit infoSpan = new GridUnit(cellLM, j);
infoSpan.row = this;
infoSpan.column = getColumn(colnum);
if (colnum > gridUnits.size()) {
gridUnits.add(infoSpan);
} else {
if (cellList.get(colnum - 1) != null) {
if (gridUnits.get(colnum - 1) != null) {
log.error("Overlapping cell at position " + colnum);
//TODO throw layout exception
}
cellList.set(colnum - 1, new CellInfo(CI_COL_SPAN));
gridUnits.set(colnum - 1, infoSpan);
}
}
colnum++;
}
//Post-processing the list (looking for gaps)
int pos = 1;
ListIterator ppIter = cellList.listIterator();
while (ppIter.hasNext()) {
CellInfo cellInfo = (CellInfo)ppIter.next();
if (cellInfo == null) {
//Add cell info on empty cell
ppIter.set(new CellInfo(CI_START_OF_CELL));
//Post-processing the list (looking for gaps and resolve start and end borders)
postProcessGridUnits();
}

private void postProcessGridUnits() {
for (int pos = 1; pos <= gridUnits.size(); pos++) {
GridUnit gu = (GridUnit)gridUnits.get(pos - 1);
//Empty grid units
if (gu == null) {
//Add grid unit
gu = new GridUnit(null);
gu.row = this;
gu.column = getColumn(pos);
gridUnits.set(pos - 1, gu);
}
}
//Border resolution now that the empty grid units are filled
for (int pos = 1; pos <= gridUnits.size(); pos++) {
GridUnit gu = (GridUnit)gridUnits.get(pos - 1);
//Border resolution
if (getTable().isSeparateBorderModel()) {
gu.assignBorder(gu.layoutManager);
} else {
GridUnit start = null;
int find = pos - 1;
while (find >= 1) {
GridUnit candidate = (GridUnit)gridUnits.get(find - 1);
if (candidate.isLastGridUnitColSpan()) {
start = candidate;
break;
}
find--;
}
GridUnit end = null;
find = pos + 1;
while (find <= gridUnits.size()) {
GridUnit candidate = (GridUnit)gridUnits.get(find - 1);
if (candidate.isPrimaryGridUnit()) {
end = candidate;
break;
}
}
CommonBorderPaddingBackground borders = new CommonBorderPaddingBackground();
GridUnit.resolveBorder(getTable(), borders, gu,
(start != null ? start : null),
CommonBorderPaddingBackground.START);
GridUnit.resolveBorder(getTable(), borders, gu,
(end != null ? end : null),
CommonBorderPaddingBackground.END);
gu.effBorders = borders;
//Only start and end borders here, before and after during layout
//TODO resolve before and after borders during layout
}
pos++;
}
}

/**
* Get the cell info for a cell.
*
* @param pos the position of the cell (must be >= 1)
* @return the cell info object
*/
protected CellInfo getCellInfo(int pos) {
if (cellList == null) {
setupCells();
protected GridUnit getCellInfo(int pos) {
if (gridUnits == null) {
prepareGridUnits();
}
if (pos <= cellList.size()) {
return (CellInfo)cellList.get(pos - 1);
if (pos <= gridUnits.size()) {
return (GridUnit)gridUnits.get(pos - 1);
} else {
return null;
}
@@ -189,11 +266,10 @@ public class Row extends BlockStackingLayoutManager {
*/
public BreakPoss getNextBreakPoss(LayoutContext context) {
//LayoutManager curLM; // currently active LM
CellInfo curCellInfo; //currently active cell info
GridUnit curGridUnit; //currently active grid unit

BreakPoss lastPos = null;
List breakList = new java.util.ArrayList();
List spannedColumns = new java.util.ArrayList();

int min = 0;
int opt = 0;
@@ -205,9 +281,9 @@ public class Row extends BlockStackingLayoutManager {
int startColumn = 1;
boolean over = false;

while ((curCellInfo = getCellInfo(startColumn)) != null) {
Cell cellLM = curCellInfo.layoutManager;
if (curCellInfo.isColSpan()) {
while ((curGridUnit = getCellInfo(startColumn)) != null) {
Cell cellLM = curGridUnit.layoutManager;
if (curGridUnit.isColSpan()) {
//skip spanned slots
startColumn++;
continue;
@@ -227,15 +303,17 @@ public class Row extends BlockStackingLayoutManager {
stackSize));

//Determine which columns this cell will occupy
getColumnsForCell(cellLM, startColumn, spannedColumns);
List spannedGridUnits = new java.util.ArrayList();
getGridUnitsForCell(cellLM, startColumn, spannedGridUnits);
int childRefIPD = 0;
for (int i = 0; i < spannedColumns.size(); i++) {
Column col = (Column)spannedColumns.get(i);
for (int i = 0; i < spannedGridUnits.size(); i++) {
Column col = ((GridUnit)spannedGridUnits.get(i)).column;
childRefIPD += col.getWidth().getValue();
}
childLC.setRefIPD(childRefIPD);

if (cellLM != null) {
cellLM.addGridUnitsFromRow(spannedGridUnits);
cellLM.setInRowIPDOffset(ipdOffset);
while (!cellLM.isFinished()) {
if ((bp = cellLM.getNextBreakPoss(childLC)) != null) {
@@ -309,8 +387,8 @@ public class Row extends BlockStackingLayoutManager {
boolean fin = true;
startColumn = 1;
//Check if any of the cell LMs haven't finished, yet
while ((curCellInfo = getCellInfo(startColumn)) != null) {
Cell cellLM = curCellInfo.layoutManager;
while ((curGridUnit = getCellInfo(startColumn)) != null) {
Cell cellLM = curGridUnit.layoutManager;
if (cellLM == null) {
//skip empty cell
startColumn++;
@@ -333,27 +411,13 @@ public class Row extends BlockStackingLayoutManager {
return breakPoss;
}

/**
* Gets the Column at a given index.
* @param index index of the column (index must be >= 1)
* @return the requested Column
*/
private Column getColumn(int index) {
int size = columns.size();
if (index > size - 1) {
return (Column)columns.get(size - 1);
} else {
return (Column)columns.get(index - 1);
}
}
/**
* Determines the columns that are spanned by the given cell.
* @param cellLM table-cell LM
* @param startCell starting cell index (must be >= 1)
* @param spannedColumns List to receive the applicable columns
*/
private void getColumnsForCell(Cell cellLM, int startCell, List spannedColumns) {
private void getGridUnitsForCell(Cell cellLM, int startCell, List spannedColumns) {
int count;
if (cellLM != null) {
count = cellLM.getFObj().getNumberColumnsSpanned();
@@ -362,7 +426,7 @@ public class Row extends BlockStackingLayoutManager {
}
spannedColumns.clear();
for (int i = 0; i < count; i++) {
spannedColumns.add(getColumn(startCell + i));
spannedColumns.add(this.gridUnits.get(startCell + i - 1));
}
}

@@ -376,13 +440,13 @@ public class Row extends BlockStackingLayoutManager {
*/
protected void reset(Position pos) {
//LayoutManager curLM; // currently active LM
CellInfo curCellInfo;
GridUnit curGridUnit;
int cellIndex = 1;

if (pos == null) {
while ((curCellInfo = getCellInfo(cellIndex)) != null) {
if (curCellInfo.layoutManager != null) {
curCellInfo.layoutManager.resetPosition(null);
while ((curGridUnit = getCellInfo(cellIndex)) != null) {
if (curGridUnit.layoutManager != null) {
curGridUnit.layoutManager.resetPosition(null);
}
cellIndex++;
}
@@ -390,10 +454,10 @@ public class Row extends BlockStackingLayoutManager {
RowPosition rpos = (RowPosition)pos;
List breaks = rpos.cellBreaks;

while ((curCellInfo = getCellInfo(cellIndex)) != null) {
if (curCellInfo.layoutManager != null) {
while ((curGridUnit = getCellInfo(cellIndex)) != null) {
if (curGridUnit.layoutManager != null) {
List childbreaks = (List)breaks.get(cellIndex);
curCellInfo.layoutManager.resetPosition(
curGridUnit.layoutManager.resetPosition(
(Position)childbreaks.get(childbreaks.size() - 1));
}
cellIndex++;
@@ -540,27 +604,5 @@ public class Row extends BlockStackingLayoutManager {
}
}

private class CellInfo {
/** layout manager for this cell, may be null */
public Cell layoutManager;
/** flags for this cell, on of Row.CI_* */
public int flags = CI_START_OF_CELL;
public CellInfo(Cell layoutManager) {
this.layoutManager = layoutManager;
}
public CellInfo(int flags) {
this.flags = flags;
}
/** @return true if the cell is part of a span in column direction */
public boolean isColSpan() {
return (flags & CI_COL_SPAN) != 0;
}

}
}


+ 20
- 2
src/java/org/apache/fop/layoutmgr/table/TableLayoutManager.java 查看文件

@@ -280,10 +280,28 @@ public class TableLayoutManager extends BlockStackingLayoutManager {
//new property evaluation context so proportional-column-width() works
//correctly.
if (columns.size() == 0) {
this.columns.add(new Column(getTable().getDefaultColumn()));
Column col = new Column(getTable().getDefaultColumn());
col.setParent(this);
this.columns.add(col);
}
}
/**
* @param column the column to check
* @return true if the column is the first column
*/
public boolean isFirst(Column column) {
return (this.columns.size() == 0 || this.columns.get(0) == column);
}
/**
* @param column the column to check
* @return true if the column is the last column
*/
public boolean isLast(Column column) {
return (this.columns.size() == 0 || this.columns.get(columns.size() - 1) == column);
}
/**
* Get the break possibility and height of the table header or footer.
*
@@ -455,6 +473,6 @@ public class TableLayoutManager extends BlockStackingLayoutManager {
reset(null);
}
}
}


正在加载...
取消
保存