| /* |
| * 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, 2009 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. |
| */ |
| |
| #pragma once |
| |
| #include "RenderTable.h" |
| #include <wtf/Vector.h> |
| |
| namespace WebCore { |
| |
| class RenderTableCell; |
| class RenderTableRow; |
| |
| enum CollapsedBorderSide { |
| CBSBefore, |
| CBSAfter, |
| CBSStart, |
| CBSEnd |
| }; |
| |
| // Helper class for paintObject. |
| struct CellSpan { |
| public: |
| explicit CellSpan(unsigned start, unsigned end) |
| : start(start) |
| , end(end) |
| { |
| } |
| |
| unsigned start; |
| unsigned end; |
| }; |
| |
| class RenderTableSection final : public RenderBox { |
| WTF_MAKE_ISO_ALLOCATED(RenderTableSection); |
| public: |
| RenderTableSection(Element&, RenderStyle&&); |
| RenderTableSection(Document&, RenderStyle&&); |
| virtual ~RenderTableSection(); |
| |
| RenderTableRow* firstRow() const; |
| RenderTableRow* lastRow() const; |
| |
| std::optional<LayoutUnit> firstLineBaseline() const override; |
| |
| void addCell(RenderTableCell*, RenderTableRow* row); |
| |
| LayoutUnit calcRowLogicalHeight(); |
| void layoutRows(); |
| void computeOverflowFromCells(); |
| |
| RenderTable* table() const { return downcast<RenderTable>(parent()); } |
| |
| struct CellStruct { |
| Vector<RenderTableCell*, 1> cells; |
| bool inColSpan { false }; // true for columns after the first in a colspan |
| |
| RenderTableCell* primaryCell() { return hasCells() ? cells[cells.size() - 1] : 0; } |
| const RenderTableCell* primaryCell() const { return hasCells() ? cells[cells.size() - 1] : 0; } |
| bool hasCells() const { return cells.size() > 0; } |
| }; |
| |
| typedef Vector<CellStruct> Row; |
| struct RowStruct { |
| Row row; |
| RenderTableRow* rowRenderer { nullptr }; |
| LayoutUnit baseline; |
| Length logicalHeight; |
| }; |
| |
| const BorderValue& borderAdjoiningTableStart() const; |
| const BorderValue& borderAdjoiningTableEnd() const; |
| const BorderValue& borderAdjoiningStartCell(const RenderTableCell&) const; |
| const BorderValue& borderAdjoiningEndCell(const RenderTableCell&) const; |
| |
| const RenderTableCell* firstRowCellAdjoiningTableStart() const; |
| const RenderTableCell* firstRowCellAdjoiningTableEnd() const; |
| |
| CellStruct& cellAt(unsigned row, unsigned col); |
| const CellStruct& cellAt(unsigned row, unsigned col) const; |
| RenderTableCell* primaryCellAt(unsigned row, unsigned col); |
| RenderTableRow* rowRendererAt(unsigned row) const; |
| |
| void appendColumn(unsigned pos); |
| void splitColumn(unsigned pos, unsigned first); |
| |
| LayoutUnit calcOuterBorderBefore() const; |
| LayoutUnit calcOuterBorderAfter() const; |
| LayoutUnit calcOuterBorderStart() const; |
| LayoutUnit calcOuterBorderEnd() const; |
| void recalcOuterBorder(); |
| |
| LayoutUnit outerBorderBefore() const { return m_outerBorderBefore; } |
| LayoutUnit outerBorderAfter() const { return m_outerBorderAfter; } |
| LayoutUnit outerBorderStart() const { return m_outerBorderStart; } |
| LayoutUnit outerBorderEnd() const { return m_outerBorderEnd; } |
| |
| LayoutUnit outerBorderLeft(const RenderStyle* styleForCellFlow) const; |
| LayoutUnit outerBorderRight(const RenderStyle* styleForCellFlow) const; |
| LayoutUnit outerBorderTop(const RenderStyle* styleForCellFlow) const; |
| LayoutUnit outerBorderBottom(const RenderStyle* styleForCellFlow) const; |
| |
| unsigned numRows() const; |
| unsigned numColumns() const; |
| void recalcCells(); |
| void recalcCellsIfNeeded(); |
| void removeRedundantColumns(); |
| |
| bool needsCellRecalc() const { return m_needsCellRecalc; } |
| void setNeedsCellRecalc(); |
| |
| LayoutUnit rowBaseline(unsigned row); |
| void rowLogicalHeightChanged(unsigned rowIndex); |
| |
| void clearCachedCollapsedBorders(); |
| void removeCachedCollapsedBorders(const RenderTableCell&); |
| void setCachedCollapsedBorder(const RenderTableCell&, CollapsedBorderSide, CollapsedBorderValue); |
| CollapsedBorderValue cachedCollapsedBorder(const RenderTableCell&, CollapsedBorderSide); |
| |
| // distributeExtraLogicalHeightToRows methods return the *consumed* extra logical height. |
| // FIXME: We may want to introduce a structure holding the in-flux layout information. |
| LayoutUnit distributeExtraLogicalHeightToRows(LayoutUnit extraLogicalHeight); |
| |
| static RenderPtr<RenderTableSection> createAnonymousWithParentRenderer(const RenderTable&); |
| RenderPtr<RenderBox> createAnonymousBoxWithSameTypeAs(const RenderBox&) const override; |
| |
| void paint(PaintInfo&, const LayoutPoint&) override; |
| |
| void willInsertTableRow(RenderTableRow& child, RenderObject* beforeChild); |
| |
| private: |
| void styleDidChange(StyleDifference, const RenderStyle* oldStyle) override; |
| |
| static RenderPtr<RenderTableSection> createTableSectionWithStyle(Document&, const RenderStyle&); |
| |
| enum ShouldIncludeAllIntersectingCells { |
| IncludeAllIntersectingCells, |
| DoNotIncludeAllIntersectingCells |
| }; |
| |
| ASCIILiteral renderName() const override { return (isAnonymous() || isPseudoElement()) ? "RenderTableSection (anonymous)"_s : "RenderTableSection"_s; } |
| |
| bool canHaveChildren() const override { return true; } |
| |
| bool isTableSection() const override { return true; } |
| |
| void willBeRemovedFromTree(IsInternalMove) override; |
| |
| void layout() override; |
| |
| void paintCell(RenderTableCell*, PaintInfo&, const LayoutPoint&); |
| void paintObject(PaintInfo&, const LayoutPoint&) override; |
| void paintRowGroupBorder(const PaintInfo&, bool antialias, LayoutRect, BoxSide, CSSPropertyID borderColor, BorderStyle, BorderStyle tableBorderStyle); |
| void paintRowGroupBorderIfRequired(const PaintInfo&, const LayoutPoint& paintOffset, unsigned row, unsigned col, BoxSide, RenderTableCell* = 0); |
| LayoutUnit offsetLeftForRowGroupBorder(RenderTableCell*, const LayoutRect& rowGroupRect, unsigned row); |
| |
| LayoutUnit offsetTopForRowGroupBorder(RenderTableCell*, BoxSide borderSide, unsigned row); |
| LayoutUnit verticalRowGroupBorderHeight(RenderTableCell*, const LayoutRect& rowGroupRect, unsigned row); |
| LayoutUnit horizontalRowGroupBorderWidth(RenderTableCell*, const LayoutRect& rowGroupRect, unsigned row, unsigned column); |
| |
| void imageChanged(WrappedImagePtr, const IntRect* = 0) override; |
| |
| bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) override; |
| |
| void ensureRows(unsigned); |
| |
| void relayoutCellIfFlexed(RenderTableCell&, int rowIndex, int rowHeight); |
| |
| void distributeExtraLogicalHeightToPercentRows(LayoutUnit& extraLogicalHeight, int totalPercent); |
| void distributeExtraLogicalHeightToAutoRows(LayoutUnit& extraLogicalHeight, unsigned autoRowsCount); |
| void distributeRemainingExtraLogicalHeight(LayoutUnit& extraLogicalHeight); |
| |
| bool hasOverflowingCell() const { return m_overflowingCells.size() || m_forceSlowPaintPathWithOverflowingCell; } |
| void computeOverflowFromCells(unsigned totalRows, unsigned nEffCols); |
| |
| CellSpan fullTableRowSpan() const; |
| CellSpan fullTableColumnSpan() const { return CellSpan(0, table()->columns().size()); } |
| |
| // Flip the rect so it aligns with the coordinates used by the rowPos and columnPos vectors. |
| LayoutRect logicalRectForWritingModeAndDirection(const LayoutRect&) const; |
| |
| CellSpan dirtiedRows(const LayoutRect& repaintRect) const; |
| CellSpan dirtiedColumns(const LayoutRect& repaintRect) const; |
| |
| // These two functions take a rectangle as input that has been flipped by logicalRectForWritingModeAndDirection. |
| // The returned span of rows or columns is end-exclusive, and empty if start==end. |
| // The IncludeAllIntersectingCells argument is used to determine which cells to include when |
| // an edge of the flippedRect lies exactly on a cell boundary. Using IncludeAllIntersectingCells |
| // will return both cells, and using DoNotIncludeAllIntersectingCells will return only the cell |
| // that hittesting should return. |
| CellSpan spannedRows(const LayoutRect& flippedRect, ShouldIncludeAllIntersectingCells) const; |
| CellSpan spannedColumns(const LayoutRect& flippedRect, ShouldIncludeAllIntersectingCells) const; |
| |
| void setLogicalPositionForCell(RenderTableCell*, unsigned effectiveColumn) const; |
| |
| void firstChild() const = delete; |
| void lastChild() const = delete; |
| |
| Vector<RowStruct> m_grid; |
| Vector<LayoutUnit> m_rowPos; |
| |
| // the current insertion position |
| unsigned m_cCol { 0 }; |
| unsigned m_cRow { 0 }; |
| |
| LayoutUnit m_outerBorderStart; |
| LayoutUnit m_outerBorderEnd; |
| LayoutUnit m_outerBorderBefore; |
| LayoutUnit m_outerBorderAfter; |
| |
| // This HashSet holds the overflowing cells for faster painting. |
| // If we have more than gMaxAllowedOverflowingCellRatio * total cells, it will be empty |
| // and m_forceSlowPaintPathWithOverflowingCell will be set to save memory. |
| HashSet<RenderTableCell*> m_overflowingCells; |
| |
| // This map holds the collapsed border values for cells with collapsed borders. |
| // It is held at RenderTableSection level to spare memory consumption by table cells. |
| HashMap<std::pair<const RenderTableCell*, int>, CollapsedBorderValue > m_cellsCollapsedBorders; |
| |
| bool m_forceSlowPaintPathWithOverflowingCell { false }; |
| bool m_hasMultipleCellLevels { false }; |
| bool m_needsCellRecalc { false }; |
| }; |
| |
| inline const BorderValue& RenderTableSection::borderAdjoiningTableStart() const |
| { |
| if (isDirectionSame(this, table())) |
| return style().borderStart(); |
| return style().borderEnd(); |
| } |
| |
| inline const BorderValue& RenderTableSection::borderAdjoiningTableEnd() const |
| { |
| if (isDirectionSame(this, table())) |
| return style().borderEnd(); |
| return style().borderStart(); |
| } |
| |
| inline RenderTableSection::CellStruct& RenderTableSection::cellAt(unsigned row, unsigned col) |
| { |
| recalcCellsIfNeeded(); |
| return m_grid[row].row[col]; |
| } |
| |
| inline const RenderTableSection::CellStruct& RenderTableSection::cellAt(unsigned row, unsigned col) const |
| { |
| ASSERT(!m_needsCellRecalc); |
| return m_grid[row].row[col]; |
| } |
| |
| inline RenderTableCell* RenderTableSection::primaryCellAt(unsigned row, unsigned col) |
| { |
| recalcCellsIfNeeded(); |
| CellStruct& c = m_grid[row].row[col]; |
| return c.primaryCell(); |
| } |
| |
| inline RenderTableRow* RenderTableSection::rowRendererAt(unsigned row) const |
| { |
| ASSERT(!m_needsCellRecalc); |
| return m_grid[row].rowRenderer; |
| } |
| |
| inline LayoutUnit RenderTableSection::outerBorderLeft(const RenderStyle* styleForCellFlow) const |
| { |
| if (styleForCellFlow->isHorizontalWritingMode()) |
| return styleForCellFlow->isLeftToRightDirection() ? outerBorderStart() : outerBorderEnd(); |
| return styleForCellFlow->isFlippedBlocksWritingMode() ? outerBorderAfter() : outerBorderBefore(); |
| } |
| |
| inline LayoutUnit RenderTableSection::outerBorderRight(const RenderStyle* styleForCellFlow) const |
| { |
| if (styleForCellFlow->isHorizontalWritingMode()) |
| return styleForCellFlow->isLeftToRightDirection() ? outerBorderEnd() : outerBorderStart(); |
| return styleForCellFlow->isFlippedBlocksWritingMode() ? outerBorderBefore() : outerBorderAfter(); |
| } |
| |
| inline LayoutUnit RenderTableSection::outerBorderTop(const RenderStyle* styleForCellFlow) const |
| { |
| if (styleForCellFlow->isHorizontalWritingMode()) |
| return styleForCellFlow->isFlippedBlocksWritingMode() ? outerBorderAfter() : outerBorderBefore(); |
| return styleForCellFlow->isLeftToRightDirection() ? outerBorderStart() : outerBorderEnd(); |
| } |
| |
| inline LayoutUnit RenderTableSection::outerBorderBottom(const RenderStyle* styleForCellFlow) const |
| { |
| if (styleForCellFlow->isHorizontalWritingMode()) |
| return styleForCellFlow->isFlippedBlocksWritingMode() ? outerBorderBefore() : outerBorderAfter(); |
| return styleForCellFlow->isLeftToRightDirection() ? outerBorderEnd() : outerBorderStart(); |
| } |
| |
| inline unsigned RenderTableSection::numRows() const |
| { |
| ASSERT(!m_needsCellRecalc); |
| return m_grid.size(); |
| } |
| |
| inline void RenderTableSection::recalcCellsIfNeeded() |
| { |
| if (m_needsCellRecalc) |
| recalcCells(); |
| } |
| |
| inline LayoutUnit RenderTableSection::rowBaseline(unsigned row) |
| { |
| recalcCellsIfNeeded(); |
| return m_grid[row].baseline; |
| } |
| |
| inline CellSpan RenderTableSection::fullTableRowSpan() const |
| { |
| ASSERT(!m_needsCellRecalc); |
| return CellSpan(0, m_grid.size()); |
| } |
| |
| inline RenderPtr<RenderBox> RenderTableSection::createAnonymousBoxWithSameTypeAs(const RenderBox& renderer) const |
| { |
| return RenderTableSection::createTableSectionWithStyle(renderer.document(), renderer.style()); |
| } |
| |
| } // namespace WebCore |
| |
| SPECIALIZE_TYPE_TRAITS_RENDER_OBJECT(RenderTableSection, isTableSection()) |