Use #pragma once in WebCore
[WebKit-https.git] / Source / WebCore / rendering / RenderTableSection.h
index f9fa467..3332c81 100644 (file)
@@ -22,8 +22,7 @@
  * Boston, MA 02110-1301, USA.
  */
 
-#ifndef RenderTableSection_h
-#define RenderTableSection_h
+#pragma once
 
 #include "RenderTable.h"
 #include <wtf/Vector.h>
@@ -33,65 +32,79 @@ namespace WebCore {
 class RenderTableCell;
 class RenderTableRow;
 
-class RenderTableSection : public RenderBox {
+enum CollapsedBorderSide {
+    CBSBefore,
+    CBSAfter,
+    CBSStart,
+    CBSEnd
+};
+
+// Helper class for paintObject.
+struct CellSpan {
 public:
-    RenderTableSection(Node*);
+    CellSpan(unsigned start, unsigned end)
+        : start(start)
+        , end(end)
+    {
+    }
+
+    unsigned start;
+    unsigned end;
+};
+
+class RenderTableSection final : public RenderBox {
+public:
+    RenderTableSection(Element&, RenderStyle&&);
+    RenderTableSection(Document&, RenderStyle&&);
     virtual ~RenderTableSection();
 
-    const RenderObjectChildList* children() const { return &m_children; }
-    RenderObjectChildList* children() { return &m_children; }
+    RenderTableRow* firstRow() const;
+    RenderTableRow* lastRow() const;
 
-    virtual void addChild(RenderObject* child, RenderObject* beforeChild = 0);
+    void addChild(RenderObject* child, RenderObject* beforeChild = 0) override;
 
-    virtual LayoutUnit firstLineBoxBaseline() const;
+    Optional<int> firstLineBaseline() const override;
 
     void addCell(RenderTableCell*, RenderTableRow* row);
 
-    void setCellLogicalWidths();
     LayoutUnit calcRowLogicalHeight();
-    LayoutUnit layoutRows(LayoutUnit logicalHeight);
+    void layoutRows();
+    void computeOverflowFromCells();
 
-    RenderTable* table() const { return toRenderTable(parent()); }
+    RenderTable* table() const { return downcast<RenderTable>(parent()); }
 
     struct CellStruct {
         Vector<RenderTableCell*, 1> cells; 
-        bool inColSpan; // true for columns after the first in a colspan
-
-        CellStruct():
-          inColSpan(false) {}
-        
-        RenderTableCell* primaryCell()
-        {
-            return hasCells() ? cells[cells.size() - 1] : 0;
-        }
-
-        const RenderTableCell* primaryCell() const
-        {
-            return hasCells() ? cells[cells.size() - 1] : 0;
-        }
+        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;
+        RenderTableRow* rowRenderer { nullptr };
         LayoutUnit baseline;
         Length logicalHeight;
     };
 
-    CellStruct& cellAt(int row,  int col) { return m_grid[row].row[col]; }
-    const CellStruct& cellAt(int row, int col) const { return m_grid[row].row[col]; }
-    RenderTableCell* primaryCellAt(int row, int col)
-    {
-        CellStruct& c = m_grid[row].row[col];
-        return c.primaryCell();
-    }
+    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;
 
-    void appendColumn(int pos);
-    void splitColumn(unsigned pos, int first);
+    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;
@@ -104,90 +117,226 @@ public:
     LayoutUnit outerBorderStart() const { return m_outerBorderStart; }
     LayoutUnit outerBorderEnd() const { return m_outerBorderEnd; }
 
-    unsigned numRows() const { return m_grid.size(); }
+    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()
-    {
-        if (m_needsCellRecalc)
-            recalcCells();
-    }
+    void recalcCellsIfNeeded();
 
     bool needsCellRecalc() const { return m_needsCellRecalc; }
     void setNeedsCellRecalc();
 
-    LayoutUnit getBaseline(int row) { return m_grid[row].baseline; }
+    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 std::unique_ptr<RenderTableSection> createAnonymousWithParentRenderer(const RenderTable&);
+    std::unique_ptr<RenderBox> createAnonymousBoxWithSameTypeAs(const RenderBox&) const override;
+    
+    void paint(PaintInfo&, const LayoutPoint&) override;
 
 protected:
-    virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle);
+    void styleDidChange(StyleDifference, const RenderStyle* oldStyle) override;
 
 private:
-    virtual RenderObjectChildList* virtualChildren() { return children(); }
-    virtual const RenderObjectChildList* virtualChildren() const { return children(); }
+    static std::unique_ptr<RenderTableSection> createTableSectionWithStyle(Document&, const RenderStyle&);
+
+    enum ShouldIncludeAllIntersectingCells {
+        IncludeAllIntersectingCells,
+        DoNotIncludeAllIntersectingCells
+    };
 
-    virtual const char* renderName() const { return isAnonymous() ? "RenderTableSection (anonymous)" : "RenderTableSection"; }
+    const char* renderName() const override { return (isAnonymous() || isPseudoElement()) ? "RenderTableSection (anonymous)" : "RenderTableSection"; }
 
-    virtual bool isTableSection() const { return true; }
+    bool canHaveChildren() const override { return true; }
 
-    virtual void willBeDestroyed();
+    bool isTableSection() const override { return true; }
 
-    virtual void layout();
+    void willBeRemovedFromTree() override;
 
-    virtual void removeChild(RenderObject* oldChild);
+    void layout() override;
 
-    virtual void paint(PaintInfo&, const LayoutPoint&);
-    virtual void paintCell(RenderTableCell*, PaintInfo&, const LayoutPoint&);
-    virtual void paintObject(PaintInfo&, const LayoutPoint&);
+    void paintCell(RenderTableCell*, PaintInfo&, const LayoutPoint&);
+    void paintObject(PaintInfo&, const LayoutPoint&) override;
+    void paintRowGroupBorder(const PaintInfo&, bool antialias, LayoutRect, BoxSide, CSSPropertyID borderColor, EBorderStyle, EBorderStyle tableBorderStyle);
+    void paintRowGroupBorderIfRequired(const PaintInfo&, const LayoutPoint& paintOffset, unsigned row, unsigned col, BoxSide, RenderTableCell* = 0);
+    LayoutUnit offsetLeftForRowGroupBorder(RenderTableCell*, const LayoutRect& rowGroupRect, unsigned row);
 
-    virtual void imageChanged(WrappedImagePtr, const IntRect* = 0);
+    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);
 
-    virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const LayoutPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction);
+    void imageChanged(WrappedImagePtr, const IntRect* = 0) override;
 
