|  | /* | 
|  | * Copyright (C) 1997 Martin Jones (mjones@kde.org) | 
|  | *           (C) 1997 Torben Weis (weis@kde.org) | 
|  | *           (C) 1998 Waldo Bastian (bastian@kde.org) | 
|  | *           (C) 1999 Lars Knoll (knoll@kde.org) | 
|  | *           (C) 1999 Antti Koivisto (koivisto@kde.org) | 
|  | * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2009, 2013 Apple Inc. All rights reserved. | 
|  | * | 
|  | * This library is free software; you can redistribute it and/or | 
|  | * modify it under the terms of the GNU Library General Public | 
|  | * License as published by the Free Software Foundation; either | 
|  | * version 2 of the License, or (at your option) any later version. | 
|  | * | 
|  | * This library 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 | 
|  | * Library General Public License for more details. | 
|  | * | 
|  | * You should have received a copy of the GNU Library General Public License | 
|  | * along with this library; see the file COPYING.LIB.  If not, write to | 
|  | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | 
|  | * Boston, MA 02110-1301, USA. | 
|  | */ | 
|  |  | 
|  | #ifndef RenderTableCell_h | 
|  | #define RenderTableCell_h | 
|  |  | 
|  | #include "core/rendering/RenderBlockFlow.h" | 
|  | #include "core/rendering/RenderTableRow.h" | 
|  | #include "core/rendering/RenderTableSection.h" | 
|  | #include "platform/LengthFunctions.h" | 
|  |  | 
|  | namespace blink { | 
|  |  | 
|  | static const unsigned unsetColumnIndex = 0x1FFFFFFF; | 
|  | static const unsigned maxColumnIndex = 0x1FFFFFFE; // 536,870,910 | 
|  |  | 
|  | enum IncludeBorderColorOrNot { DoNotIncludeBorderColor, IncludeBorderColor }; | 
|  |  | 
|  | class SubtreeLayoutScope; | 
|  |  | 
|  | class RenderTableCell final : public RenderBlockFlow { | 
|  | public: | 
|  | explicit RenderTableCell(Element*); | 
|  |  | 
|  | unsigned colSpan() const | 
|  | { | 
|  | if (!m_hasColSpan) | 
|  | return 1; | 
|  | return parseColSpanFromDOM(); | 
|  | } | 
|  | unsigned rowSpan() const | 
|  | { | 
|  | if (!m_hasRowSpan) | 
|  | return 1; | 
|  | return parseRowSpanFromDOM(); | 
|  | } | 
|  |  | 
|  | // Called from HTMLTableCellElement. | 
|  | void colSpanOrRowSpanChanged(); | 
|  |  | 
|  | void setCol(unsigned column) | 
|  | { | 
|  | if (UNLIKELY(column > maxColumnIndex)) | 
|  | CRASH(); | 
|  |  | 
|  | m_column = column; | 
|  | } | 
|  |  | 
|  | unsigned col() const | 
|  | { | 
|  | ASSERT(m_column != unsetColumnIndex); | 
|  | return m_column; | 
|  | } | 
|  |  | 
|  | RenderTableRow* row() const { return toRenderTableRow(parent()); } | 
|  | RenderTableSection* section() const { return toRenderTableSection(parent()->parent()); } | 
|  | RenderTable* table() const { return toRenderTable(parent()->parent()->parent()); } | 
|  |  | 
|  | RenderTableCell* previousCell() const; | 
|  | RenderTableCell* nextCell() const; | 
|  |  | 
|  | unsigned rowIndex() const | 
|  | { | 
|  | // This function shouldn't be called on a detached cell. | 
|  | ASSERT(row()); | 
|  | return row()->rowIndex(); | 
|  | } | 
|  |  | 
|  | Length styleOrColLogicalWidth() const | 
|  | { | 
|  | Length styleWidth = style()->logicalWidth(); | 
|  | if (!styleWidth.isAuto()) | 
|  | return styleWidth; | 
|  | if (RenderTableCol* firstColumn = table()->colElement(col())) | 
|  | return logicalWidthFromColumns(firstColumn, styleWidth); | 
|  | return styleWidth; | 
|  | } | 
|  |  | 
|  | int logicalHeightForRowSizing() const | 
|  | { | 
|  | // FIXME: This function does too much work, and is very hot during table layout! | 
|  | int adjustedLogicalHeight = pixelSnappedLogicalHeight() - (intrinsicPaddingBefore() + intrinsicPaddingAfter()); | 
|  | int styleLogicalHeight = valueForLength(style()->logicalHeight(), 0); | 
|  | // In strict mode, box-sizing: content-box do the right thing and actually add in the border and padding. | 
|  | // Call computedCSSPadding* directly to avoid including implicitPadding. | 
|  | if (!document().inQuirksMode() && style()->boxSizing() != BORDER_BOX) | 
|  | styleLogicalHeight += (computedCSSPaddingBefore() + computedCSSPaddingAfter()).floor() + borderBefore() + borderAfter(); | 
|  | return max(styleLogicalHeight, adjustedLogicalHeight); | 
|  | } | 
|  |  | 
|  |  | 
|  | void setCellLogicalWidth(int constrainedLogicalWidth, SubtreeLayoutScope&); | 
|  |  | 
|  | virtual int borderLeft() const override; | 
|  | virtual int borderRight() const override; | 
|  | virtual int borderTop() const override; | 
|  | virtual int borderBottom() const override; | 
|  | virtual int borderStart() const override; | 
|  | virtual int borderEnd() const override; | 
|  | virtual int borderBefore() const override; | 
|  | virtual int borderAfter() const override; | 
|  |  | 
|  | void collectBorderValues(RenderTable::CollapsedBorderValues&) const; | 
|  | static void sortBorderValues(RenderTable::CollapsedBorderValues&); | 
|  |  | 
|  | virtual void layout() override; | 
|  |  | 
|  | virtual void paint(PaintInfo&, const LayoutPoint&) override; | 
|  |  | 
|  | void paintCollapsedBorders(PaintInfo&, const LayoutPoint&); | 
|  | void paintBackgroundsBehindCell(PaintInfo&, const LayoutPoint&, RenderObject* backgroundObject); | 
|  |  | 
|  | LayoutUnit cellBaselinePosition() const; | 
|  | bool isBaselineAligned() const | 
|  | { | 
|  | EVerticalAlign va = style()->verticalAlign(); | 
|  | return va == BASELINE || va == TEXT_BOTTOM || va == TEXT_TOP || va == SUPER || va == SUB || va == LENGTH; | 
|  | } | 
|  |  | 
|  | void computeIntrinsicPadding(int rowHeight, SubtreeLayoutScope&); | 
|  | void clearIntrinsicPadding() { setIntrinsicPadding(0, 0); } | 
|  |  | 
|  | int intrinsicPaddingBefore() const { return m_intrinsicPaddingBefore; } | 
|  | int intrinsicPaddingAfter() const { return m_intrinsicPaddingAfter; } | 
|  |  | 
|  | virtual LayoutUnit paddingTop() const override; | 
|  | virtual LayoutUnit paddingBottom() const override; | 
|  | virtual LayoutUnit paddingLeft() const override; | 
|  | virtual LayoutUnit paddingRight() const override; | 
|  |  | 
|  | // FIXME: For now we just assume the cell has the same block flow direction as the table. It's likely we'll | 
|  | // create an extra anonymous RenderBlock to handle mixing directionality anyway, in which case we can lock | 
|  | // the block flow directionality of the cells to the table's directionality. | 
|  | virtual LayoutUnit paddingBefore() const override; | 
|  | virtual LayoutUnit paddingAfter() const override; | 
|  |  | 
|  | void setOverrideLogicalContentHeightFromRowHeight(LayoutUnit); | 
|  |  | 
|  | virtual void scrollbarsChanged(bool horizontalScrollbarChanged, bool verticalScrollbarChanged) override; | 
|  |  | 
|  | bool cellWidthChanged() const { return m_cellWidthChanged; } | 
|  | void setCellWidthChanged(bool b = true) { m_cellWidthChanged = b; } | 
|  |  | 
|  | static RenderTableCell* createAnonymous(Document*); | 
|  | static RenderTableCell* createAnonymousWithParentRenderer(const RenderObject*); | 
|  | virtual RenderBox* createAnonymousBoxWithSameTypeAs(const RenderObject* parent) const override | 
|  | { | 
|  | return createAnonymousWithParentRenderer(parent); | 
|  | } | 
|  |  | 
|  | // This function is used to unify which table part's style we use for computing direction and | 
|  | // writing mode. Writing modes are not allowed on row group and row but direction is. | 
|  | // This means we can safely use the same style in all cases to simplify our code. | 
|  | // FIXME: Eventually this function should replaced by style() once we support direction | 
|  | // on all table parts and writing-mode on cells. | 
|  | const RenderStyle* styleForCellFlow() const | 
|  | { | 
|  | return row()->style(); | 
|  | } | 
|  |  | 
|  | const BorderValue& borderAdjoiningTableStart() const | 
|  | { | 
|  | ASSERT(isFirstOrLastCellInRow()); | 
|  | if (section()->hasSameDirectionAs(table())) | 
|  | return style()->borderStart(); | 
|  |  | 
|  | return style()->borderEnd(); | 
|  | } | 
|  |  | 
|  | const BorderValue& borderAdjoiningTableEnd() const | 
|  | { | 
|  | ASSERT(isFirstOrLastCellInRow()); | 
|  | if (section()->hasSameDirectionAs(table())) | 
|  | return style()->borderEnd(); | 
|  |  | 
|  | return style()->borderStart(); | 
|  | } | 
|  |  | 
|  | const BorderValue& borderAdjoiningCellBefore(const RenderTableCell* cell) | 
|  | { | 
|  | ASSERT_UNUSED(cell, table()->cellAfter(cell) == this); | 
|  | // FIXME: https://webkit.org/b/79272 - Add support for mixed directionality at the cell level. | 
|  | return style()->borderStart(); | 
|  | } | 
|  |  | 
|  | const BorderValue& borderAdjoiningCellAfter(const RenderTableCell* cell) | 
|  | { | 
|  | ASSERT_UNUSED(cell, table()->cellBefore(cell) == this); | 
|  | // FIXME: https://webkit.org/b/79272 - Add support for mixed directionality at the cell level. | 
|  | return style()->borderEnd(); | 
|  | } | 
|  |  | 
|  | #if ENABLE(ASSERT) | 
|  | bool isFirstOrLastCellInRow() const | 
|  | { | 
|  | return !table()->cellAfter(this) || !table()->cellBefore(this); | 
|  | } | 
|  | #endif | 
|  | protected: | 
|  | virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle) override; | 
|  | virtual void computePreferredLogicalWidths() override; | 
|  |  | 
|  | virtual void addLayerHitTestRects(LayerHitTestRects&, const RenderLayer* currentCompositedLayer, const LayoutPoint& layerOffset, const LayoutRect& containerRect) const override; | 
|  |  | 
|  | private: | 
|  | virtual const char* renderName() const override { return (isAnonymous() || isPseudoElement()) ? "RenderTableCell (anonymous)" : "RenderTableCell"; } | 
|  |  | 
|  | virtual bool isOfType(RenderObjectType type) const override { return type == RenderObjectTableCell || RenderBlockFlow::isOfType(type); } | 
|  |  | 
|  | virtual void willBeRemovedFromTree() override; | 
|  |  | 
|  | virtual void updateLogicalWidth() override; | 
|  |  | 
|  | virtual void paintBoxDecorationBackground(PaintInfo&, const LayoutPoint&) override; | 
|  | virtual void paintMask(PaintInfo&, const LayoutPoint&) override; | 
|  |  | 
|  | virtual bool boxShadowShouldBeAppliedToBackground(BackgroundBleedAvoidance, InlineFlowBox*) const override; | 
|  |  | 
|  | virtual LayoutSize offsetFromContainer(const RenderObject*, const LayoutPoint&, bool* offsetDependsOnPoint = 0) const override; | 
|  | virtual LayoutRect clippedOverflowRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer, const PaintInvalidationState* = 0) const override; | 
|  | virtual void mapRectToPaintInvalidationBacking(const RenderLayerModelObject* paintInvalidationContainer, LayoutRect&, const PaintInvalidationState*) const override; | 
|  |  | 
|  | int borderHalfLeft(bool outer) const; | 
|  | int borderHalfRight(bool outer) const; | 
|  | int borderHalfTop(bool outer) const; | 
|  | int borderHalfBottom(bool outer) const; | 
|  |  | 
|  | int borderHalfStart(bool outer) const; | 
|  | int borderHalfEnd(bool outer) const; | 
|  | int borderHalfBefore(bool outer) const; | 
|  | int borderHalfAfter(bool outer) const; | 
|  |  | 
|  | void setIntrinsicPaddingBefore(int p) { m_intrinsicPaddingBefore = p; } | 
|  | void setIntrinsicPaddingAfter(int p) { m_intrinsicPaddingAfter = p; } | 
|  | void setIntrinsicPadding(int before, int after) { setIntrinsicPaddingBefore(before); setIntrinsicPaddingAfter(after); } | 
|  |  | 
|  | bool hasStartBorderAdjoiningTable() const; | 
|  | bool hasEndBorderAdjoiningTable() const; | 
|  |  | 
|  | CollapsedBorderValue collapsedStartBorder(IncludeBorderColorOrNot = IncludeBorderColor) const; | 
|  | CollapsedBorderValue collapsedEndBorder(IncludeBorderColorOrNot = IncludeBorderColor) const; | 
|  | CollapsedBorderValue collapsedBeforeBorder(IncludeBorderColorOrNot = IncludeBorderColor) const; | 
|  | CollapsedBorderValue collapsedAfterBorder(IncludeBorderColorOrNot = IncludeBorderColor) const; | 
|  |  | 
|  | CollapsedBorderValue cachedCollapsedLeftBorder(const RenderStyle*) const; | 
|  | CollapsedBorderValue cachedCollapsedRightBorder(const RenderStyle*) const; | 
|  | CollapsedBorderValue cachedCollapsedTopBorder(const RenderStyle*) const; | 
|  | CollapsedBorderValue cachedCollapsedBottomBorder(const RenderStyle*) const; | 
|  |  | 
|  | CollapsedBorderValue computeCollapsedStartBorder(IncludeBorderColorOrNot = IncludeBorderColor) const; | 
|  | CollapsedBorderValue computeCollapsedEndBorder(IncludeBorderColorOrNot = IncludeBorderColor) const; | 
|  | CollapsedBorderValue computeCollapsedBeforeBorder(IncludeBorderColorOrNot = IncludeBorderColor) const; | 
|  | CollapsedBorderValue computeCollapsedAfterBorder(IncludeBorderColorOrNot = IncludeBorderColor) const; | 
|  |  | 
|  | Length logicalWidthFromColumns(RenderTableCol* firstColForThisCell, Length widthFromStyle) const; | 
|  |  | 
|  | void updateColAndRowSpanFlags(); | 
|  |  | 
|  | unsigned parseRowSpanFromDOM() const; | 
|  | unsigned parseColSpanFromDOM() const; | 
|  |  | 
|  | void nextSibling() const WTF_DELETED_FUNCTION; | 
|  | void previousSibling() const WTF_DELETED_FUNCTION; | 
|  |  | 
|  | // Note MSVC will only pack members if they have identical types, hence we use unsigned instead of bool here. | 
|  | unsigned m_column : 29; | 
|  | unsigned m_cellWidthChanged : 1; | 
|  | unsigned m_hasColSpan: 1; | 
|  | unsigned m_hasRowSpan: 1; | 
|  | int m_intrinsicPaddingBefore; | 
|  | int m_intrinsicPaddingAfter; | 
|  | }; | 
|  |  | 
|  | DEFINE_RENDER_OBJECT_TYPE_CASTS(RenderTableCell, isTableCell()); | 
|  |  | 
|  | inline RenderTableCell* RenderTableCell::previousCell() const | 
|  | { | 
|  | return toRenderTableCell(RenderObject::previousSibling()); | 
|  | } | 
|  |  | 
|  | inline RenderTableCell* RenderTableCell::nextCell() const | 
|  | { | 
|  | return toRenderTableCell(RenderObject::nextSibling()); | 
|  | } | 
|  |  | 
|  | inline RenderTableCell* RenderTableRow::firstCell() const | 
|  | { | 
|  | ASSERT(children() == virtualChildren()); | 
|  | return toRenderTableCell(children()->firstChild()); | 
|  | } | 
|  |  | 
|  | inline RenderTableCell* RenderTableRow::lastCell() const | 
|  | { | 
|  | ASSERT(children() == virtualChildren()); | 
|  | return toRenderTableCell(children()->lastChild()); | 
|  | } | 
|  |  | 
|  | } // namespace blink | 
|  |  | 
|  | #endif // RenderTableCell_h |