Use is<>() / downcast<>() for Table render objects
[WebKit-https.git] / Source / WebCore / rendering / RenderTableSection.h
index 9f1f406..ee85929 100644 (file)
 
 namespace WebCore {
 
+class RenderTableRow;
+
+enum CollapsedBorderSide {
+    CBSBefore,
+    CBSAfter,
+    CBSStart,
+    CBSEnd
+};
+
+// Helper class for paintObject.
+class CellSpan {
+public:
+    CellSpan(unsigned start, unsigned end)
+        : m_start(start)
+        , m_end(end)
+    {
+    }
+
+    unsigned start() const { return m_start; }
+    unsigned end() const { return m_end; }
+
+    unsigned& start() { return m_start; }
+    unsigned& end() { return m_end; }
+
+private:
+    unsigned m_start;
+    unsigned m_end;
+};
+
 class RenderTableCell;
 class RenderTableRow;
 
-class RenderTableSection : public RenderBox {
+class RenderTableSection final : public RenderBox {
 public:
-    RenderTableSection(Node*);
+    RenderTableSection(Element&, PassRef<RenderStyle>);
+    RenderTableSection(Document&, PassRef<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);
+    virtual void addChild(RenderObject* child, RenderObject* beforeChild = 0) override;
 
-    virtual int firstLineBoxBaseline() const;
+    virtual int firstLineBaseline() const override;
 
     void addCell(RenderTableCell*, RenderTableRow* row);
 
-    void setCellLogicalWidths();
     int calcRowLogicalHeight();
-    int layoutRows(int 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) {}
-        
+        CellStruct()
+            : inColSpan(false)
+        {
+        }
+
         RenderTableCell* primaryCell()
         {
             return hasCells() ? cells[cells.size() - 1] : 0;
@@ -76,22 +108,67 @@ public:
     typedef Vector<CellStruct> Row;
 
     struct RowStruct {
-        Row* row;
+        RowStruct()
+            : rowRenderer(0)
+            , baseline()
+        {
+        }
+
+        Row row;
         RenderTableRow* rowRenderer;
-        int baseline;
+        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)
+    const BorderValue& borderAdjoiningTableStart() const
     {
-        CellStruct& c = (*m_grid[row].row)[col];
+        if (hasSameDirectionAs(table()))
+            return style().borderStart();
+
+        return style().borderEnd();
+    }
+
+    const BorderValue& borderAdjoiningTableEnd() const
+    {
+        if (hasSameDirectionAs(table()))
+            return style().borderEnd();
+
+        return style().borderStart();
+    }
+
+    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)
+    {
+        recalcCellsIfNeeded();
+        return m_grid[row].row[col];
+    }
+
+    const CellStruct& cellAt(unsigned row, unsigned col) const
+    {
+        ASSERT(!m_needsCellRecalc);
+        return m_grid[row].row[col];
+    }
+
+    RenderTableCell* primaryCellAt(unsigned row, unsigned col)
+    {
+        recalcCellsIfNeeded();
+        CellStruct& c = m_grid[row].row[col];
         return c.primaryCell();
     }
 
-    void appendColumn(int pos);
-    void splitColumn(int pos, int first);
+    RenderTableRow* rowRendererAt(unsigned row) const
+    {
+        ASSERT(!m_needsCellRecalc);
+        return m_grid[row].rowRenderer;
+    }
+
+    void appendColumn(unsigned pos);
+    void splitColumn(unsigned pos, unsigned first);
 
     int calcOuterBorderBefore() const;
     int calcOuterBorderAfter() const;
@@ -104,8 +181,41 @@ public:
     int outerBorderStart() const { return m_outerBorderStart; }
     int outerBorderEnd() const { return m_outerBorderEnd; }
 
-    int numRows() const { return m_gridRows; }
-    int numColumns() const;
+    int outerBorderLeft(const RenderStyle* styleForCellFlow) const
+    {
+    if (styleForCellFlow->isHorizontalWritingMode())
+        return styleForCellFlow->isLeftToRightDirection() ? outerBorderStart() : outerBorderEnd();
+    return styleForCellFlow->isFlippedBlocksWritingMode() ? outerBorderAfter() : outerBorderBefore();
+    }
+
+    int outerBorderRight(const RenderStyle* styleForCellFlow) const
+    {
+    if (styleForCellFlow->isHorizontalWritingMode())
+        return styleForCellFlow->isLeftToRightDirection() ? outerBorderEnd() : outerBorderStart();
+    return styleForCellFlow->isFlippedBlocksWritingMode() ? outerBorderBefore() : outerBorderAfter();
+    }
+
+    int outerBorderTop(const RenderStyle* styleForCellFlow) const
+    {
+    if (styleForCellFlow->isHorizontalWritingMode())
+        return styleForCellFlow->isFlippedBlocksWritingMode() ? outerBorderAfter() : outerBorderBefore();
+    return styleForCellFlow->isLeftToRightDirection() ? outerBorderStart() : outerBorderEnd();
+    }
+
+    int outerBorderBottom(const RenderStyle* styleForCellFlow) const
+    {
+    if (styleForCellFlow->isHorizontalWritingMode())
+        return styleForCellFlow->isFlippedBlocksWritingMode() ? outerBorderBefore() : outerBorderAfter();
+    return styleForCellFlow->isLeftToRightDirection() ? outerBorderEnd() : outerBorderStart();
+    }
+
+    unsigned numRows() const
+    {
+        ASSERT(!m_needsCellRecalc);
+        return m_grid.size();
+    }
+
+    unsigned numColumns() const;
     void recalcCells();
     void recalcCellsIfNeeded()
     {
@@ -116,43 +226,106 @@ public:
     bool needsCellRecalc() const { return m_needsCellRecalc; }
     void setNeedsCellRecalc();
 
-    int getBaseline(int row) { return m_grid[row].baseline; }
+    LayoutUnit rowBaseline(unsigned row)
+    {
+        recalcCellsIfNeeded();
+        return m_grid[row].baseline;
+    }
+
+    void rowLogicalHeightChanged(unsigned rowIndex);
+
+    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.
+    int distributeExtraLogicalHeightToRows(int extraLogicalHeight);
+
+    static RenderTableSection* createAnonymousWithParentRenderer(const RenderObject*);
+    virtual RenderBox* createAnonymousBoxWithSameTypeAs(const RenderObject* parent) const override
+    {
+        return createAnonymousWithParentRenderer(parent);
+    }
+    
+    virtual void paint(PaintInfo&, const LayoutPoint&) override;
+
+protected:
+    virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle) override;
 
 private:
-    virtual RenderObjectChildList* virtualChildren() { return children(); }
-    virtual const RenderObjectChildList* virtualChildren() const { return children(); }
+    enum ShouldIncludeAllIntersectingCells {
+        IncludeAllIntersectingCells,
+        DoNotIncludeAllIntersectingCells
+    };
+
+    virtual const char* renderName() const override { return (isAnonymous() || isPseudoElement()) ? "RenderTableSection (anonymous)" : "RenderTableSection"; }
+
+    virtual bool canHaveChildren() const override { return true; }
+
+    virtual bool isTableSection() const override { return true; }
+
+    virtual void willBeRemovedFromTree() override;
+
+    virtual void layout() override;
+
+    void paintCell(RenderTableCell*, PaintInfo&, const LayoutPoint&);
+    virtual 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);
+    int offsetLeftForRowGroupBorder(RenderTableCell*, const LayoutRect& rowGroupRect, unsigned row);
+
+    int offsetTopForRowGroupBorder(RenderTableCell*, BoxSide borderSide, unsigned row);
+    int verticalRowGroupBorderHeight(RenderTableCell*, const LayoutRect& rowGroupRect, unsigned row);
+    int horizontalRowGroupBorderWidth(RenderTableCell*, const LayoutRect& rowGroupRect, unsigned row, unsigned column);
+
+    virtual void imageChanged(WrappedImagePtr, const IntRect* = 0) override;
 
-    virtual const char* renderName() const { return isAnonymous() ? "RenderTableSection (anonymous)" : "RenderTableSection"; }
+    virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) override;
 
-    virtual bool isTableSection() const { return true; }
+    void ensureRows(unsigned);
 
-    virtual void willBeDestroyed();
+    void distributeExtraLogicalHeightToPercentRows(int& extraLogicalHeight, int totalPercent);
+    void distributeExtraLogicalHeightToAutoRows(int& extraLogicalHeight, unsigned autoRowsCount);
+    void distributeRemainingExtraLogicalHeight(int& extraLogicalHeight);
 
-    virtual void layout();
+    bool hasOverflowingCell() const { return m_overflowingCells.size() || m_forceSlowPaintPathWithOverflowingCell; }
+    void computeOverflowFromCells(unsigned totalRows, unsigned nEffCols);
 
-    virtual void removeChild(RenderObject* oldChild);
+    CellSpan fullTableRowSpan() const
+    {
+        ASSERT(!m_needsCellRecalc);
+        return CellSpan(0, m_grid.size());
+    }
+
+    CellSpan fullTableColumnSpan() const { return CellSpan(0, table()->columns().size()); }
 
-    virtual void paint(PaintInfo&, const LayoutPoint&);
-    virtual void paintCell(RenderTableCell*, PaintInfo&, const LayoutPoint&);
-    virtual void paintObject(PaintInfo&, const LayoutPoint&);
+    // Flip the rect so it aligns with the coordinates used by the rowPos and columnPos vectors.
+    LayoutRect logicalRectForWritingModeAndDirection(const LayoutRect&) const;
 
-    virtual void imageChanged(WrappedImagePtr, const IntRect* = 0);
+    CellSpan dirtiedRows(const LayoutRect& repaintRect) const;
+    CellSpan dirtiedColumns(const LayoutRect& repaintRect) const;
 
-    virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const LayoutPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction);
+    // 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;
 
