1 /**
2 * This file is part of the DOM implementation for KDE.
3 *
4 * Copyright (C) 1997 Martin Jones (mjones@kde.org)
5 * (C) 1997 Torben Weis (weis@kde.org)
6 * (C) 1998 Waldo Bastian (bastian@kde.org)
7 * (C) 1999 Lars Knoll (knoll@kde.org)
8 * (C) 1999 Antti Koivisto (koivisto@kde.org)
9 * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc.
10 *
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Library General Public
13 * License as published by the Free Software Foundation; either
14 * version 2 of the License, or (at your option) any later version.
15 *
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Library General Public License for more details.
20 *
21 * You should have received a copy of the GNU Library General Public License
22 * along with this library; see the file COPYING.LIB. If not, write to
23 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
24 * Boston, MA 02110-1301, USA.
25 */
26
27 #include "config.h"
28 #include "RenderTableRow.h"
29
30 #include "CachedImage.h"
31 #include "Document.h"
32 #include "HTMLNames.h"
33 #include "RenderTableCell.h"
34 #include "RenderView.h"
35
36 namespace WebCore {
37
38 using namespace HTMLNames;
39
RenderTableRow(Node * node)40 RenderTableRow::RenderTableRow(Node* node)
41 : RenderBox(node)
42 {
43 // init RenderObject attributes
44 setInline(false); // our object is not Inline
45 }
46
destroy()47 void RenderTableRow::destroy()
48 {
49 RenderTableSection* recalcSection = section();
50
51 RenderBox::destroy();
52
53 if (recalcSection)
54 recalcSection->setNeedsCellRecalc();
55 }
56
styleWillChange(StyleDifference diff,const RenderStyle * newStyle)57 void RenderTableRow::styleWillChange(StyleDifference diff, const RenderStyle* newStyle)
58 {
59 if (section() && style() && style()->height() != newStyle->height())
60 section()->setNeedsCellRecalc();
61
62 ASSERT(newStyle->display() == TABLE_ROW);
63
64 RenderBox::styleWillChange(diff, newStyle);
65 }
66
addChild(RenderObject * child,RenderObject * beforeChild)67 void RenderTableRow::addChild(RenderObject* child, RenderObject* beforeChild)
68 {
69 // Make sure we don't append things after :after-generated content if we have it.
70 if (!beforeChild && isAfterContent(lastChild()))
71 beforeChild = lastChild();
72
73 if (!child->isTableCell()) {
74 RenderObject* last = beforeChild;
75 if (!last)
76 last = lastChild();
77 if (last && last->isAnonymous() && last->isTableCell()) {
78 last->addChild(child);
79 return;
80 }
81
82 // If beforeChild is inside an anonymous cell, insert into the cell.
83 if (last && !last->isTableCell() && last->parent() && last->parent()->isAnonymous()) {
84 last->parent()->addChild(child, beforeChild);
85 return;
86 }
87
88 RenderTableCell* cell = new (renderArena()) RenderTableCell(document() /* anonymous object */);
89 RefPtr<RenderStyle> newStyle = RenderStyle::create();
90 newStyle->inheritFrom(style());
91 newStyle->setDisplay(TABLE_CELL);
92 cell->setStyle(newStyle.release());
93 addChild(cell, beforeChild);
94 cell->addChild(child);
95 return;
96 }
97
98 // If the next renderer is actually wrapped in an anonymous table cell, we need to go up and find that.
99 while (beforeChild && beforeChild->parent() != this)
100 beforeChild = beforeChild->parent();
101
102 RenderTableCell* cell = toRenderTableCell(child);
103
104 // Generated content can result in us having a null section so make sure to null check our parent.
105 if (parent())
106 section()->addCell(cell, this);
107
108 ASSERT(!beforeChild || beforeChild->isTableCell());
109 RenderBox::addChild(cell, beforeChild);
110
111 if (beforeChild || nextSibling())
112 section()->setNeedsCellRecalc();
113 }
114
layout()115 void RenderTableRow::layout()
116 {
117 ASSERT(needsLayout());
118
119 // Table rows do not add translation.
120 LayoutStateMaintainer statePusher(view(), this, IntSize());
121
122 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
123 if (child->isTableCell()) {
124 RenderTableCell* cell = toRenderTableCell(child);
125 if (child->needsLayout()) {
126 cell->calcVerticalMargins();
127 cell->layout();
128 }
129 }
130 }
131
132 // We only ever need to repaint if our cells didn't, which menas that they didn't need
133 // layout, so we know that our bounds didn't change. This code is just making up for
134 // the fact that we did not repaint in setStyle() because we had a layout hint.
135 // We cannot call repaint() because our clippedOverflowRectForRepaint() is taken from the
136 // parent table, and being mid-layout, that is invalid. Instead, we repaint our cells.
137 if (selfNeedsLayout() && checkForRepaintDuringLayout()) {
138 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
139 if (child->isTableCell())
140 child->repaint();
141 }
142 }
143
144 statePusher.pop();
145 setNeedsLayout(false);
146 }
147
clippedOverflowRectForRepaint(RenderBoxModelObject * repaintContainer)148 IntRect RenderTableRow::clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer)
149 {
150 ASSERT(parent());
151
152 if (repaintContainer == this)
153 return RenderBox::clippedOverflowRectForRepaint(repaintContainer);
154
155 // For now, just repaint the whole table.
156 // FIXME: Find a better way to do this, e.g., need to repaint all the cells that we
157 // might have propagated a background color into.
158 // FIXME: do repaintContainer checks here
159 if (RenderTable* parentTable = table())
160 return parentTable->clippedOverflowRectForRepaint(repaintContainer);
161
162 return IntRect();
163 }
164
165 // Hit Testing
nodeAtPoint(const HitTestRequest & request,HitTestResult & result,int x,int y,int tx,int ty,HitTestAction action)166 bool RenderTableRow::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty, HitTestAction action)
167 {
168 // Table rows cannot ever be hit tested. Effectively they do not exist.
169 // Just forward to our children always.
170 for (RenderObject* child = lastChild(); child; child = child->previousSibling()) {
171 // FIXME: We have to skip over inline flows, since they can show up inside table rows
172 // at the moment (a demoted inline <form> for example). If we ever implement a
173 // table-specific hit-test method (which we should do for performance reasons anyway),
174 // then we can remove this check.
175 if (child->isTableCell() && !toRenderBox(child)->hasSelfPaintingLayer() && child->nodeAtPoint(request, result, x, y, tx, ty, action)) {
176 updateHitTestResult(result, IntPoint(x - tx, y - ty));
177 return true;
178 }
179 }
180
181 return false;
182 }
183
paint(PaintInfo & paintInfo,int tx,int ty)184 void RenderTableRow::paint(PaintInfo& paintInfo, int tx, int ty)
185 {
186 ASSERT(hasSelfPaintingLayer());
187 if (!layer())
188 return;
189 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
190 if (child->isTableCell()) {
191 // Paint the row background behind the cell.
192 if (paintInfo.phase == PaintPhaseBlockBackground || paintInfo.phase == PaintPhaseChildBlockBackground) {
193 RenderTableCell* cell = toRenderTableCell(child);
194 cell->paintBackgroundsBehindCell(paintInfo, tx, ty, this);
195 }
196 if (!toRenderBox(child)->hasSelfPaintingLayer())
197 child->paint(paintInfo, tx, ty);
198 }
199 }
200 }
201
imageChanged(WrappedImagePtr,const IntRect *)202 void RenderTableRow::imageChanged(WrappedImagePtr, const IntRect*)
203 {
204 // FIXME: Examine cells and repaint only the rect the image paints in.
205 repaint();
206 }
207
208 } // namespace WebCore
209