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