-    bool ensureRows(int);
-    void clearGrid();
+    void setLogicalPositionForCell(RenderTableCell*, unsigned effectiveColumn) const;
 
-    RenderObjectChildList m_children;
+    void firstChild() const = delete;
+    void lastChild() const = delete;
 
     Vector<RowStruct> m_grid;
     Vector<int> m_rowPos;
 
-    int m_gridRows;
-
     // the current insertion position
-    int m_cCol;
-    int m_cRow;
+    unsigned m_cCol;
+    unsigned m_cRow;
 
     int m_outerBorderStart;
     int m_outerBorderEnd;
@@ -160,26 +333,22 @@ private:
     int m_outerBorderAfter;
 
     bool m_needsCellRecalc;
-    bool m_hasOverflowingCell;
-
-    bool m_hasMultipleCellLevels;
-};
 
-inline RenderTableSection* toRenderTableSection(RenderObject* object)
-{
-    ASSERT(!object || object->isTableSection());
-    return static_cast<RenderTableSection*>(object);
-}
+    // 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;
 
-inline const RenderTableSection* toRenderTableSection(const RenderObject* object)
-{
-    ASSERT(!object || object->isTableSection());
-    return static_cast<const RenderTableSection*>(object);
-}
+    bool m_hasMultipleCellLevels;
 
-// This will catch anyone doing an unnecessary cast.
-void toRenderTableSection(const RenderTableSection*);
+    // 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;
+};
 
 } // namespace WebCore
 
+SPECIALIZE_TYPE_TRAITS_RENDER_OBJECT(RenderTableSection, isTableSection())
+
 #endif // RenderTableSection_h