-    bool ensureRows(unsigned);
-    void fillRowsWithDefaultStartingAtPosition(unsigned);
+    bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) override;
+
+    void ensureRows(unsigned);
+
+    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;
 
-    RenderObjectChildList m_children;
+    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;
-    unsigned m_cRow;
+    unsigned m_cCol { 0 };
+    unsigned m_cRow  { 0 };
 
     LayoutUnit m_outerBorderStart;
     LayoutUnit m_outerBorderEnd;
     LayoutUnit m_outerBorderBefore;
     LayoutUnit m_outerBorderAfter;
 
-    bool m_needsCellRecalc;
+    bool m_needsCellRecalc  { false };
 
     // 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;
-    bool m_forceSlowPaintPathWithOverflowingCell;
+    bool m_forceSlowPaintPathWithOverflowingCell { false };
+
+    bool m_hasMultipleCellLevels { false };
 
-    bool m_hasMultipleCellLevels;
+    // 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;
 };
 
-inline RenderTableSection* toRenderTableSection(RenderObject* object)
+inline const BorderValue& RenderTableSection::borderAdjoiningTableStart() const
 {
-    ASSERT(!object || object->isTableSection());
-    return static_cast<RenderTableSection*>(object);
+    if (isDirectionSame(this, table()))
+        return style().borderStart();
+    return style().borderEnd();
 }
 
-inline const RenderTableSection* toRenderTableSection(const RenderObject* object)
+inline const BorderValue& RenderTableSection::borderAdjoiningTableEnd() const
 {
-    ASSERT(!object || object->isTableSection());
-    return static_cast<const RenderTableSection*>(object);
+    if (isDirectionSame(this, table()))
+        return style().borderEnd();
+    return style().borderStart();
 }
 
-// This will catch anyone doing an unnecessary cast.
-void toRenderTableSection(const RenderTableSection*);
+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 std::unique_ptr<RenderBox> RenderTableSection::createAnonymousBoxWithSameTypeAs(const RenderBox& renderer) const
+{
+    return RenderTableSection::createTableSectionWithStyle(renderer.document(), renderer.style());
+}
 
 } // namespace WebCore
 
-#endif // RenderTableSection_h
+SPECIALIZE_TYPE_TRAITS_RENDER_OBJECT(RenderTableSection, isTableSection())