Fix the issue that Web Audio test case fails on PR3.
[framework/web/webkit-efl.git] / Source / WebCore / rendering / RenderTableRow.cpp
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, 2008, 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 #include "config.h"
26 #include "RenderTableRow.h"
27
28 #include "CachedImage.h"
29 #include "Document.h"
30 #include "HTMLNames.h"
31 #include "HitTestResult.h"
32 #include "PaintInfo.h"
33 #include "RenderTableCell.h"
34 #include "RenderView.h"
35
36 namespace WebCore {
37
38 using namespace HTMLNames;
39
40 RenderTableRow::RenderTableRow(Node* node)
41     : RenderBox(node)
42     , m_rowIndex(unsetRowIndex)
43 {
44     // init RenderObject attributes
45     setInline(false);   // our object is not Inline
46 }
47
48 void RenderTableRow::willBeDestroyed()
49 {
50     RenderTableSection* recalcSection = section();
51     
52     RenderBox::willBeDestroyed();
53     
54     if (recalcSection)
55         recalcSection->setNeedsCellRecalc();
56 }
57
58 void RenderTableRow::updateBeforeAndAfterContent()
59 {
60     if (!isAnonymous() && document()->usesBeforeAfterRules()) {
61         children()->updateBeforeAfterContent(this, BEFORE);
62         children()->updateBeforeAfterContent(this, AFTER);
63     }
64 }
65
66 void RenderTableRow::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
67 {
68     ASSERT(style()->display() == TABLE_ROW);
69
70     RenderBox::styleDidChange(diff, oldStyle);
71     propagateStyleToAnonymousChildren();
72
73     if (parent())
74         updateBeforeAndAfterContent();
75
76     if (section() && oldStyle && style()->logicalHeight() != oldStyle->logicalHeight())
77         section()->rowLogicalHeightChanged(rowIndex());
78
79     // If border was changed, notify table.
80     if (parent()) {
81         RenderTable* table = this->table();
82         if (table && !table->selfNeedsLayout() && !table->normalChildNeedsLayout() && oldStyle && oldStyle->border() != style()->border())
83             table->invalidateCollapsedBorders();
84     }
85 }
86
87 void RenderTableRow::addChild(RenderObject* child, RenderObject* beforeChild)
88 {
89     // Make sure we don't append things after :after-generated content if we have it.
90     if (!beforeChild)
91         beforeChild = afterPseudoElementRenderer();
92
93     if (!child->isTableCell()) {
94         RenderObject* last = beforeChild;
95         if (!last)
96             last = lastChild();
97         if (last && last->isAnonymous() && last->isTableCell() && !last->isBeforeOrAfterContent()) {
98             if (beforeChild == last)
99                 beforeChild = last->firstChild();
100             last->addChild(child, beforeChild);
101             return;
102         }
103
104         if (beforeChild && !beforeChild->isAnonymous() && beforeChild->parent() == this) {
105             RenderObject* cell = beforeChild->previousSibling();
106             if (cell && cell->isTableCell() && cell->isAnonymous()) {
107                 cell->addChild(child);
108                 return;
109             }
110         }
111
112         // If beforeChild is inside an anonymous cell, insert into the cell.
113         if (last && !last->isTableCell() && last->parent() && last->parent()->isAnonymous() && !last->parent()->isBeforeOrAfterContent()) {
114             last->parent()->addChild(child, beforeChild);
115             return;
116         }
117
118         RenderTableCell* cell = RenderTableCell::createAnonymousWithParentRenderer(this);
119         addChild(cell, beforeChild);
120         cell->addChild(child);
121         return;
122     } 
123
124     if (beforeChild && beforeChild->parent() != this)
125         beforeChild = splitAnonymousBoxesAroundChild(beforeChild);    
126
127     RenderTableCell* cell = toRenderTableCell(child);
128
129     // Generated content can result in us having a null section so make sure to null check our parent.
130     if (parent())
131         section()->addCell(cell, this);
132
133     ASSERT(!beforeChild || beforeChild->isTableCell());
134     RenderBox::addChild(cell, beforeChild);
135
136     if (beforeChild || nextSibling())
137         section()->setNeedsCellRecalc();
138 }
139
140 void RenderTableRow::layout()
141 {
142     ASSERT(needsLayout());
143
144     // Table rows do not add translation.
145     LayoutStateMaintainer statePusher(view(), this, LayoutSize(), style()->isFlippedBlocksWritingMode());
146
147     bool paginated = view()->layoutState()->isPaginated();
148                 
149     for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
150         if (child->isTableCell()) {
151             RenderTableCell* cell = toRenderTableCell(child);
152             if (!cell->needsLayout() && paginated && view()->layoutState()->pageLogicalHeight() && view()->layoutState()->pageLogicalOffset(cell, cell->logicalTop()) != cell->pageLogicalOffset())
153                 cell->setChildNeedsLayout(true, MarkOnlyThis);
154
155             if (child->needsLayout()) {
156                 cell->computeBlockDirectionMargins(table());
157                 cell->layout();
158             }
159         }
160     }
161
162     // We only ever need to repaint if our cells didn't, which menas that they didn't need
163     // layout, so we know that our bounds didn't change. This code is just making up for
164     // the fact that we did not repaint in setStyle() because we had a layout hint.
165     // We cannot call repaint() because our clippedOverflowRectForRepaint() is taken from the
166     // parent table, and being mid-layout, that is invalid. Instead, we repaint our cells.
167     if (selfNeedsLayout() && checkForRepaintDuringLayout()) {
168         for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
169             if (child->isTableCell())
170                 child->repaint();
171         }
172     }
173
174     statePusher.pop();
175     // RenderTableSection::layoutRows will set our logical height and width later, so it calls updateLayerTransform().
176     setNeedsLayout(false);
177 }
178
179 LayoutRect RenderTableRow::clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer) const
180 {
181     ASSERT(parent());
182
183     if (repaintContainer == this)
184         return RenderBox::clippedOverflowRectForRepaint(repaintContainer);
185
186     // For now, just repaint the whole table.
187     // FIXME: Find a better way to do this, e.g., need to repaint all the cells that we
188     // might have propagated a background color into.
189     // FIXME: do repaintContainer checks here
190     if (RenderTable* parentTable = table())
191         return parentTable->clippedOverflowRectForRepaint(repaintContainer);
192
193     return LayoutRect();
194 }
195
196 // Hit Testing
197 bool RenderTableRow::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action)
198 {
199     // Table rows cannot ever be hit tested.  Effectively they do not exist.
200     // Just forward to our children always.
201     for (RenderObject* child = lastChild(); child; child = child->previousSibling()) {
202         // FIXME: We have to skip over inline flows, since they can show up inside table rows
203         // at the moment (a demoted inline <form> for example). If we ever implement a
204         // table-specific hit-test method (which we should do for performance reasons anyway),
205         // then we can remove this check.
206         if (child->isTableCell() && !toRenderBox(child)->hasSelfPaintingLayer()) {
207             LayoutPoint cellPoint = flipForWritingModeForChild(toRenderTableCell(child), accumulatedOffset);
208             if (child->nodeAtPoint(request, result, pointInContainer, cellPoint, action)) {
209                 updateHitTestResult(result, pointInContainer.point() - toLayoutSize(cellPoint));
210                 return true;
211             }
212         }
213     }
214
215     return false;
216 }
217
218 void RenderTableRow::paintOutlineForRowIfNeeded(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
219 {
220     LayoutPoint adjustedPaintOffset = paintOffset + location();
221     PaintPhase paintPhase = paintInfo.phase;
222     if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseSelfOutline) && style()->visibility() == VISIBLE)
223         paintOutline(paintInfo.context, LayoutRect(adjustedPaintOffset, size()));
224 }
225
226 void RenderTableRow::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
227 {
228     ASSERT(hasSelfPaintingLayer());
229
230     paintOutlineForRowIfNeeded(paintInfo, paintOffset);
231     for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
232         if (child->isTableCell()) {
233             // Paint the row background behind the cell.
234             if (paintInfo.phase == PaintPhaseBlockBackground || paintInfo.phase == PaintPhaseChildBlockBackground) {
235                 RenderTableCell* cell = toRenderTableCell(child);
236                 cell->paintBackgroundsBehindCell(paintInfo, paintOffset, this);
237             }
238             if (!toRenderBox(child)->hasSelfPaintingLayer())
239                 child->paint(paintInfo, paintOffset);
240         }
241     }
242 }
243
244 void RenderTableRow::imageChanged(WrappedImagePtr, const IntRect*)
245 {
246     // FIXME: Examine cells and repaint only the rect the image paints in.
247     repaint();
248 }
249
250 RenderTableRow* RenderTableRow::createAnonymousWithParentRenderer(const RenderObject* parent)
251 {
252     RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(parent->style(), TABLE_ROW);
253     RenderTableRow* newRow = new (parent->renderArena()) RenderTableRow(parent->document() /* is anonymous */);
254     newRow->setStyle(newStyle.release());
255     return newRow;
256 }
257
258 } // namespace WebCore