}
}
+ public static void extendMinimum(MinOptMax mom, int len, boolean optToLen) {
+ System.out.print("before: " + mom);
+ if (mom.min < len) {
+ mom.min = len;
+ mom.opt = Math.max(mom.min, mom.opt);
+ if (optToLen) {
+ mom.opt = Math.min(mom.min, len);
+ }
+ mom.max = Math.max(mom.opt, mom.max);
+ }
+ System.out.println(" - after: " + mom);
+ }
+
/**
* After a calculation on a MinOptMax, this can be called to set opt to
* a new effective value.
}
}
+ /**
+ * Converts a LengthRangeProperty to a MinOptMax.
+ * @param prop LengthRangeProperty
+ * @return the requested MinOptMax instance
+ */
+ public static MinOptMax toMinOptMax(LengthRangeProperty prop) {
+ MinOptMax mom = new MinOptMax(
+ (prop.getMinimum().isAuto()
+ ? 0 : prop.getMinimum().getLength().getValue()),
+ (prop.getOptimum().isAuto()
+ ? 0 : prop.getOptimum().getLength().getValue()),
+ (prop.getMinimum().isAuto()
+ ? Integer.MAX_VALUE
+ : prop.getMaximum().getLength().getValue()));
+ return mom;
+ }
+
}
rowHeight = h;
}
+ private int getContentHeight(int rowHeight, GridUnit gu) {
+ int bpd = rowHeight;
+ bpd -= gu.getPrimary().getHalfMaxBorderWidth();
+ CommonBorderPaddingBackground cbpb
+ = gu.getCell().getCommonBorderPaddingBackground();
+ bpd -= cbpb.getPaddingBefore(false);
+ bpd -= cbpb.getPaddingAfter(false);
+ return bpd;
+ }
+
/**
* Add the areas for the break points.
* The cell contains block stacking layout managers
} else {
TraitSetter.addBackground(curBlockArea, fobj.getCommonBorderPaddingBackground());
//TODO Set these booleans right
- boolean[] outer = new boolean[] {false, false, false, false};
+ boolean[] outer = new boolean[] {
+ gridUnit.getFlag(GridUnit.FIRST_IN_TABLE),
+ gridUnit.getFlag(GridUnit.LAST_IN_TABLE),
+ gridUnit.getFlag(GridUnit.IN_FIRST_COLUMN),
+ gridUnit.getFlag(GridUnit.IN_LAST_COLUMN)};
if (!gridUnit.hasSpanning()) {
//Can set the borders directly if there's no span
TraitSetter.addCollapsingBorders(curBlockArea,
Block block = new Block();
block.addTrait(Trait.IS_REFERENCE_AREA, Boolean.TRUE);
block.setPositioning(Block.ABSOLUTE);
- //block.setBPD(gu.row.getRowHeight());
- block.setBPD(rowHeight); //TODO This needs to be fixed for row spanning
- //lastRowHeight = gu.row.getRowHeight();
+
+ int bpd = getContentHeight(rowHeight, gu);
+ bpd += gridUnit.getHalfMaxBeforeBorderWidth()
+ - (gu.getBorders().getBorderBeforeWidth(false) / 2);
+ block.setBPD(bpd);
+ //TODO This needs to be fixed for row spanning
lastRowHeight = rowHeight;
int ipd = gu.getColumn().getColumnWidth().getValue();
int borderStartWidth = gu.getBorders().getBorderStartWidth(false) / 2;
ipd -= gu.getBorders().getBorderEndWidth(false) / 2;
block.setIPD(ipd);
block.setXOffset(dx + borderStartWidth);
- block.setYOffset(dy);
+ int halfCollapsingBorderHeight = 0;
+ if (!fobj.isSeparateBorderModel()) {
+ halfCollapsingBorderHeight +=
+ gu.getBorders().getBorderBeforeWidth(false) / 2;
+ }
+ block.setYOffset(dy - halfCollapsingBorderHeight);
TraitSetter.addCollapsingBorders(block, gu.getBorders(), outer);
parentLM.addChildArea(block);
dx += gu.getColumn().getColumnWidth().getValue();
}
AreaAdditionUtil.addAreas(parentIter, layoutContext);
- /*
- LayoutManager childLM;
- int iStartPos = 0;
- LayoutContext lc = new LayoutContext(0);
- PositionIterator childPosIter;
- childPosIter = new StackingIter(positionList.listIterator());
- while ((childLM = childPosIter.getNextChildLM()) != null) {
- // set last area flag
- lc.setFlags(LayoutContext.LAST_AREA,
- (layoutContext.isLastArea() && childLM == lastLM));
- lc.setStackLimit(layoutContext.getStackLimit());
- // Add the line areas to Area
- childLM.addAreas(childPosIter, lc);
- }
- while (parentIter.hasNext()) {
- LeafPosition lfp = (LeafPosition) parentIter.next();
- // Add the block areas to Area
- PositionIterator breakPosIter =
- new BreakPossPosIter(childBreaks, iStartPos,
- lfp.getLeafPos() + 1);
- iStartPos = lfp.getLeafPos() + 1;
- while ((childLM = breakPosIter.getNextChildLM()) != null) {
- childLM.addAreas(breakPosIter, lc);
- }
- }*/
-
- int contentBPD = rowHeight;
- contentBPD -= borderAndPaddingBPD;
+ int contentBPD = getContentHeight(rowHeight, gridUnit);
curBlockArea.setBPD(contentBPD);
flush();
}
int halfCollapsingBorderHeight = 0;
if (!fobj.isSeparateBorderModel()) {
- halfCollapsingBorderHeight +=
- gridUnit.getBorders().getBorderBeforeWidth(false) / 2;
+ if (gridUnit.hasSpanning()) {
+ halfCollapsingBorderHeight -= gridUnit.getHalfMaxBeforeBorderWidth();
+ } else {
+ halfCollapsingBorderHeight += gridUnit.getHalfMaxBeforeBorderWidth();
+ }
}
curBlockArea.setXOffset(xoffset + inRowIPDOffset + halfBorderSep + indent);
curBlockArea.setYOffset(yoffset - halfCollapsingBorderHeight);
}
}
- /* (non-Javadoc)
+ /**
* @see org.apache.fop.layoutmgr.BlockLevelLayoutManager#negotiateBPDAdjustment(int, org.apache.fop.layoutmgr.KnuthElement)
*/
public int negotiateBPDAdjustment(int adj, KnuthElement lastElement) {
*/
public abstract class CollapsingBorderModel {
+ /** before side */
+ protected static final int BEFORE = CommonBorderPaddingBackground.BEFORE;
+ /** after side */
+ protected static final int AFTER = CommonBorderPaddingBackground.AFTER;
+ /** start side */
+ protected static final int START = CommonBorderPaddingBackground.START;
+ /** end side */
+ protected static final int END = CommonBorderPaddingBackground.END;
+
+ /** Flag: current grid unit is either start or end of the table. */
+ public static final int VERTICAL_START_END_OF_TABLE = 1;
+
/** 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;
+ //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;
+ //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;
+ //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;
+ //public static final int LAST_ROW_IN_GROUP = 8;
private static CollapsingBorderModel collapse = null;
private static CollapsingBorderModel collapseWithPrecedence = null;
import org.apache.fop.fo.flow.TableCell;
import org.apache.fop.fo.flow.TableColumn;
import org.apache.fop.fo.flow.TableRow;
-import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
import org.apache.fop.fo.properties.CommonBorderPaddingBackground.BorderInfo;
/**
*/
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);
//row group (=body, table-header or table-footer)
current[2] = currentBody.getCommonBorderPaddingBackground().getBorderInfo(side);
}
- if ((otherSide == BEFORE && otherGridUnit.getFlag(GridUnit.FIRST_IN_BODY))
- || (otherSide == AFTER && otherGridUnit.getFlag(GridUnit.LAST_IN_BODY))) {
+ if (otherGridUnit != null
+ && ((otherSide == BEFORE && otherGridUnit.getFlag(GridUnit.FIRST_IN_BODY))
+ || (otherSide == AFTER && otherGridUnit.getFlag(GridUnit.LAST_IN_BODY)))) {
//row group (=body, table-header or table-footer)
other[2] = otherBody.getCommonBorderPaddingBackground().getBorderInfo(otherSide);
}
other[3] = otherColumn.getCommonBorderPaddingBackground().getBorderInfo(otherSide);
}
//TODO current[4] and other[4] for column groups
- if (otherGridUnit == null) {
+ if (otherGridUnit == null
+ && ((side == BEFORE && (flags & VERTICAL_START_END_OF_TABLE) > 0)
+ || (side == AFTER && (flags & VERTICAL_START_END_OF_TABLE) > 0)
+ || (side == START)
+ || (side == END))) {
//table
current[5] = table.getCommonBorderPaddingBackground().getBorderInfo(side);
}
// *** Rule 2 ***
if (!doRule2(current, other)) {
- return null; //paint no border
}
// *** Rule 3 ***
}
private BorderInfo doRule1(BorderInfo[] current, BorderInfo[] other) {
- for (int i = 0; i < current.length - 1; i++) {
+ for (int i = 0; i < current.length; i++) {
if ((current[i] != null) && (current[i].getStyle() == Constants.EN_HIDDEN)) {
return current[i];
}
private boolean doRule2(BorderInfo[] current, BorderInfo[] other) {
boolean found = false;
- for (int i = 0; i < current.length - 1; i++) {
+ for (int i = 0; i < current.length; i++) {
if ((current[i] != null) && (current[i].getStyle() != Constants.EN_NONE)) {
found = true;
break;
private BorderInfo doRule3(BorderInfo[] current, BorderInfo[] other) {
int width = 0;
//Find max border width
- for (int i = 0; i < current.length - 1; i++) {
+ for (int i = 0; i < current.length; i++) {
if ((current[i] != null) && (current[i].getRetainedWidth() > width)) {
width = current[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++) {
+ for (int i = 0; i < current.length; 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 (widest == null) {
widest = other[i];
}
- break;
} else {
other[i] = null; //Discard the narrower ones
}
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++) {
+ for (int i = 0; i < current.length; 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++) {
+ for (int i = 0; i < current.length; i++) {
if (current[i] != null) {
int currPref = getPreferenceValue(current[i].getStyle());
if (currPref == pref) {
}
private BorderInfo doRule5(BorderInfo[] current, BorderInfo[] other) {
- for (int i = 0; i < current.length - 1; i++) {
+ for (int i = 0; i < current.length; i++) {
if (current[i] != null) {
return current[i];
}
package org.apache.fop.layoutmgr.table;
import org.apache.fop.fo.flow.TableBody;
-import org.apache.fop.fo.flow.TableCell;
import org.apache.fop.fo.flow.TableColumn;
import org.apache.fop.fo.flow.TableRow;
* @param row Optional table-row instance
* @param column table-column instance
* @param body table-body the grid unit belongs to
- * @param startCol
- * @param colSpanIndex
+ * @param startCol column index
*/
public EmptyGridUnit(TableRow row, TableColumn column, TableBody body,
int startCol) {
- super(null, column, startCol, 0);
+ super(null, null, column, startCol, 0);
this.row = row;
this.body = body;
}
/** Indicates that the grid unit is in the last row (context: table). */
public static final int LAST_IN_TABLE = 5;
+ /** Primary grid unit */
+ private PrimaryGridUnit primary;
/** Table cell which occupies this grid unit */
private TableCell cell;
/** Table column that this grid unit belongs to */
public GridUnit(TableCell cell, TableColumn column, int startCol, int colSpanIndex) {
+ this(null, cell, column, startCol, colSpanIndex);
+ }
+
+ public GridUnit(PrimaryGridUnit primary, TableColumn column, int startCol, int colSpanIndex) {
+ this(primary, primary.getCell(), column, startCol, colSpanIndex);
+ }
+
+ protected GridUnit(PrimaryGridUnit primary, TableCell cell, TableColumn column, int startCol, int colSpanIndex) {
+ this.primary = primary;
this.cell = cell;
this.column = column;
this.startCol = startCol;
return (Table)node;
}
+ /**
+ * @return the primary grid unit if this is a spanned grid unit
+ */
+ public PrimaryGridUnit getPrimary() {
+ return (isPrimary() ? (PrimaryGridUnit)this : this.primary);
+ }
+
public boolean isPrimary() {
return false;
}
}
}
+ /**
+ * @return the index of the grid unit inside a cell in row direction
+ */
+ public int getRowSpanIndex() {
+ return this.rowSpanIndex;
+ }
+
/**
* Returns a BorderInfo instance for a side of the currently applicable cell before border
* resolution (i.e. the value from the FO). A return value of null indicates an empty cell.
* @param side the side to resolve (one of CommonBorderPaddingBackground.BEFORE|AFTER|START|END)
*/
public void resolveBorder(GridUnit other, int side) {
+ resolveBorder(other, side, 0);
+ }
+
+ /**
+ * Resolve collapsing borders for the given cell. Used in case of the collapsing border model.
+ * @param other neighbouring grid unit if any
+ * @param side the side to resolve (one of CommonBorderPaddingBackground.BEFORE|AFTER|START|END)
+ * @param resFlags flags for the border resolution
+ */
+ public void resolveBorder(GridUnit other, int side, int resFlags) {
CollapsingBorderModel borderModel = CollapsingBorderModel.getBorderModelFor(
getTable().getBorderCollapse());
if (this.effBorders == null) {
}
this.effBorders.setBorderInfo(
borderModel.determineWinner(this, other,
- side, 0), side);
+ side, resFlags), side);
}
public boolean getFlag(int which) {
return null;
} else {
//cloning the current GridUnit with adjustments
- GridUnit gu = new GridUnit(getCell(), getColumn(), startCol, colSpanIndex);
+ GridUnit gu = new GridUnit(getPrimary(), getColumn(), startCol, colSpanIndex);
gu.rowSpanIndex = rowSpanIndex + 1;
return gu;
}
import org.apache.fop.fo.flow.TableCell;
import org.apache.fop.fo.flow.TableColumn;
+import org.apache.fop.fo.properties.LengthRangeProperty;
/**
* This class represents a primary grid unit of a spanned cell.
private int startRow;
/** Links to the spanned grid units. (List of GridUnit arrays, one array represents a row) */
private List rows;
+ /** The calculated size of the cell's content. (cached value) */
+ private int contentLength = -1;
public PrimaryGridUnit(TableCell cell, TableColumn column, int startCol, int startRow) {
super(cell, column, startCol, 0);
return this.elements;
}
+ /**
+ * @return Returns the half the maximum before border width of this cell.
+ */
+ public int getHalfMaxBeforeBorderWidth() {
+ int value = 0;
+ if (getRows() != null) {
+ int before = 0;
+ //first row for before borders
+ GridUnit[] row = (GridUnit[])getRows().get(0);
+ for (int i = 0; i < row.length; i++) {
+ if (row[i].hasBorders()) {
+ before = Math.max(before,
+ row[i].getBorders().getBorderBeforeWidth(false));
+ }
+ }
+ value += before / 2;
+ } else {
+ if (hasBorders()) {
+ value += getBorders().getBorderBeforeWidth(false) / 2;
+ }
+ }
+ return value;
+ }
+
+ /**
+ * @return Returns the sum of half the maximum before and after border
+ * widths of this cell.
+ */
+ public int getHalfMaxBorderWidth() {
+ int value = getHalfMaxBeforeBorderWidth();
+ if (getRows() != null) {
+ //Last row for after borders
+ int after = 0;
+ GridUnit[] row = (GridUnit[])getRows().get(getRows().size() - 1);
+ for (int i = 0; i < row.length; i++) {
+ if (row[i].hasBorders()) {
+ after = Math.max(after, row[i].getBorders().getBorderAfterWidth(false));
+ }
+ }
+ value += after / 2;
+ } else {
+ if (hasBorders()) {
+ value += getBorders().getBorderAfterWidth(false) / 2;
+ }
+ }
+ return value;
+ }
+
+ /** @param value The length of the cell content to remember. */
+ public void setContentLength(int value) {
+ this.contentLength = value;
+ }
+
+ /** @return Returns the length of the cell content. */
+ public int getContentLength() {
+ return contentLength;
+ }
+
+ /**
+ * @return Returns the length of the cell content after the bpd/height attributes on cell
+ * and row have been taken into account.
+ */
+ public int getEffectiveContentLength() {
+ int value = getContentLength();
+ if (!getCell().getBlockProgressionDimension().getMinimum().isAuto()) {
+ value = Math.max(value,
+ getCell().getBlockProgressionDimension().getMinimum().getLength().getValue());
+ }
+ if (getRow() != null
+ && !getRow().getBlockProgressionDimension().getMinimum().isAuto()) {
+ value = Math.max(value,
+ getRow().getBlockProgressionDimension().getMinimum().getLength().getValue());
+ }
+ return value;
+ }
+
+ /** @return true if cell/row has an explicit BPD/height */
+ public boolean hasBPD() {
+ if (!getCell().getBlockProgressionDimension().getOptimum().isAuto()) {
+ return true;
+ }
+ if (getRow() != null
+ && !getRow().getBlockProgressionDimension().getOptimum().isAuto()) {
+ return true;
+ }
+ return false;
+ }
+
public List getRows() {
return this.rows;
}
import org.apache.fop.area.Trait;
import org.apache.fop.fo.flow.Table;
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.KnuthBox;
import org.apache.fop.layoutmgr.KnuthElement;
import org.apache.fop.layoutmgr.KnuthPossPosIter;
import org.apache.fop.layoutmgr.LayoutContext;
import org.apache.fop.layoutmgr.LayoutManager;
+import org.apache.fop.layoutmgr.MinOptMaxUtil;
import org.apache.fop.layoutmgr.Position;
import org.apache.fop.layoutmgr.PositionIterator;
import org.apache.fop.layoutmgr.TraitSetter;
private int startXOffset;
private int usedBPD;
+ /**
+ * Main constructor
+ * @param parent Parent layout manager
+ */
public TableContentLayoutManager(TableLayoutManager parent) {
this.tableLM = parent;
Table table = getTableLM().getTable();
}
}
+ /**
+ * @return the table layout manager
+ */
public TableLayoutManager getTableLM() {
return this.tableLM;
}
+ /**
+ * @return the column setup of this table
+ */
public ColumnSetup getColumns() {
return getTableLM().getColumns();
}
* @param iter TableRowIterator instance to fetch rows from
* @param context Active LayoutContext
* @param alignment alignment indicator
+ * @param isHeaderFooter true if currently handling headers/footers
* @return An element list
*/
private LinkedList getKnuthElementsForRowIterator(TableRowIterator iter,
- LayoutContext context, int alignment, boolean disableHeaderFooter) {
+ LayoutContext context, int alignment, boolean isHeaderFooter) {
LinkedList returnList = new LinkedList();
TableRowIterator.EffRow[] rowGroup = null;
- TableRowIterator.EffRow row = null;
while ((rowGroup = iter.getNextRowGroup()) != null) {
- for (int rgi = 0; rgi < rowGroup.length; rgi++) {
- row = rowGroup[rgi];
- List pgus = new java.util.ArrayList();
- TableRow tableRow = null;
- int maxCellHeight = 0;
- for (int j = 0; j < row.getGridUnits().size(); j++) {
- GridUnit gu = (GridUnit)row.getGridUnits().get(j);
- if (gu.isPrimary() && !gu.isEmpty()) {
- PrimaryGridUnit primary = (PrimaryGridUnit)gu;
- primary.getCellLM().setParent(tableLM);
+ resolveNormalBeforeAfterBordersForRowGroup(rowGroup, iter);
+ createElementsForRowGroup(context, alignment, isHeaderFooter,
+ returnList, rowGroup);
+ }
+
+ //Remove last penalty
+ KnuthElement last = (KnuthElement)returnList.getLast();
+ if (last.isPenalty() && last.getW() == 0 && last.getP() == 0) {
+ returnList.removeLast();
+ }
+ return returnList;
+ }
- //Calculate width of cell
- int spanWidth = 0;
- for (int i = primary.getStartCol();
- i < primary.getStartCol() + primary.getCell().getNumberColumnsSpanned();
- i++) {
- spanWidth += getTableLM().getColumns().getColumn(i + 1)
- .getColumnWidth().getValue();
- }
- log.info("spanWidth=" + spanWidth);
- LayoutContext childLC = new LayoutContext(0);
- childLC.setStackLimit(context.getStackLimit()); //necessary?
- childLC.setRefIPD(spanWidth);
+ /**
+ * Resolves normal borders for a row group.
+ * @param iter Table row iterator to operate on
+ */
+ private void resolveNormalBeforeAfterBordersForRowGroup(TableRowIterator.EffRow[] rowGroup,
+ TableRowIterator iter) {
+ for (int rgi = 0; rgi < rowGroup.length; rgi++) {
+ TableRowIterator.EffRow row = rowGroup[rgi];
+ TableRowIterator.EffRow prev = iter.getCachedRow(row.getIndex() - 1);
+ TableRowIterator.EffRow next = iter.getCachedRow(row.getIndex() + 1);
+ if (next == null) {
+ //It wasn't read, yet, or we are at the last row
+ next = iter.getNextRow();
+ iter.backToPreviewRow();
+ }
+ if ((prev == null) && (iter == this.trIter) && (this.headerIter != null)) {
+ prev = this.headerIter.getLastRow();
+ }
+ if ((prev == null) && (iter == this.headerIter)) {
+ prev = this.trIter.getFirstRow();
+ }
+ if ((next == null) && (iter == this.trIter) && (this.footerIter != null)) {
+ next = this.footerIter.getFirstRow();
+ }
+ if ((next == null) && (iter == this.footerIter)) {
+ //TODO This could be bad for memory consumption because it already causes the
+ //whole body iterator to be prefetched!
+ prev = this.trIter.getLastRow();
+ }
+ log.debug(prev + " - " + row + " - " + next);
+
+ //Determine the grid units necessary for getting all the borders right
+ int guCount = row.getGridUnits().size();
+ if (prev != null) {
+ guCount = Math.max(guCount, prev.getGridUnits().size());
+ }
+ if (next != null) {
+ guCount = Math.max(guCount, next.getGridUnits().size());
+ }
+ GridUnit gu = (GridUnit)row.getGridUnits().get(0);
+ //Create empty grid units to hold resolved borders of neighbouring cells
+ //TODO maybe this needs to be done differently (and sooner)
+ for (int i = 0; i < guCount - row.getGridUnits().size(); i++) {
+ //TODO This block in untested!
+ int pos = row.getGridUnits().size() + i;
+ row.getGridUnits().add(new EmptyGridUnit(gu.getRow(),
+ this.tableLM.getColumns().getColumn(pos + 1), gu.getBody(),
+ pos));
+ }
+
+ //Now resolve normal borders
+ if (getTableLM().getTable().isSeparateBorderModel()) {
+ //nop, borders are already assigned at this point
+ } else {
+ for (int i = 0; i < row.getGridUnits().size(); i++) {
+ gu = (GridUnit)row.getGridUnits().get(i);
+ GridUnit other;
+ int flags = 0;
+ if (prev != null && i < prev.getGridUnits().size()) {
+ other = (GridUnit)prev.getGridUnits().get(i);
+ } else {
+ other = null;
+ }
+ if ((iter == this.trIter)
+ && gu.getFlag(GridUnit.FIRST_IN_TABLE)
+ && (this.headerIter == null)) {
+ flags |= CollapsingBorderModel.VERTICAL_START_END_OF_TABLE;
+ }
+ if ((iter == this.headerIter)
+ && gu.getFlag(GridUnit.FIRST_IN_TABLE)) {
+ flags |= CollapsingBorderModel.VERTICAL_START_END_OF_TABLE;
+ }
+ gu.resolveBorder(other,
+ CommonBorderPaddingBackground.BEFORE, flags);
+
+ flags = 0;
+ if (next != null && i < next.getGridUnits().size()) {
+ other = (GridUnit)next.getGridUnits().get(i);
+ } else {
+ other = null;
+ }
+ if ((iter == this.trIter)
+ && gu.getFlag(GridUnit.LAST_IN_TABLE)
+ && (this.footerIter == null)) {
+ flags |= CollapsingBorderModel.VERTICAL_START_END_OF_TABLE;
+ }
+ if ((iter == this.footerIter)
+ && gu.getFlag(GridUnit.LAST_IN_TABLE)) {
+ flags |= CollapsingBorderModel.VERTICAL_START_END_OF_TABLE;
+ }
+ gu.resolveBorder(other,
+ CommonBorderPaddingBackground.AFTER, flags);
+ }
+
+ }
+ }
+ }
+
+ /**
+ * Creates Knuth elements for a row group (see TableRowIterator.getNextRowGroup()).
+ * @param context Active LayoutContext
+ * @param alignment alignment indicator
+ * @param isHeaderFooter true if currently processing headers/footers
+ * @param returnList List to received the generated elements
+ * @param rowGroup row group to process
+ */
+ private void createElementsForRowGroup(LayoutContext context, int alignment,
+ boolean isHeaderFooter, LinkedList returnList,
+ TableRowIterator.EffRow[] rowGroup) {
+ MinOptMax[] rowHeights = new MinOptMax[rowGroup.length];
+ TableRowIterator.EffRow row;
+ List pgus = new java.util.ArrayList(); //holds a list of a row's primary grid units
+ for (int rgi = 0; rgi < rowGroup.length; rgi++) {
+ row = rowGroup[rgi];
+ rowHeights[rgi] = new MinOptMax(0, 0, Integer.MAX_VALUE);
+
+ pgus.clear();
+ TableRow tableRow = null;
+ int minContentHeight = 0;
+ int maxCellHeight = 0;
+ for (int j = 0; j < row.getGridUnits().size(); j++) {
+ GridUnit gu = (GridUnit)row.getGridUnits().get(j);
+ if (gu.isPrimary() && !gu.isEmpty()) {
+ PrimaryGridUnit primary = (PrimaryGridUnit)gu;
+ primary.getCellLM().setParent(tableLM);
+
+ //Determine the table-row if any
+ if (tableRow == null) {
+ tableRow = primary.getRow();
- LinkedList elems = primary.getCellLM().getNextKnuthElements(childLC, alignment);
- primary.setElements(elems);
- log.debug("Elements: " + elems);
- int len = calcCellHeightFromContents(elems);
- pgus.add(primary);
- maxCellHeight = Math.max(maxCellHeight, len);
- if (len > row.getHeight().opt) {
- row.setHeight(new MinOptMax(len));
+ //Check for bpd on row, see CSS21, 17.5.3 Table height algorithms
+ LengthRangeProperty bpd = tableRow.getBlockProgressionDimension();
+ if (!bpd.getMinimum().isAuto()) {
+ minContentHeight = Math.max(minContentHeight,
+ bpd.getMinimum().getLength().getValue());
}
+ }
+
+ //Calculate width of cell
+ int spanWidth = 0;
+ for (int i = primary.getStartCol();
+ i < primary.getStartCol() + primary.getCell().getNumberColumnsSpanned();
+ i++) {
+ spanWidth += getTableLM().getColumns().getColumn(i + 1)
+ .getColumnWidth().getValue();
+ }
+ log.info("spanWidth=" + spanWidth);
+ LayoutContext childLC = new LayoutContext(0);
+ childLC.setStackLimit(context.getStackLimit()); //necessary?
+ childLC.setRefIPD(spanWidth);
+
+ //Get the element list for the cell contents
+ LinkedList elems = primary.getCellLM().getNextKnuthElements(childLC, alignment);
+ primary.setElements(elems);
+ log.debug("Elements: " + elems);
+
+ //Calculate height of cell contents
+ primary.setContentLength(calcCellHeightFromContents(elems));
+ maxCellHeight = Math.max(maxCellHeight, primary.getContentLength());
+
+ //Calculate height of row, see CSS21, 17.5.3 Table height algorithms
+ if (gu.isLastGridUnitRowSpan()) {
+ int effCellContentHeight = minContentHeight;
LengthRangeProperty bpd = primary.getCell().getBlockProgressionDimension();
- if (!bpd.getOptimum().isAuto()) {
- if (bpd.getOptimum().getLength().getValue() > row.getHeight().opt) {
- row.setHeight(new MinOptMax(bpd.getOptimum().getLength().getValue()));
- }
+ if (!bpd.getMinimum().isAuto()) {
+ effCellContentHeight = Math.max(effCellContentHeight,
+ bpd.getMinimum().getLength().getValue());
}
- if (tableRow == null) {
- tableRow = primary.getRow();
+ effCellContentHeight = Math.max(effCellContentHeight,
+ primary.getContentLength());
+ int halfMaxBorderWidths = primary.getHalfMaxBorderWidth();
+ int padding = 0;
+ CommonBorderPaddingBackground cbpb
+ = primary.getCell().getCommonBorderPaddingBackground();
+ padding += cbpb.getPaddingBefore(false);
+ padding += cbpb.getPaddingAfter(false);
+ int effRowHeight = effCellContentHeight + padding + halfMaxBorderWidths;
+ if (effRowHeight > rowHeights[rgi].min) {
+ //This is the new height of the (grid) row
+ MinOptMaxUtil.extendMinimum(rowHeights[rgi], effRowHeight, false);
+ row.setHeight(rowHeights[rgi]);
}
}
+
+ pgus.add(primary);
}
-
- if (tableRow != null) {
- LengthRangeProperty bpd = tableRow.getBlockProgressionDimension();
- if (!bpd.getOptimum().isAuto()) {
- if (bpd.getOptimum().getLength().getValue() > row.getHeight().opt) {
- row.setHeight(new MinOptMax(bpd.getOptimum().getLength().getValue()));
- }
- }
- }
- log.debug(row);
-
- PrimaryGridUnit[] pguArray = new PrimaryGridUnit[pgus.size()];
- pguArray = (PrimaryGridUnit[])pgus.toArray(pguArray);
- LinkedList returnedList = getCombinedKnuthElementsForRow(pguArray, row,
- disableHeaderFooter);
- if (returnedList != null) {
- returnList.addAll(returnedList);
- }
+ }
+
+ log.debug(row);
+
+ PrimaryGridUnit[] pguArray = new PrimaryGridUnit[pgus.size()];
+ pguArray = (PrimaryGridUnit[])pgus.toArray(pguArray);
+ LinkedList returnedList = getCombinedKnuthElementsForRow(pguArray, row,
+ isHeaderFooter);
+ if (returnedList != null) {
+ returnList.addAll(returnedList);
+ }
- if (row.getHeight().opt > maxCellHeight) {
- int space = row.getHeight().opt - maxCellHeight;
- KnuthPenalty penalty = (KnuthPenalty)returnList.removeLast();
- //Insert dummy box before penalty
- returnList.add(new KnuthBox(space, new Position(getTableLM()), false));
- returnList.add(penalty);
+ /* not necessary anymore
+ if (row.getHeight().opt > maxCellHeight) {
+ int space = row.getHeight().opt - maxCellHeight;
+ KnuthPenalty penalty = (KnuthPenalty)returnList.removeLast();
+ //Insert dummy box before penalty
+ returnList.add(new KnuthBox(space, new Position(getTableLM()), false));
+ returnList.add(penalty);
+ }*/
+
+ //Calculate row height in row groups with spans
+ /*
+ if (tableRow != null) {
+ LengthRangeProperty bpd = tableRow.getBlockProgressionDimension();
+ if (bpd.getOptimum().isAuto()) {
+ rowHeights[rgi] = new MinOptMax(0, 0, Integer.MAX_VALUE);
+ } else {
+ rowHeights[rgi] = MinOptMaxUtil.toMinOptMax(bpd);
}
- }
- }
-
- //Remove last penalty
- KnuthElement last = (KnuthElement)returnList.getLast();
- if (last.isPenalty() && last.getW() == 0 && last.getP() == 0) {
- returnList.removeLast();
+ } else {
+ rowHeights[rgi] = new MinOptMax(0, 0, Integer.MAX_VALUE);
+ }*/
+ /*
+ for (int j = 0; j < row.getGridUnits().size(); j++) {
+ GridUnit gu = (GridUnit)row.getGridUnits().get(j);
+ if (gu.isLastGridUnitRowSpan() && !gu.isEmpty()) {
+ log.debug(rgi + " - " + gu);
+ MinOptMax effCellHeight;
+ LengthRangeProperty bpd = gu.getCell().getBlockProgressionDimension();
+ if (bpd.getOptimum().isAuto()) {
+ effCellHeight = new MinOptMax(0, 0, Integer.MAX_VALUE);
+ } else {
+ effCellHeight = MinOptMaxUtil.toMinOptMax(bpd);
+ }
+ int contentLen = gu.getPrimary().getContentLength();
+ if (getTableLM().getTable().isSeparateBorderModel()) {
+ //contentLen += before and after borders of that cell plus half the BPD border-separation
+ } else {
+ //contentLen += half of before and after borders for that cell
+ }
+ for (int previous = 0; previous < gu.getRowSpanIndex(); previous++) {
+ contentLen -= rowHeights[rgi - previous - 1].opt;
+ }
+ log.debug("->" + contentLen);
+ if (contentLen > effCellHeight.min) {
+ MinOptMaxUtil.extendMinimum(effCellHeight, contentLen, true);
+ }
+ if (effCellHeight.min > rowHeights[rgi].min) {
+ MinOptMaxUtil.extendMinimum(rowHeights[rgi], effCellHeight.min, false);
+ }
+ }
+ }*/
}
- return returnList;
}
private LinkedList getCombinedKnuthElementsForRow(PrimaryGridUnit[] pguArray,
- TableRowIterator.EffRow row, boolean disableHeaderFooter) {
+ TableRowIterator.EffRow row, boolean isHeaderFooter) {
List[] elementLists = new List[pguArray.length];
for (int i = 0; i < pguArray.length; i++) {
- //Copy elements to array lists to improve element access performance
- elementLists[i] = new java.util.ArrayList(pguArray[i].getElements());
+ if (pguArray[i].hasBPD()) {
+ List list = new java.util.ArrayList(1);
+ list.add(new KnuthBoxCellWithBPD(
+ pguArray[i].getEffectiveContentLength(), pguArray[i]));
+ elementLists[i] = list;
+ } else {
+ //Copy elements (LinkedList) to array lists to improve element access performance
+ elementLists[i] = new java.util.ArrayList(pguArray[i].getElements());
+ }
}
int[] index = new int[pguArray.length];
int[] start = new int[pguArray.length];
int totalHeight = 0;
for (int i = 0; i < pguArray.length; i++) {
- fullWidths[i] = calcCellHeightFromContents(pguArray[i].getElements());
+ fullWidths[i] = pguArray[i].getContentLength();
totalHeight = Math.max(totalHeight, fullWidths[i]);
}
int laststep = 0;
List gridUnitParts = new java.util.ArrayList(pguArray.length);
for (int i = 0; i < pguArray.length; i++) {
if (end[i] >= start[i]) {
- gridUnitParts.add(new GridUnitPart(pguArray[i], start[i], end[i]));
+ if (start[i] == 0 && end[i] == 0
+ && elementLists[i].size() == 1
+ && elementLists[i].get(0) instanceof KnuthBoxCellWithBPD) {
+ gridUnitParts.add(new GridUnitPart(pguArray[i],
+ 0, pguArray[i].getElements().size() - 1));
+ } else {
+ gridUnitParts.add(new GridUnitPart(pguArray[i], start[i], end[i]));
+ }
}
}
gridUnitParts, row);
returnList.add(new KnuthBox(boxLen, tcpos, false));
TableHFPenaltyPosition penaltyPos = new TableHFPenaltyPosition(getTableLM());
- if (!disableHeaderFooter) {
+ if (!isHeaderFooter) {
if (!getTableLM().getTable().omitHeaderAtBreak()) {
penaltyLen += this.headerNetHeight;
penaltyPos.headerElements = this.headerList;
private void handleTableContentPosition(TableContentPosition tcpos) {
rowFO = null;
if (lastRow != tcpos.row && lastRow != null) {
- //yoffset += lastRow.getHeight().opt;
- yoffset += lastRowHeight;
- this.accumulatedBPD += lastRowHeight;
+ yoffset += lastRow.getHeight().opt;
+ this.accumulatedBPD += lastRow.getHeight().opt;
}
lastRow = tcpos.row;
Iterator partIter = tcpos.gridUnitParts.iterator();
//Calculate the height of the row
int maxLen = addAreasAndFlushRow(false);
- lastRowHeight = maxLen;
+ lastRowHeight = tcpos.row.getHeight().opt;
}
private int addAreasAndFlushRow(boolean finalFlush) {
partLength[i] = len;
log.debug("len of part: " + len);
maxLen = Math.max(maxLen, len);
- maxLen = Math.max(maxLen, getExplicitCellHeight(gridUnits[i]));
+ //maxLen = Math.max(maxLen, getExplicitCellHeight(gridUnits[i]));
}
}
+ start[i] + "-" + end[i]);
}
addAreasForCell(gridUnits[i], start[i], end[i],
- layoutContext, lastRow, yoffset, partLength[i], maxLen);
+ layoutContext, lastRow, yoffset,
+ partLength[i], lastRow.getHeight().opt);
gridUnits[i] = null;
start[i] = 0;
end[i] = 0;
}
}
-
+
+ /*
private int getExplicitCellHeight(PrimaryGridUnit pgu) {
int len = 0;
if (!pgu.getCell().getBlockProgressionDimension().getOptimum().isAuto()) {
.getOptimum().getLength().getValue());
}
return len;
- }
+ }*/
private void addAreasForCell(PrimaryGridUnit gu, int start, int end,
LayoutContext layoutContext, TableRowIterator.EffRow row,
return sb.toString();
}
}
+
+ private class KnuthBoxCellWithBPD extends KnuthBox {
+
+ private PrimaryGridUnit pgu;
+
+ public KnuthBoxCellWithBPD(int w, PrimaryGridUnit pgu) {
+ super(w, null, true);
+ this.pgu = pgu;
+ }
+}
}
}
}
+ public void backToPreviewRow() {
+ currentIndex--;
+ }
+
+ public EffRow getFirstRow() {
+ if (rows.size() == 0) {
+ prefetchNext();
+ }
+ return getCachedRow(0);
+ }
+
+ public EffRow getLastRow() {
+ while (prefetchNext()) {
+ //nop
+ }
+ return getCachedRow(rows.size() - 1);
+ }
+
public EffRow getCachedRow(int index) {
- return (EffRow)rows.get(index);
+ if (index < 0 || index >= rows.size()) {
+ return null;
+ } else {
+ return (EffRow)rows.get(index);
+ }
}
private boolean prefetchNext() {
+ boolean firstInTable = false;
+ boolean firstInBody = false;
if (childInBodyIterator != null) {
if (!childInBodyIterator.hasNext()) {
//force skip on to next body
if (childInBodyIterator == null) {
if (bodyIterator.hasNext()) {
childInBodyIterator = ((TableBody)bodyIterator.next()).getChildNodes();
+ if (rows.size() == 0) {
+ firstInTable = true;
+ }
+ firstInBody = true;
} else {
//no more rows
+ if (rows.size() > 0) {
+ getCachedRow(rows.size() - 1).setFlagForAllGridUnits(
+ GridUnit.LAST_IN_BODY, true);
+ getCachedRow(rows.size() - 1).setFlagForAllGridUnits(
+ GridUnit.LAST_IN_TABLE, true);
+ }
return false;
}
}
throw new IllegalStateException("Illegal class found: " + node.getClass().getName());
}
EffRow gridUnits = buildGridRow(this.currentRow);
+ if (firstInBody) {
+ gridUnits.setFlagForAllGridUnits(GridUnit.FIRST_IN_BODY, true);
+ }
+ if (firstInTable) {
+ gridUnits.setFlagForAllGridUnits(GridUnit.FIRST_IN_TABLE, true);
+ }
log.debug(gridUnits);
rows.add(gridUnits);
return true;
horzSpan[0] = gu;
for (int j = 1; j < cell.getNumberColumnsSpanned(); j++) {
colnum++;
- GridUnit guSpan = new GridUnit(cell, columns.getColumn(colnum), colnum - 1, j);
+ GridUnit guSpan = new GridUnit(gu, columns.getColumn(colnum), colnum - 1, j);
if (safelyGetListItem(gridUnits, colnum - 1) != null) {
log.error("Overlapping cell at position " + colnum);
//TODO throw layout exception
return gridUnits;
}
+ public void setFlagForAllGridUnits(int flag, boolean value) {
+ Iterator iter = gridUnits.iterator();
+ while (iter.hasNext()) {
+ GridUnit gu = (GridUnit)iter.next();
+ gu.setFlag(flag, value);
+ }
+ }
+
/** @see java.lang.Object#toString() */
public String toString() {
StringBuffer sb = new StringBuffer("EffRow {");