1/*
2 * Copyright (C) 1997 Martin Jones (mjones@kde.org)
3 *           (C) 1997 Torben Weis (weis@kde.org)
4 *           (C) 1998 Waldo Bastian (bastian@kde.org)
5 *           (C) 1999 Lars Knoll (knoll@kde.org)
6 *           (C) 1999 Antti Koivisto (koivisto@kde.org)
7 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2009, 2013 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 RenderTableCell_h
26#define RenderTableCell_h
27
28#include "core/rendering/RenderBlockFlow.h"
29#include "core/rendering/RenderTableRow.h"
30#include "core/rendering/RenderTableSection.h"
31#include "platform/LengthFunctions.h"
32
33namespace blink {
34
35static const unsigned unsetColumnIndex = 0x1FFFFFFF;
36static const unsigned maxColumnIndex = 0x1FFFFFFE; // 536,870,910
37
38enum IncludeBorderColorOrNot { DoNotIncludeBorderColor, IncludeBorderColor };
39
40class SubtreeLayoutScope;
41
42class RenderTableCell FINAL : public RenderBlockFlow {
43public:
44    explicit RenderTableCell(Element*);
45
46    unsigned colSpan() const
47    {
48        if (!m_hasColSpan)
49            return 1;
50        return parseColSpanFromDOM();
51    }
52    unsigned rowSpan() const
53    {
54        if (!m_hasRowSpan)
55            return 1;
56        return parseRowSpanFromDOM();
57    }
58
59    // Called from HTMLTableCellElement.
60    void colSpanOrRowSpanChanged();
61
62    void setCol(unsigned column)
63    {
64        if (UNLIKELY(column > maxColumnIndex))
65            CRASH();
66
67        m_column = column;
68    }
69
70    unsigned col() const
71    {
72        ASSERT(m_column != unsetColumnIndex);
73        return m_column;
74    }
75
76    RenderTableRow* row() const { return toRenderTableRow(parent()); }
77    RenderTableSection* section() const { return toRenderTableSection(parent()->parent()); }
78    RenderTable* table() const { return toRenderTable(parent()->parent()->parent()); }
79
80    RenderTableCell* previousCell() const;
81    RenderTableCell* nextCell() const;
82
83    unsigned rowIndex() const
84    {
85        // This function shouldn't be called on a detached cell.
86        ASSERT(row());
87        return row()->rowIndex();
88    }
89
90    Length styleOrColLogicalWidth() const
91    {
92        Length styleWidth = style()->logicalWidth();
93        if (!styleWidth.isAuto())
94            return styleWidth;
95        if (RenderTableCol* firstColumn = table()->colElement(col()))
96            return logicalWidthFromColumns(firstColumn, styleWidth);
97        return styleWidth;
98    }
99
100    int logicalHeightForRowSizing() const
101    {
102        // FIXME: This function does too much work, and is very hot during table layout!
103        int adjustedLogicalHeight = pixelSnappedLogicalHeight() - (intrinsicPaddingBefore() + intrinsicPaddingAfter());
104        int styleLogicalHeight = valueForLength(style()->logicalHeight(), 0);
105        // In strict mode, box-sizing: content-box do the right thing and actually add in the border and padding.
106        // Call computedCSSPadding* directly to avoid including implicitPadding.
107        if (!document().inQuirksMode() && style()->boxSizing() != BORDER_BOX)
108            styleLogicalHeight += (computedCSSPaddingBefore() + computedCSSPaddingAfter()).floor() + borderBefore() + borderAfter();
109        return max(styleLogicalHeight, adjustedLogicalHeight);
110    }
111
112
113    void setCellLogicalWidth(int constrainedLogicalWidth, SubtreeLayoutScope&);
114
115    virtual int borderLeft() const OVERRIDE;
116    virtual int borderRight() const OVERRIDE;
117    virtual int borderTop() const OVERRIDE;
118    virtual int borderBottom() const OVERRIDE;
119    virtual int borderStart() const OVERRIDE;
120    virtual int borderEnd() const OVERRIDE;
121    virtual int borderBefore() const OVERRIDE;
122    virtual int borderAfter() const OVERRIDE;
123
124    void collectBorderValues(RenderTable::CollapsedBorderValues&) const;
125    static void sortBorderValues(RenderTable::CollapsedBorderValues&);
126
127    virtual void layout() OVERRIDE;
128
129    virtual void paint(PaintInfo&, const LayoutPoint&) OVERRIDE;
130
131    void paintCollapsedBorders(PaintInfo&, const LayoutPoint&);
132    void paintBackgroundsBehindCell(PaintInfo&, const LayoutPoint&, RenderObject* backgroundObject);
133
134    LayoutUnit cellBaselinePosition() const;
135    bool isBaselineAligned() const
136    {
137        EVerticalAlign va = style()->verticalAlign();
138        return va == BASELINE || va == TEXT_BOTTOM || va == TEXT_TOP || va == SUPER || va == SUB || va == LENGTH;
139    }
140
141    void computeIntrinsicPadding(int rowHeight, SubtreeLayoutScope&);
142    void clearIntrinsicPadding() { setIntrinsicPadding(0, 0); }
143
144    int intrinsicPaddingBefore() const { return m_intrinsicPaddingBefore; }
145    int intrinsicPaddingAfter() const { return m_intrinsicPaddingAfter; }
146
147    virtual LayoutUnit paddingTop() const OVERRIDE;
148    virtual LayoutUnit paddingBottom() const OVERRIDE;
149    virtual LayoutUnit paddingLeft() const OVERRIDE;
150    virtual LayoutUnit paddingRight() const OVERRIDE;
151
152    // FIXME: For now we just assume the cell has the same block flow direction as the table. It's likely we'll
153    // create an extra anonymous RenderBlock to handle mixing directionality anyway, in which case we can lock
154    // the block flow directionality of the cells to the table's directionality.
155    virtual LayoutUnit paddingBefore() const OVERRIDE;
156    virtual LayoutUnit paddingAfter() const OVERRIDE;
157
158    void setOverrideLogicalContentHeightFromRowHeight(LayoutUnit);
159
160    virtual void scrollbarsChanged(bool horizontalScrollbarChanged, bool verticalScrollbarChanged) OVERRIDE;
161
162    bool cellWidthChanged() const { return m_cellWidthChanged; }
163    void setCellWidthChanged(bool b = true) { m_cellWidthChanged = b; }
164
165    static RenderTableCell* createAnonymous(Document*);
166    static RenderTableCell* createAnonymousWithParentRenderer(const RenderObject*);
167    virtual RenderBox* createAnonymousBoxWithSameTypeAs(const RenderObject* parent) const OVERRIDE
168    {
169        return createAnonymousWithParentRenderer(parent);
170    }
171
172    // This function is used to unify which table part's style we use for computing direction and
173    // writing mode. Writing modes are not allowed on row group and row but direction is.
174    // This means we can safely use the same style in all cases to simplify our code.
175    // FIXME: Eventually this function should replaced by style() once we support direction
176    // on all table parts and writing-mode on cells.
177    const RenderStyle* styleForCellFlow() const
178    {
179        return row()->style();
180    }
181
182    const BorderValue& borderAdjoiningTableStart() const
183    {
184        ASSERT(isFirstOrLastCellInRow());
185        if (section()->hasSameDirectionAs(table()))
186            return style()->borderStart();
187
188        return style()->borderEnd();
189    }
190
191    const BorderValue& borderAdjoiningTableEnd() const
192    {
193        ASSERT(isFirstOrLastCellInRow());
194        if (section()->hasSameDirectionAs(table()))
195            return style()->borderEnd();
196
197        return style()->borderStart();
198    }
199
200    const BorderValue& borderAdjoiningCellBefore(const RenderTableCell* cell)
201    {
202        ASSERT_UNUSED(cell, table()->cellAfter(cell) == this);
203        // FIXME: https://webkit.org/b/79272 - Add support for mixed directionality at the cell level.
204        return style()->borderStart();
205    }
206
207    const BorderValue& borderAdjoiningCellAfter(const RenderTableCell* cell)
208    {
209        ASSERT_UNUSED(cell, table()->cellBefore(cell) == this);
210        // FIXME: https://webkit.org/b/79272 - Add support for mixed directionality at the cell level.
211        return style()->borderEnd();
212    }
213
214#if ENABLE(ASSERT)
215    bool isFirstOrLastCellInRow() const
216    {
217        return !table()->cellAfter(this) || !table()->cellBefore(this);
218    }
219#endif
220protected:
221    virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle) OVERRIDE;
222    virtual void computePreferredLogicalWidths() OVERRIDE;
223
224    virtual void addLayerHitTestRects(LayerHitTestRects&, const RenderLayer* currentCompositedLayer, const LayoutPoint& layerOffset, const LayoutRect& containerRect) const OVERRIDE;
225
226private:
227    virtual const char* renderName() const OVERRIDE { return (isAnonymous() || isPseudoElement()) ? "RenderTableCell (anonymous)" : "RenderTableCell"; }
228
229    virtual bool isTableCell() const OVERRIDE { return true; }
230
231    virtual void willBeRemovedFromTree() OVERRIDE;
232
233    virtual void updateLogicalWidth() OVERRIDE;
234
235    virtual void paintBoxDecorationBackground(PaintInfo&, const LayoutPoint&) OVERRIDE;
236    virtual void paintMask(PaintInfo&, const LayoutPoint&) OVERRIDE;
237
238    virtual bool boxShadowShouldBeAppliedToBackground(BackgroundBleedAvoidance, InlineFlowBox*) const OVERRIDE;
239
240    virtual LayoutSize offsetFromContainer(const RenderObject*, const LayoutPoint&, bool* offsetDependsOnPoint = 0) const OVERRIDE;
241    virtual LayoutRect clippedOverflowRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer, const PaintInvalidationState* = 0) const OVERRIDE;
242    virtual void mapRectToPaintInvalidationBacking(const RenderLayerModelObject* paintInvalidationContainer, LayoutRect&, const PaintInvalidationState*) const OVERRIDE;
243
244    int borderHalfLeft(bool outer) const;
245    int borderHalfRight(bool outer) const;
246    int borderHalfTop(bool outer) const;
247    int borderHalfBottom(bool outer) const;
248
249    int borderHalfStart(bool outer) const;
250    int borderHalfEnd(bool outer) const;
251    int borderHalfBefore(bool outer) const;
252    int borderHalfAfter(bool outer) const;
253
254    void setIntrinsicPaddingBefore(int p) { m_intrinsicPaddingBefore = p; }
255    void setIntrinsicPaddingAfter(int p) { m_intrinsicPaddingAfter = p; }
256    void setIntrinsicPadding(int before, int after) { setIntrinsicPaddingBefore(before); setIntrinsicPaddingAfter(after); }
257
258    bool hasStartBorderAdjoiningTable() const;
259    bool hasEndBorderAdjoiningTable() const;
260
261    CollapsedBorderValue collapsedStartBorder(IncludeBorderColorOrNot = IncludeBorderColor) const;
262    CollapsedBorderValue collapsedEndBorder(IncludeBorderColorOrNot = IncludeBorderColor) const;
263    CollapsedBorderValue collapsedBeforeBorder(IncludeBorderColorOrNot = IncludeBorderColor) const;
264    CollapsedBorderValue collapsedAfterBorder(IncludeBorderColorOrNot = IncludeBorderColor) const;
265
266    CollapsedBorderValue cachedCollapsedLeftBorder(const RenderStyle*) const;
267    CollapsedBorderValue cachedCollapsedRightBorder(const RenderStyle*) const;
268    CollapsedBorderValue cachedCollapsedTopBorder(const RenderStyle*) const;
269    CollapsedBorderValue cachedCollapsedBottomBorder(const RenderStyle*) const;
270
271    CollapsedBorderValue computeCollapsedStartBorder(IncludeBorderColorOrNot = IncludeBorderColor) const;
272    CollapsedBorderValue computeCollapsedEndBorder(IncludeBorderColorOrNot = IncludeBorderColor) const;
273    CollapsedBorderValue computeCollapsedBeforeBorder(IncludeBorderColorOrNot = IncludeBorderColor) const;
274    CollapsedBorderValue computeCollapsedAfterBorder(IncludeBorderColorOrNot = IncludeBorderColor) const;
275
276    Length logicalWidthFromColumns(RenderTableCol* firstColForThisCell, Length widthFromStyle) const;
277
278    void updateColAndRowSpanFlags();
279
280    unsigned parseRowSpanFromDOM() const;
281    unsigned parseColSpanFromDOM() const;
282
283    void nextSibling() const WTF_DELETED_FUNCTION;
284    void previousSibling() const WTF_DELETED_FUNCTION;
285
286    // Note MSVC will only pack members if they have identical types, hence we use unsigned instead of bool here.
287    unsigned m_column : 29;
288    unsigned m_cellWidthChanged : 1;
289    unsigned m_hasColSpan: 1;
290    unsigned m_hasRowSpan: 1;
291    int m_intrinsicPaddingBefore;
292    int m_intrinsicPaddingAfter;
293};
294
295DEFINE_RENDER_OBJECT_TYPE_CASTS(RenderTableCell, isTableCell());
296
297inline RenderTableCell* RenderTableCell::previousCell() const
298{
299    return toRenderTableCell(RenderObject::previousSibling());
300}
301
302inline RenderTableCell* RenderTableCell::nextCell() const
303{
304    return toRenderTableCell(RenderObject::nextSibling());
305}
306
307inline RenderTableCell* RenderTableRow::firstCell() const
308{
309    ASSERT(children() == virtualChildren());
310    return toRenderTableCell(children()->firstChild());
311}
312
313inline RenderTableCell* RenderTableRow::lastCell() const
314{
315    ASSERT(children() == virtualChildren());
316    return toRenderTableCell(children()->lastChild());
317}
318
319} // namespace blink
320
321#endif // RenderTableCell_h
322