/* * {{{ header & license * Copyright (c) 2007 Wisconsin Court System * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * }}} */ package org.xhtmlrenderer.newtable; import java.awt.Rectangle; import java.util.List; import java.util.Set; import org.xhtmlrenderer.css.constants.CSSName; import org.xhtmlrenderer.css.constants.IdentValue; import org.xhtmlrenderer.css.style.CalculatedStyle; import org.xhtmlrenderer.css.style.CssContext; import org.xhtmlrenderer.css.style.Length; import org.xhtmlrenderer.css.style.derived.BorderPropertySet; import org.xhtmlrenderer.css.style.derived.RectPropertySet; import org.xhtmlrenderer.layout.CollapsedBorderSide; import org.xhtmlrenderer.layout.FloatManager; import org.xhtmlrenderer.layout.LayoutContext; import org.xhtmlrenderer.render.BlockBox; import org.xhtmlrenderer.render.BorderPainter; import org.xhtmlrenderer.render.Box; import org.xhtmlrenderer.render.ContentLimit; import org.xhtmlrenderer.render.ContentLimitContainer; import org.xhtmlrenderer.render.PageBox; import org.xhtmlrenderer.render.RenderingContext; public class TableCellBox extends BlockBox { public static final TableCellBox SPANNING_CELL = new TableCellBox(); private int _row; private int _col; private TableBox _table; private TableSectionBox _section; private BorderPropertySet _collapsedLayoutBorder; private BorderPropertySet _collapsedPaintingBorder; private CollapsedBorderValue _collapsedBorderTop; private CollapsedBorderValue _collapsedBorderRight; private CollapsedBorderValue _collapsedBorderBottom; private CollapsedBorderValue _collapsedBorderLeft; // 'double', 'solid', 'dashed', 'dotted', 'ridge', 'outset', 'groove', and the lowest: 'inset'. private static final int[] BORDER_PRIORITIES = new int[IdentValue.getIdentCount()]; static { BORDER_PRIORITIES[IdentValue.DOUBLE.FS_ID] = 1; BORDER_PRIORITIES[IdentValue.SOLID.FS_ID] = 2; BORDER_PRIORITIES[IdentValue.DASHED.FS_ID] = 3; BORDER_PRIORITIES[IdentValue.DOTTED.FS_ID] = 4; BORDER_PRIORITIES[IdentValue.RIDGE.FS_ID] = 5; BORDER_PRIORITIES[IdentValue.OUTSET.FS_ID] = 6; BORDER_PRIORITIES[IdentValue.GROOVE.FS_ID] = 7; BORDER_PRIORITIES[IdentValue.INSET.FS_ID] = 8; } private static final int BCELL = 10; private static final int BROW = 9; private static final int BROWGROUP = 8; private static final int BCOL = 7; private static final int BTABLE = 6; public TableCellBox() { } public BlockBox copyOf() { TableCellBox result = new TableCellBox(); result.setStyle(getStyle()); result.setElement(getElement()); return result; } public BorderPropertySet getBorder(CssContext cssCtx) { if (getTable().getStyle().isCollapseBorders()) { // Should always be non-null, but might not be if layout code crashed return _collapsedLayoutBorder == null ? BorderPropertySet.EMPTY_BORDER : _collapsedLayoutBorder; } else { return super.getBorder(cssCtx); } } public void calcCollapsedBorder(CssContext c) { CollapsedBorderValue top = collapsedTopBorder(c); CollapsedBorderValue right = collapsedRightBorder(c); CollapsedBorderValue bottom = collapsedBottomBorder(c); CollapsedBorderValue left = collapsedLeftBorder(c); _collapsedPaintingBorder = new BorderPropertySet(top, right, bottom, left); // Give the extra pixel to top and left. top.setWidth((top.width()+1)/2); right.setWidth(right.width()/2); bottom.setWidth(bottom.width()/2); left.setWidth((left.width()+1)/2); _collapsedLayoutBorder = new BorderPropertySet(top, right, bottom, left); _collapsedBorderTop = top; _collapsedBorderRight = right; _collapsedBorderBottom = bottom; _collapsedBorderLeft = left; } public int getCol() { return _col; } public void setCol(int col) { _col = col; } public int getRow() { return _row; } public void setRow(int row) { _row = row; } public void layout(LayoutContext c) { super.layout(c); } public TableBox getTable() { // cell -> row -> section -> table if (_table == null) { _table = (TableBox)getParent().getParent().getParent(); } return _table; } protected TableSectionBox getSection() { if (_section == null) { _section = (TableSectionBox)getParent().getParent(); } return _section; } public Length getOuterStyleWidth(CssContext c) { Length result = getStyle().asLength(c, CSSName.WIDTH); if (result.isVariable() || result.isPercent()) { return result; } int bordersAndPadding = 0; BorderPropertySet border = getBorder(c); bordersAndPadding += (int)border.left() + (int)border.right(); RectPropertySet padding = getPadding(c); bordersAndPadding += (int)padding.left() + (int)padding.right(); result.setValue(result.value() + bordersAndPadding); return result; } public Length getOuterStyleOrColWidth(CssContext c) { Length result = getOuterStyleWidth(c); if (getStyle().getColSpan() > 1 || ! result.isVariable()) { return result; } TableColumn col = getTable().colElement(getCol()); if (col != null) { // XXX Need to add in collapsed borders from cell (if collapsing borders) result = col.getStyle().asLength(c, CSSName.WIDTH); } return result; } public void setLayoutWidth(LayoutContext c, int width) { calcDimensions(c); setContentWidth(width - getLeftMBP() - getRightMBP()); } public boolean isAutoHeight() { return getStyle().isAutoHeight() || ! getStyle().hasAbsoluteUnit(CSSName.HEIGHT); } public int calcBaseline(LayoutContext c) { int result = super.calcBaseline(c); if (result != NO_BASELINE) { return result; } else { Rectangle contentArea = getContentAreaEdge(getAbsX(), getAbsY(), c); return (int)contentArea.getY(); } } public int calcBlockBaseline(LayoutContext c) { return super.calcBaseline(c); } public void moveContent(LayoutContext c, final int deltaY) { for (int i = 0; i < getChildCount(); i++) { Box b = getChild(i); b.setY(b.getY() + deltaY); } getPersistentBFC().getFloatManager().performFloatOperation( new FloatManager.FloatOperation() { public void operate(Box floater) { floater.setY(floater.getY() + deltaY); } }); calcChildLocations(); } public boolean isPageBreaksChange(LayoutContext c, int posDeltaY) { if (! c.isPageBreaksAllowed()) { return false; } PageBox page = c.getRootLayer().getFirstPage(c, this); int bottomEdge = getAbsY() + getChildrenHeight(); return page != null && (bottomEdge >= page.getBottom() - c.getExtraSpaceBottom() || bottomEdge + posDeltaY >= page.getBottom() - c.getExtraSpaceBottom()); } public IdentValue getVerticalAlign() { IdentValue val = getStyle().getIdent(CSSName.VERTICAL_ALIGN); if (val == IdentValue.TOP || val == IdentValue.MIDDLE || val == IdentValue.BOTTOM) { return val; } else { return IdentValue.BASELINE; } } private boolean isPaintBackgroundsAndBorders() { boolean showEmpty = getStyle().isShowEmptyCells(); // XXX Not quite right, but good enough for now // (e.g. absolute boxes will be counted as content here when the spec // says the cell should be treated as empty). return showEmpty || getChildrenContentType() != BlockBox.CONTENT_EMPTY; } public void paintBackground(RenderingContext c) { if (isPaintBackgroundsAndBorders() && getStyle().isVisible()) { Rectangle bounds; if (c.isPrint() && getTable().getStyle().isPaginateTable()) { bounds = getContentLimitedBorderEdge(c); } else { bounds = getPaintingBorderEdge(c); } if (bounds != null) { paintBackgroundStack(c, bounds); } } } private void paintBackgroundStack(RenderingContext c, Rectangle bounds) { Rectangle imageContainer; BorderPropertySet border = getStyle().getBorder(c); TableColumn column = getTable().colElement(getCol()); if (column != null) { c.getOutputDevice().paintBackground( c, column.getStyle(), bounds, getTable().getColumnBounds(c, getCol()), border); } Box row = getParent(); Box section = row.getParent(); CalculatedStyle tableStyle = getTable().getStyle(); CalculatedStyle sectionStyle = section.getStyle(); imageContainer = section.getPaintingBorderEdge(c); imageContainer.y += tableStyle.getBorderVSpacing(c); imageContainer.height -= tableStyle.getBorderVSpacing(c); imageContainer.x += tableStyle.getBorderHSpacing(c); imageContainer.width -= 2*tableStyle.getBorderHSpacing(c); c.getOutputDevice().paintBackground(c, sectionStyle, bounds, imageContainer, sectionStyle.getBorder(c)); CalculatedStyle rowStyle = row.getStyle(); imageContainer = row.getPaintingBorderEdge(c); imageContainer.x += tableStyle.getBorderHSpacing(c); imageContainer.width -= 2*tableStyle.getBorderHSpacing(c); c.getOutputDevice().paintBackground(c, rowStyle, bounds, imageContainer, rowStyle.getBorder(c)); c.getOutputDevice().paintBackground(c, getStyle(), bounds, getPaintingBorderEdge(c), border); } public void paintBorder(RenderingContext c) { if (isPaintBackgroundsAndBorders() && ! hasCollapsedPaintingBorder()) { // Collapsed table borders are painted separately if (c.isPrint() && getTable().getStyle().isPaginateTable() && getStyle().isVisible()) { Rectangle bounds = getContentLimitedBorderEdge(c); if (bounds != null) { c.getOutputDevice().paintBorder(c, getStyle(), bounds, getBorderSides()); } } else { super.paintBorder(c); } } } public void paintCollapsedBorder(RenderingContext c, int side) { c.getOutputDevice().paintCollapsedBorder( c, getCollapsedPaintingBorder(), getCollapsedBorderBounds(c), side); } private Rectangle getContentLimitedBorderEdge(RenderingContext c) { Rectangle result = getPaintingBorderEdge(c); TableSectionBox section = getSection(); if (section.isHeader() || section.isFooter()) { return result; } ContentLimitContainer contentLimitContainer = ((TableRowBox)getParent()).getContentLimitContainer(); ContentLimit limit = contentLimitContainer.getContentLimit(c.getPageNo()); if (limit == null) { return null; } else { if (limit.getTop() == ContentLimit.UNDEFINED || limit.getBottom() == ContentLimit.UNDEFINED) { return result; } int top; if (c.getPageNo() == contentLimitContainer.getInitialPageNo()) { top = result.y; } else { top = limit.getTop() - ((TableRowBox)getParent()).getExtraSpaceTop() ; } int bottom; if (c.getPageNo() == contentLimitContainer.getLastPageNo()) { bottom = result.y + result.height; } else { bottom = limit.getBottom() + ((TableRowBox)getParent()).getExtraSpaceBottom(); } result.y = top; result.height = bottom - top; return result; } } public Rectangle getChildrenClipEdge(RenderingContext c) { if (c.isPrint() && getTable().getStyle().isPaginateTable()) { Rectangle bounds = getContentLimitedBorderEdge(c); if (bounds != null) { BorderPropertySet border = getBorder(c); RectPropertySet padding = getPadding(c); bounds.y += (int)border.top() + (int)padding.top(); bounds.height -= (int)border.height() + (int)padding.height(); return bounds; } } return super.getChildrenClipEdge(c); } protected boolean isFixedWidthAdvisoryOnly() { return getTable().getStyle().isIdent(CSSName.TABLE_LAYOUT, IdentValue.AUTO); } protected boolean isSkipWhenCollapsingMargins() { return true; } // The following rules apply for resolving conflicts and figuring out which // border // to use. // (1) Borders with the 'border-style' of 'hidden' take precedence over all // other conflicting // borders. Any border with this value suppresses all borders at this // location. // (2) Borders with a style of 'none' have the lowest priority. Only if the // border properties of all // the elements meeting at this edge are 'none' will the border be omitted // (but note that 'none' is // the default value for the border style.) // (3) If none of the styles are 'hidden' and at least one of them is not // 'none', then narrow borders // are discarded in favor of wider ones. If several have the same // 'border-width' then styles are preferred // in this order: 'double', 'solid', 'dashed', 'dotted', 'ridge', 'outset', // 'groove', and the lowest: 'inset'. // (4) If border styles differ only in color, then a style set on a cell // wins over one on a row, // which wins over a row group, column, column group and, lastly, table. It // is undefined which color // is used when two elements of the same type disagree. public static CollapsedBorderValue compareBorders( CollapsedBorderValue border1, CollapsedBorderValue border2, boolean returnNullOnEqual) { // Sanity check the values passed in. If either is null, return the other. if (!border2.defined()) { return border1; } if (!border1.defined()) { return border2; } // Rule #1 above. if (border1.style() == IdentValue.HIDDEN) { return border1; } if (border2.style() == IdentValue.HIDDEN) { return border2; } // Rule #2 above. A style of 'none' has lowest priority and always loses // to any other border. if (border2.style() == IdentValue.NONE) { return border1; } if (border1.style() == IdentValue.NONE) { return border2; } // The first part of rule #3 above. Wider borders win. if (border1.width() != border2.width()) { return border1.width() > border2.width() ? border1 : border2; } // The borders have equal width. Sort by border style. if (border1.style() != border2.style()) { return BORDER_PRIORITIES[border1.style().FS_ID] > BORDER_PRIORITIES[border2.style().FS_ID] ? border1 : border2; } // The border have the same width and style. Rely on precedence (cell // over row over row group, etc.) if (returnNullOnEqual && border1.precedence() == border2.precedence()) { return null; } else { return border1.precedence() >= border2.precedence() ? border1 : border2; } } private static CollapsedBorderValue compareBorders( CollapsedBorderValue border1, CollapsedBorderValue border2) { return compareBorders(border1, border2, false); } private CollapsedBorderValue collapsedLeftBorder(CssContext c) { BorderPropertySet border = getStyle().getBorder(c); // For border left, we need to check, in order of precedence: // (1) Our left border. CollapsedBorderValue result = CollapsedBorderValue.borderLeft(border, BCELL); // (2) The previous cell's right border. TableCellBox prevCell = getTable().cellLeft(this); if (prevCell != null) { result = compareBorders( result, CollapsedBorderValue.borderRight(prevCell.getStyle().getBorder(c), BCELL)); if (result.hidden()) { return result; } } else if (getCol() == 0) { // (3) Our row's left border. result = compareBorders( result, CollapsedBorderValue.borderLeft(getParent().getStyle().getBorder(c), BROW)); if (result.hidden()) { return result; } // (4) Our row group's left border. result = compareBorders( result, CollapsedBorderValue.borderLeft(getSection().getStyle().getBorder(c), BROWGROUP)); if (result.hidden()) { return result; } } // (5) Our column's left border. TableColumn colElt = getTable().colElement(getCol()); if (colElt != null) { result = compareBorders( result, CollapsedBorderValue.borderLeft(colElt.getStyle().getBorder(c), BCOL)); if (result.hidden()) { return result; } } // (6) The previous column's right border. if (getCol() > 0) { colElt = getTable().colElement(getCol() - 1); if (colElt != null) { result = compareBorders( result, CollapsedBorderValue.borderRight(colElt.getStyle().getBorder(c), BCOL)); if (result.hidden()) { return result; } } } if (getCol() == 0) { // (7) The table's left border. result = compareBorders( result, CollapsedBorderValue.borderLeft(getTable().getStyle().getBorder(c), BTABLE)); if (result.hidden()) { return result; } } return result; } private CollapsedBorderValue collapsedRightBorder(CssContext c) { TableBox tableElt = getTable(); boolean inLastColumn = false; int effCol = tableElt.colToEffCol(getCol() + getStyle().getColSpan() - 1); if (effCol == tableElt.numEffCols() - 1) { inLastColumn = true; } // For border right, we need to check, in order of precedence: // (1) Our right border. CollapsedBorderValue result = CollapsedBorderValue.borderRight(getStyle().getBorder(c), BCELL); // (2) The next cell's left border. if (!inLastColumn) { TableCellBox nextCell = tableElt.cellRight(this); if (nextCell != null) { result = compareBorders(result, CollapsedBorderValue.borderLeft(nextCell.getStyle().getBorder(c), BCELL)); if (result.hidden()) { return result; } } } else { // (3) Our row's right border. result = compareBorders(result, CollapsedBorderValue.borderRight(getParent().getStyle().getBorder(c), BROW)); if (result.hidden()) { return result; } // (4) Our row group's right border. result = compareBorders(result, CollapsedBorderValue.borderRight(getSection().getStyle().getBorder(c), BROWGROUP)); if (result.hidden()) { return result; } } // (5) Our column's right border. TableColumn colElt = getTable().colElement(getCol() + getStyle().getColSpan() - 1); if (colElt != null) { result = compareBorders(result, CollapsedBorderValue.borderRight(colElt.getStyle().getBorder(c), BCOL)); if (result.hidden()) { return result; } } // (6) The next column's left border. if (!inLastColumn) { colElt = tableElt.colElement(getCol() + getStyle().getColSpan()); if (colElt != null) { result = compareBorders(result, CollapsedBorderValue.borderLeft(colElt.getStyle().getBorder(c), BCOL)); if (result.hidden()) { return result; } } } else { // (7) The table's right border. result = compareBorders(result, CollapsedBorderValue.borderRight(tableElt.getStyle().getBorder(c), BTABLE)); if (result.hidden()) { return result; } } return result; } private CollapsedBorderValue collapsedTopBorder(CssContext c) { // For border top, we need to check, in order of precedence: // (1) Our top border. CollapsedBorderValue result = CollapsedBorderValue.borderTop(getStyle().getBorder(c), BCELL); TableCellBox prevCell = getTable().cellAbove(this); if (prevCell != null) { // (2) A previous cell's bottom border. result = compareBorders(result, CollapsedBorderValue.borderBottom(prevCell.getStyle().getBorder(c), BCELL)); if (result.hidden()) { return result; } } // (3) Our row's top border. result = compareBorders(result, CollapsedBorderValue.borderTop(getParent().getStyle().getBorder(c), BROW)); if (result.hidden()) { return result; } // (4) The previous row's bottom border. if (prevCell != null) { TableRowBox prevRow = null; if (prevCell.getSection() == getSection()) { prevRow = (TableRowBox) getParent().getPreviousSibling(); } else { prevRow = prevCell.getSection().getLastRow(); } if (prevRow != null) { result = compareBorders(result, CollapsedBorderValue.borderBottom(prevRow.getStyle().getBorder(c), BROW)); if (result.hidden()) { return result; } } } // Now check row groups. TableSectionBox currSection = getSection(); if (getRow() == 0) { // (5) Our row group's top border. result = compareBorders(result, CollapsedBorderValue.borderTop(currSection.getStyle().getBorder(c), BROWGROUP)); if (result.hidden()) { return result; } // (6) Previous row group's bottom border. currSection = getTable().sectionAbove(currSection, false); if (currSection != null) { result = compareBorders(result, CollapsedBorderValue.borderBottom(currSection.getStyle().getBorder(c), BROWGROUP)); if (result.hidden()) { return result; } } } if (currSection == null) { // (8) Our column's top border. TableColumn colElt = getTable().colElement(getCol()); if (colElt != null) { result = compareBorders(result, CollapsedBorderValue.borderTop(colElt.getStyle().getBorder(c), BCOL)); if (result.hidden()) { return result; } } // (9) The table's top border. result = compareBorders(result, CollapsedBorderValue.borderTop(getTable().getStyle().getBorder(c), BTABLE)); if (result.hidden()) { return result; } } return result; } private CollapsedBorderValue collapsedBottomBorder(CssContext c) { // For border top, we need to check, in order of precedence: // (1) Our bottom border. CollapsedBorderValue result = CollapsedBorderValue.borderBottom(getStyle().getBorder(c), BCELL); TableCellBox nextCell = getTable().cellBelow(this); if (nextCell != null) { // (2) A following cell's top border. result = compareBorders(result, CollapsedBorderValue.borderTop(nextCell.getStyle().getBorder(c), BCELL)); if (result.hidden()) { return result; } } // (3) Our row's bottom border. (FIXME: Deal with rowspan!) result = compareBorders(result, CollapsedBorderValue.borderBottom(getParent().getStyle().getBorder(c), BROW)); if (result.hidden()) { return result; } // (4) The next row's top border. if (nextCell != null) { result = compareBorders(result, CollapsedBorderValue.borderTop(nextCell.getParent().getStyle().getBorder(c), BROW)); if (result.hidden()) { return result; } } // Now check row groups. TableSectionBox currSection = getSection(); if (getRow() + getStyle().getRowSpan() >= currSection.numRows()) { // (5) Our row group's bottom border. result = compareBorders(result, CollapsedBorderValue.borderBottom(currSection.getStyle().getBorder(c), BROWGROUP)); if (result.hidden()) { return result; } // (6) Following row group's top border. currSection = getTable().sectionBelow(currSection, false); if (currSection != null) { result = compareBorders(result, CollapsedBorderValue.borderTop(currSection.getStyle().getBorder(c), BROWGROUP)); if (result.hidden()) { return result; } } } if (currSection == null) { // (8) Our column's bottom border. TableColumn colElt = getTable().colElement(getCol()); if (colElt != null) { result = compareBorders(result, CollapsedBorderValue.borderBottom(colElt.getStyle().getBorder(c), BCOL)); if (result.hidden()) { return result; } } // (9) The table's bottom border. result = compareBorders(result, CollapsedBorderValue.borderBottom(getTable().getStyle().getBorder(c), BTABLE)); if (result.hidden()) { return result; } } return result; } private Rectangle getCollapsedBorderBounds(CssContext c) { BorderPropertySet border = getCollapsedPaintingBorder(); Rectangle bounds = getPaintingBorderEdge(c); bounds.x -= (int) border.left() / 2; bounds.y -= (int) border.top() / 2; bounds.width += (int) border.left() / 2 + ((int) border.right() + 1) / 2; bounds.height += (int) border.top() / 2 + ((int) border.bottom() + 1) / 2; return bounds; } public Rectangle getPaintingClipEdge(CssContext c) { if (hasCollapsedPaintingBorder()) { return getCollapsedBorderBounds(c); } else { return super.getPaintingClipEdge(c); } } public boolean hasCollapsedPaintingBorder() { return _collapsedPaintingBorder != null; } protected BorderPropertySet getCollapsedPaintingBorder() { return _collapsedPaintingBorder; } public CollapsedBorderValue getCollapsedBorderBottom() { return _collapsedBorderBottom; } public CollapsedBorderValue getCollapsedBorderLeft() { return _collapsedBorderLeft; } public CollapsedBorderValue getCollapsedBorderRight() { return _collapsedBorderRight; } public CollapsedBorderValue getCollapsedBorderTop() { return _collapsedBorderTop; } public void addCollapsedBorders(Set all, List borders) { if (_collapsedBorderTop.exists() && !all.contains(_collapsedBorderTop)) { all.add(_collapsedBorderTop); borders.add(new CollapsedBorderSide(this, BorderPainter.TOP)); } if (_collapsedBorderRight.exists() && !all.contains(_collapsedBorderRight)) { all.add(_collapsedBorderRight); borders.add(new CollapsedBorderSide(this, BorderPainter.RIGHT)); } if (_collapsedBorderBottom.exists() && !all.contains(_collapsedBorderBottom)) { all.add(_collapsedBorderBottom); borders.add(new CollapsedBorderSide(this, BorderPainter.BOTTOM)); } if (_collapsedBorderLeft.exists() && !all.contains(_collapsedBorderLeft)) { all.add(_collapsedBorderLeft); borders.add(new CollapsedBorderSide(this, BorderPainter.LEFT)); } } // Treat height as if it specifies border height (i.e. // box-sizing: border-box in CSS3). There doesn't seem to be any // justification in the spec for this, but everybody does it // (in standards mode) so I guess we will too protected int getCSSHeight(CssContext c) { if (getStyle().isAutoHeight()) { return -1; } else { int result = (int)getStyle().getFloatPropertyProportionalWidth( CSSName.HEIGHT, getContainingBlock().getContentWidth(), c); BorderPropertySet border = getBorder(c); result -= (int)border.top() + (int)border.bottom(); RectPropertySet padding = getPadding(c); result -= (int)padding.top() + (int)padding.bottom(); return result >= 0 ? result : -1; } } protected boolean isAllowHeightToShrink() { return false; } public boolean isNeedsClipOnPaint(RenderingContext c) { boolean result = super.isNeedsClipOnPaint(c); if (result) { return result; } return c.isPrint() && getTable().getStyle().isPaginateTable() && ((TableRowBox)getParent()).getContentLimitContainer().isContainsMultiplePages(); } }