Home | History | Annotate | Download | only in rendering
      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 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 
     34 namespace WebCore {
     35 
     36 using namespace HTMLNames;
     37 
     38 RenderTableRow::RenderTableRow(Node* node)
     39     : RenderBox(node)
     40 {
     41     // init RenderObject attributes
     42     setInline(false);   // our object is not Inline
     43 }
     44 
     45 void RenderTableRow::destroy()
     46 {
     47     RenderTableSection* recalcSection = section();
     48 
     49     RenderBox::destroy();
     50 
     51     if (recalcSection)
     52         recalcSection->setNeedsCellRecalc();
     53 }
     54 
     55 void 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 
     65 void 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 
    113 void 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 
    146 IntRect 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
    164 bool 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 
    182 void 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 
    200 void 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