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 Apple Computer, Inc. 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 "RenderTableCell.h" 32#include "RenderView.h" 33 34namespace WebCore { 35 36using namespace HTMLNames; 37 38RenderTableRow::RenderTableRow(Node* node) 39 : RenderBox(node) 40{ 41 // init RenderObject attributes 42 setInline(false); // our object is not Inline 43} 44 45void RenderTableRow::destroy() 46{ 47 RenderTableSection* recalcSection = section(); 48 49 RenderBox::destroy(); 50 51 if (recalcSection) 52 recalcSection->setNeedsCellRecalc(); 53} 54 55void RenderTableRow::styleWillChange(StyleDifference diff, const RenderStyle* newStyle) 56{ 57 if (section() && style() && style()->height() != newStyle->height()) 58 section()->setNeedsCellRecalc(); 59 60 ASSERT(newStyle->display() == TABLE_ROW); 61 62 RenderBox::styleWillChange(diff, newStyle); 63} 64 65void RenderTableRow::addChild(RenderObject* child, RenderObject* beforeChild) 66{ 67 // Make sure we don't append things after :after-generated content if we have it. 68 if (!beforeChild && isAfterContent(lastChild())) 69 beforeChild = lastChild(); 70 71 if (!child->isTableCell()) { 72 RenderObject* last = beforeChild; 73 if (!last) 74 last = lastChild(); 75 if (last && last->isAnonymous() && last->isTableCell()) { 76 last->addChild(child); 77 return; 78 } 79 80 // If beforeChild is inside an anonymous cell, insert into the cell. 81 if (last && !last->isTableCell() && last->parent() && last->parent()->isAnonymous()) { 82 last->parent()->addChild(child, beforeChild); 83 return; 84 } 85 86 RenderTableCell* cell = new (renderArena()) RenderTableCell(document() /* anonymous object */); 87 RefPtr<RenderStyle> newStyle = RenderStyle::create(); 88 newStyle->inheritFrom(style()); 89 newStyle->setDisplay(TABLE_CELL); 90 cell->setStyle(newStyle.release()); 91 addChild(cell, beforeChild); 92 cell->addChild(child); 93 return; 94 } 95 96 // If the next renderer is actually wrapped in an anonymous table cell, we need to go up and find that. 97 while (beforeChild && beforeChild->parent() != this) 98 beforeChild = beforeChild->parent(); 99 100 RenderTableCell* cell = toRenderTableCell(child); 101 102 // Generated content can result in us having a null section so make sure to null check our parent. 103 if (parent()) 104 section()->addCell(cell, this); 105 106 ASSERT(!beforeChild || beforeChild->isTableCell()); 107 RenderBox::addChild(cell, beforeChild); 108 109 if (beforeChild || nextSibling()) 110 section()->setNeedsCellRecalc(); 111} 112 113void RenderTableRow::layout() 114{ 115 ASSERT(needsLayout()); 116 117 // Table rows do not add translation. 118 LayoutStateMaintainer statePusher(view(), this, IntSize()); 119 120 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { 121 if (child->isTableCell()) { 122 RenderTableCell* cell = toRenderTableCell(child); 123 if (child->needsLayout()) { 124 cell->calcVerticalMargins(); 125 cell->layout(); 126 } 127 } 128 } 129 130 // We only ever need to repaint if our cells didn't, which menas that they didn't need 131 // layout, so we know that our bounds didn't change. This code is just making up for 132 // the fact that we did not repaint in setStyle() because we had a layout hint. 133 // We cannot call repaint() because our clippedOverflowRectForRepaint() is taken from the 134 // parent table, and being mid-layout, that is invalid. Instead, we repaint our cells. 135 if (selfNeedsLayout() && checkForRepaintDuringLayout()) { 136 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { 137 if (child->isTableCell()) 138 child->repaint(); 139 } 140 } 141 142 statePusher.pop(); 143 setNeedsLayout(false); 144} 145 146IntRect RenderTableRow::clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer) 147{ 148 ASSERT(parent()); 149 150 if (repaintContainer == this) 151 return RenderBox::clippedOverflowRectForRepaint(repaintContainer); 152 153 // For now, just repaint the whole table. 154 // FIXME: Find a better way to do this, e.g., need to repaint all the cells that we 155 // might have propagated a background color into. 156 // FIXME: do repaintContainer checks here 157 if (RenderTable* parentTable = table()) 158 return parentTable->clippedOverflowRectForRepaint(repaintContainer); 159 160 return IntRect(); 161} 162 163// Hit Testing 164bool RenderTableRow::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty, HitTestAction action) 165{ 166 // Table rows cannot ever be hit tested. Effectively they do not exist. 167 // Just forward to our children always. 168 for (RenderObject* child = lastChild(); child; child = child->previousSibling()) { 169 // FIXME: We have to skip over inline flows, since they can show up inside table rows 170 // at the moment (a demoted inline <form> for example). If we ever implement a 171 // table-specific hit-test method (which we should do for performance reasons anyway), 172 // then we can remove this check. 173 if (child->isTableCell() && !toRenderBox(child)->hasSelfPaintingLayer() && child->nodeAtPoint(request, result, x, y, tx, ty, action)) { 174 updateHitTestResult(result, IntPoint(x - tx, y - ty)); 175 return true; 176 } 177 } 178 179 return false; 180} 181 182void RenderTableRow::paint(PaintInfo& paintInfo, int tx, int ty) 183{ 184 ASSERT(hasSelfPaintingLayer()); 185 if (!layer()) 186 return; 187 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { 188 if (child->isTableCell()) { 189 // Paint the row background behind the cell. 190 if (paintInfo.phase == PaintPhaseBlockBackground || paintInfo.phase == PaintPhaseChildBlockBackground) { 191 RenderTableCell* cell = toRenderTableCell(child); 192 cell->paintBackgroundsBehindCell(paintInfo, tx, ty, this); 193 } 194 if (!toRenderBox(child)->hasSelfPaintingLayer()) 195 child->paint(paintInfo, tx, ty); 196 } 197 } 198} 199 200void RenderTableRow::imageChanged(WrappedImagePtr, const IntRect*) 201{ 202 // FIXME: Examine cells and repaint only the rect the image paints in. 203 repaint(); 204} 205 206} // namespace WebCore 207