• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
33 namespace WebCore {
34 
35 static const unsigned unsetColumnIndex = 0x1FFFFFFF;
36 static const unsigned maxColumnIndex = 0x1FFFFFFE; // 536,870,910
37 
38 enum IncludeBorderColorOrNot { DoNotIncludeBorderColor, IncludeBorderColor };
39 
40 class SubtreeLayoutScope;
41 
42 class RenderTableCell FINAL : public RenderBlockFlow {
43 public:
44     explicit RenderTableCell(Element*);
45 
colSpan()46     unsigned colSpan() const
47     {
48         if (!m_hasColSpan)
49             return 1;
50         return parseColSpanFromDOM();
51     }
rowSpan()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 
setCol(unsigned column)62     void setCol(unsigned column)
63     {
64         if (UNLIKELY(column > maxColumnIndex))
65             CRASH();
66 
67         m_column = column;
68     }
69 
col()70     unsigned col() const
71     {
72         ASSERT(m_column != unsetColumnIndex);
73         return m_column;
74     }
75 
row()76     RenderTableRow* row() const { return toRenderTableRow(parent()); }
section()77     RenderTableSection* section() const { return toRenderTableSection(parent()->parent()); }
table()78     RenderTable* table() const { return toRenderTable(parent()->parent()->parent()); }
79 
80     RenderTableCell* previousCell() const;
81     RenderTableCell* nextCell() const;
82 
rowIndex()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 
styleOrColLogicalWidth()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 
logicalHeightForRowSizing()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;
isBaselineAligned()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&);
clearIntrinsicPadding()142     void clearIntrinsicPadding() { setIntrinsicPadding(0, 0); }
143 
intrinsicPaddingBefore()144     int intrinsicPaddingBefore() const { return m_intrinsicPaddingBefore; }
intrinsicPaddingAfter()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 
cellWidthChanged()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*);
createAnonymousBoxWithSameTypeAs(const RenderObject * parent)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.
styleForCellFlow()177     const RenderStyle* styleForCellFlow() const
178     {
179         return row()->style();
180     }
181 
borderAdjoiningTableStart()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 
borderAdjoiningTableEnd()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 
borderAdjoiningCellBefore(const RenderTableCell * cell)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 
borderAdjoiningCellAfter(const RenderTableCell * cell)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 #ifndef NDEBUG
isFirstOrLastCellInRow()215     bool isFirstOrLastCellInRow() const
216     {
217         return !table()->cellAfter(this) || !table()->cellBefore(this);
218     }
219 #endif
220 protected:
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 
226 private:
renderName()227     virtual const char* renderName() const OVERRIDE { return (isAnonymous() || isPseudoElement()) ? "RenderTableCell (anonymous)" : "RenderTableCell"; }
228 
isTableCell()229     virtual bool isTableCell() const OVERRIDE { return true; }
230 
231     virtual void willBeRemovedFromTree() OVERRIDE;
232 
233     virtual void updateLogicalWidth() OVERRIDE;
234 
235     virtual void paintBoxDecorations(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 OVERRIDE;
242     virtual void mapRectToPaintInvalidationBacking(const RenderLayerModelObject* paintInvalidationContainer, LayoutRect&, bool fixed = false) 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 
setIntrinsicPaddingBefore(int p)254     void setIntrinsicPaddingBefore(int p) { m_intrinsicPaddingBefore = p; }
setIntrinsicPaddingAfter(int p)255     void setIntrinsicPaddingAfter(int p) { m_intrinsicPaddingAfter = p; }
setIntrinsicPadding(int before,int after)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 
295 DEFINE_RENDER_OBJECT_TYPE_CASTS(RenderTableCell, isTableCell());
296 
previousCell()297 inline RenderTableCell* RenderTableCell::previousCell() const
298 {
299     return toRenderTableCell(RenderObject::previousSibling());
300 }
301 
nextCell()302 inline RenderTableCell* RenderTableCell::nextCell() const
303 {
304     return toRenderTableCell(RenderObject::nextSibling());
305 }
306 
firstCell()307 inline RenderTableCell* RenderTableRow::firstCell() const
308 {
309     ASSERT(children() == virtualChildren());
310     return toRenderTableCell(children()->firstChild());
311 }
312 
lastCell()313 inline RenderTableCell* RenderTableRow::lastCell() const
314 {
315     ASSERT(children() == virtualChildren());
316     return toRenderTableCell(children()->lastChild());
317 }
318 
319 } // namespace WebCore
320 
321 #endif // RenderTableCell_h
322