Home | History | Annotate | Download | only in rendering
      1 /*
      2  * Copyright (C) 1997 Martin Jones (mjones (at) kde.org)
      3  *           (C) 1997 Torben Weis (weis (at) kde.org)
      4  *           (C) 1998 Waldo Bastian (bastian (at) kde.org)
      5  *           (C) 1999 Lars Knoll (knoll (at) kde.org)
      6  *           (C) 1999 Antti Koivisto (koivisto (at) kde.org)
      7  * Copyright (C) 2003, 2004, 2005, 2006, 2009, 2010 Apple Inc. All rights reserved.
      8  *
      9  * This library is free software; you can redistribute it and/or
     10  * modify it under the terms of the GNU Library General Public
     11  * License as published by the Free Software Foundation; either
     12  * version 2 of the License, or (at your option) any later version.
     13  *
     14  * This library is distributed in the hope that it will be useful,
     15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     17  * Library General Public License for more details.
     18  *
     19  * You should have received a copy of the GNU Library General Public License
     20  * along with this library; see the file COPYING.LIB.  If not, write to
     21  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     22  * Boston, MA 02110-1301, USA.
     23  */
     24 
     25 #ifndef RenderTable_h
     26 #define RenderTable_h
     27 
     28 #include "core/CSSPropertyNames.h"
     29 #include "core/rendering/RenderBlock.h"
     30 #include "core/rendering/style/CollapsedBorderValue.h"
     31 #include "wtf/Vector.h"
     32 
     33 namespace WebCore {
     34 
     35 class RenderTableCol;
     36 class RenderTableCaption;
     37 class RenderTableCell;
     38 class RenderTableSection;
     39 class TableLayout;
     40 
     41 enum SkipEmptySectionsValue { DoNotSkipEmptySections, SkipEmptySections };
     42 
     43 class RenderTable FINAL : public RenderBlock {
     44 public:
     45     explicit RenderTable(Element*);
     46     virtual ~RenderTable();
     47 
     48     // Per CSS 3 writing-mode: "The first and second values of the 'border-spacing' property represent spacing between columns
     49     // and rows respectively, not necessarily the horizontal and vertical spacing respectively".
     50     int hBorderSpacing() const { return m_hSpacing; }
     51     int vBorderSpacing() const { return m_vSpacing; }
     52 
     53     bool collapseBorders() const { return style()->borderCollapse(); }
     54 
     55     virtual int borderStart() const OVERRIDE { return m_borderStart; }
     56     virtual int borderEnd() const OVERRIDE { return m_borderEnd; }
     57     virtual int borderBefore() const OVERRIDE;
     58     virtual int borderAfter() const OVERRIDE;
     59 
     60     virtual int borderLeft() const OVERRIDE
     61     {
     62         if (style()->isHorizontalWritingMode())
     63             return style()->isLeftToRightDirection() ? borderStart() : borderEnd();
     64         return style()->isFlippedBlocksWritingMode() ? borderAfter() : borderBefore();
     65     }
     66 
     67     virtual int borderRight() const OVERRIDE
     68     {
     69         if (style()->isHorizontalWritingMode())
     70             return style()->isLeftToRightDirection() ? borderEnd() : borderStart();
     71         return style()->isFlippedBlocksWritingMode() ? borderBefore() : borderAfter();
     72     }
     73 
     74     virtual int borderTop() const OVERRIDE
     75     {
     76         if (style()->isHorizontalWritingMode())
     77             return style()->isFlippedBlocksWritingMode() ? borderAfter() : borderBefore();
     78         return style()->isLeftToRightDirection() ? borderStart() : borderEnd();
     79     }
     80 
     81     virtual int borderBottom() const OVERRIDE
     82     {
     83         if (style()->isHorizontalWritingMode())
     84             return style()->isFlippedBlocksWritingMode() ? borderBefore() : borderAfter();
     85         return style()->isLeftToRightDirection() ? borderEnd() : borderStart();
     86     }
     87 
     88     Color bgColor() const { return resolveColor(CSSPropertyBackgroundColor); }
     89 
     90     int outerBorderBefore() const;
     91     int outerBorderAfter() const;
     92     int outerBorderStart() const;
     93     int outerBorderEnd() const;
     94 
     95     int outerBorderLeft() const
     96     {
     97         if (style()->isHorizontalWritingMode())
     98             return style()->isLeftToRightDirection() ? outerBorderStart() : outerBorderEnd();
     99         return style()->isFlippedBlocksWritingMode() ? outerBorderAfter() : outerBorderBefore();
    100     }
    101 
    102     int outerBorderRight() const
    103     {
    104         if (style()->isHorizontalWritingMode())
    105             return style()->isLeftToRightDirection() ? outerBorderEnd() : outerBorderStart();
    106         return style()->isFlippedBlocksWritingMode() ? outerBorderBefore() : outerBorderAfter();
    107     }
    108 
    109     int outerBorderTop() const
    110     {
    111         if (style()->isHorizontalWritingMode())
    112             return style()->isFlippedBlocksWritingMode() ? outerBorderAfter() : outerBorderBefore();
    113         return style()->isLeftToRightDirection() ? outerBorderStart() : outerBorderEnd();
    114     }
    115 
    116     int outerBorderBottom() const
    117     {
    118         if (style()->isHorizontalWritingMode())
    119             return style()->isFlippedBlocksWritingMode() ? outerBorderBefore() : outerBorderAfter();
    120         return style()->isLeftToRightDirection() ? outerBorderEnd() : outerBorderStart();
    121     }
    122 
    123     int calcBorderStart() const;
    124     int calcBorderEnd() const;
    125     void recalcBordersInRowDirection();
    126 
    127     virtual void addChild(RenderObject* child, RenderObject* beforeChild = 0) OVERRIDE;
    128 
    129     struct ColumnStruct {
    130         explicit ColumnStruct(unsigned initialSpan = 1)
    131             : span(initialSpan)
    132         {
    133         }
    134 
    135         unsigned span;
    136     };
    137 
    138     void forceSectionsRecalc()
    139     {
    140         setNeedsSectionRecalc();
    141         recalcSections();
    142     }
    143 
    144     const Vector<ColumnStruct>& columns() const { return m_columns; }
    145     const Vector<int>& columnPositions() const { return m_columnPos; }
    146     void setColumnPosition(unsigned index, int position)
    147     {
    148         // Note that if our horizontal border-spacing changed, our position will change but not
    149         // our column's width. In practice, horizontal border-spacing won't change often.
    150         m_columnLogicalWidthChanged |= m_columnPos[index] != position;
    151         m_columnPos[index] = position;
    152     }
    153 
    154     RenderTableSection* header() const { return m_head; }
    155     RenderTableSection* footer() const { return m_foot; }
    156     RenderTableSection* firstBody() const { return m_firstBody; }
    157 
    158     // This function returns 0 if the table has no section.
    159     RenderTableSection* topSection() const;
    160     RenderTableSection* bottomSection() const;
    161 
    162     // This function returns 0 if the table has no non-empty sections.
    163     RenderTableSection* topNonEmptySection() const;
    164 
    165     unsigned lastColumnIndex() const { return numEffCols() - 1; }
    166 
    167     void splitColumn(unsigned position, unsigned firstSpan);
    168     void appendColumn(unsigned span);
    169     unsigned numEffCols() const { return m_columns.size(); }
    170     unsigned spanOfEffCol(unsigned effCol) const { return m_columns[effCol].span; }
    171 
    172     unsigned colToEffCol(unsigned column) const
    173     {
    174         if (!m_hasCellColspanThatDeterminesTableWidth)
    175             return column;
    176 
    177         unsigned effColumn = 0;
    178         unsigned numColumns = numEffCols();
    179         for (unsigned c = 0; effColumn < numColumns && c + m_columns[effColumn].span - 1 < column; ++effColumn)
    180             c += m_columns[effColumn].span;
    181         return effColumn;
    182     }
    183 
    184     unsigned effColToCol(unsigned effCol) const
    185     {
    186         if (!m_hasCellColspanThatDeterminesTableWidth)
    187             return effCol;
    188 
    189         unsigned c = 0;
    190         for (unsigned i = 0; i < effCol; i++)
    191             c += m_columns[i].span;
    192         return c;
    193     }
    194 
    195     LayoutUnit borderSpacingInRowDirection() const
    196     {
    197         if (unsigned effectiveColumnCount = numEffCols())
    198             return static_cast<LayoutUnit>(effectiveColumnCount + 1) * hBorderSpacing();
    199 
    200         return 0;
    201     }
    202 
    203     // Override paddingStart/End to return pixel values to match behavor of RenderTableCell.
    204     virtual LayoutUnit paddingEnd() const OVERRIDE { return static_cast<int>(RenderBlock::paddingEnd()); }
    205     virtual LayoutUnit paddingStart() const OVERRIDE { return static_cast<int>(RenderBlock::paddingStart()); }
    206 
    207     LayoutUnit bordersPaddingAndSpacingInRowDirection() const
    208     {
    209         // 'border-spacing' only applies to separate borders (see 17.6.1 The separated borders model).
    210         return borderStart() + borderEnd() + (collapseBorders() ? LayoutUnit() : (paddingStart() + paddingEnd() + borderSpacingInRowDirection()));
    211     }
    212 
    213     // Return the first column or column-group.
    214     RenderTableCol* firstColumn() const;
    215 
    216     RenderTableCol* colElement(unsigned col, bool* startEdge = 0, bool* endEdge = 0) const
    217     {
    218         // The common case is to not have columns, make that case fast.
    219         if (!m_hasColElements)
    220             return 0;
    221         return slowColElement(col, startEdge, endEdge);
    222     }
    223 
    224     bool needsSectionRecalc() const { return m_needsSectionRecalc; }
    225     void setNeedsSectionRecalc()
    226     {
    227         if (documentBeingDestroyed())
    228             return;
    229         m_needsSectionRecalc = true;
    230         setNeedsLayoutAndFullPaintInvalidation();
    231     }
    232 
    233     RenderTableSection* sectionAbove(const RenderTableSection*, SkipEmptySectionsValue = DoNotSkipEmptySections) const;
    234     RenderTableSection* sectionBelow(const RenderTableSection*, SkipEmptySectionsValue = DoNotSkipEmptySections) const;
    235 
    236     RenderTableCell* cellAbove(const RenderTableCell*) const;
    237     RenderTableCell* cellBelow(const RenderTableCell*) const;
    238     RenderTableCell* cellBefore(const RenderTableCell*) const;
    239     RenderTableCell* cellAfter(const RenderTableCell*) const;
    240 
    241     typedef Vector<CollapsedBorderValue> CollapsedBorderValues;
    242     void invalidateCollapsedBorders()
    243     {
    244         m_collapsedBordersValid = false;
    245         m_collapsedBorders.clear();
    246     }
    247     const CollapsedBorderValue* currentBorderValue() const { return m_currentBorder; }
    248 
    249     bool hasSections() const { return m_head || m_foot || m_firstBody; }
    250 
    251     void recalcSectionsIfNeeded() const
    252     {
    253         if (m_needsSectionRecalc)
    254             recalcSections();
    255     }
    256 
    257     static RenderTable* createAnonymousWithParentRenderer(const RenderObject*);
    258     virtual RenderBox* createAnonymousBoxWithSameTypeAs(const RenderObject* parent) const OVERRIDE
    259     {
    260         return createAnonymousWithParentRenderer(parent);
    261     }
    262 
    263     const BorderValue& tableStartBorderAdjoiningCell(const RenderTableCell*) const;
    264     const BorderValue& tableEndBorderAdjoiningCell(const RenderTableCell*) const;
    265 
    266     void addCaption(const RenderTableCaption*);
    267     void removeCaption(const RenderTableCaption*);
    268     void addColumn(const RenderTableCol*);
    269     void removeColumn(const RenderTableCol*);
    270 
    271 protected:
    272     virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle) OVERRIDE;
    273     virtual void simplifiedNormalFlowLayout() OVERRIDE;
    274 
    275 private:
    276     virtual const char* renderName() const OVERRIDE { return "RenderTable"; }
    277 
    278     virtual bool isTable() const OVERRIDE { return true; }
    279 
    280     virtual bool avoidsFloats() const OVERRIDE { return true; }
    281 
    282     virtual void paint(PaintInfo&, const LayoutPoint&) OVERRIDE;
    283     virtual void paintObject(PaintInfo&, const LayoutPoint&) OVERRIDE;
    284     virtual void paintBoxDecorations(PaintInfo&, const LayoutPoint&) OVERRIDE;
    285     virtual void paintMask(PaintInfo&, const LayoutPoint&) OVERRIDE;
    286     virtual void layout() OVERRIDE;
    287     virtual void computeIntrinsicLogicalWidths(LayoutUnit& minWidth, LayoutUnit& maxWidth) const OVERRIDE;
    288     virtual void computePreferredLogicalWidths() OVERRIDE;
    289     virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE;
    290 
    291     virtual int baselinePosition(FontBaseline, bool firstLine, LineDirectionMode, LinePositionMode = PositionOnContainingLine) const OVERRIDE;
    292     virtual int firstLineBoxBaseline() const OVERRIDE;
    293     virtual int inlineBlockBaseline(LineDirectionMode) const OVERRIDE;
    294 
    295     RenderTableCol* slowColElement(unsigned col, bool* startEdge, bool* endEdge) const;
    296 
    297     void updateColumnCache() const;
    298     void invalidateCachedColumns();
    299 
    300     virtual RenderBlock* firstLineBlock() const OVERRIDE;
    301     virtual void updateFirstLetter() OVERRIDE;
    302 
    303     virtual void updateLogicalWidth() OVERRIDE;
    304 
    305     LayoutUnit convertStyleLogicalWidthToComputedWidth(const Length& styleLogicalWidth, LayoutUnit availableWidth);
    306     LayoutUnit convertStyleLogicalHeightToComputedHeight(const Length& styleLogicalHeight);
    307 
    308     virtual LayoutRect overflowClipRect(const LayoutPoint& location, OverlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize) OVERRIDE;
    309 
    310     virtual void addOverflowFromChildren() OVERRIDE;
    311 
    312     void subtractCaptionRect(LayoutRect&) const;
    313 
    314     void recalcCollapsedBorders();
    315     void recalcSections() const;
    316     void layoutCaption(RenderTableCaption*);
    317 
    318     void distributeExtraLogicalHeight(int extraLogicalHeight);
    319 
    320     mutable Vector<int> m_columnPos;
    321     mutable Vector<ColumnStruct> m_columns;
    322     mutable Vector<RenderTableCaption*> m_captions;
    323     mutable Vector<RenderTableCol*> m_columnRenderers;
    324 
    325     mutable RenderTableSection* m_head;
    326     mutable RenderTableSection* m_foot;
    327     mutable RenderTableSection* m_firstBody;
    328 
    329     OwnPtr<TableLayout> m_tableLayout;
    330 
    331     CollapsedBorderValues m_collapsedBorders;
    332     const CollapsedBorderValue* m_currentBorder;
    333     bool m_collapsedBordersValid : 1;
    334 
    335     mutable bool m_hasColElements : 1;
    336     mutable bool m_needsSectionRecalc : 1;
    337 
    338     bool m_columnLogicalWidthChanged : 1;
    339     mutable bool m_columnRenderersValid: 1;
    340     mutable bool m_hasCellColspanThatDeterminesTableWidth : 1;
    341     bool hasCellColspanThatDeterminesTableWidth() const
    342     {
    343         for (unsigned c = 0; c < numEffCols(); c++) {
    344             if (m_columns[c].span > 1)
    345                 return true;
    346         }
    347         return false;
    348     }
    349 
    350     short m_hSpacing;
    351     short m_vSpacing;
    352     int m_borderStart;
    353     int m_borderEnd;
    354 };
    355 
    356 inline RenderTableSection* RenderTable::topSection() const
    357 {
    358     ASSERT(!needsSectionRecalc());
    359     if (m_head)
    360         return m_head;
    361     if (m_firstBody)
    362         return m_firstBody;
    363     return m_foot;
    364 }
    365 
    366 DEFINE_RENDER_OBJECT_TYPE_CASTS(RenderTable, isTable());
    367 
    368 } // namespace WebCore
    369 
    370 #endif // RenderTable_h
    371