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, 2007, 2008, 2009, 2010, 2013 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 "core/rendering/RenderTableRow.h"
     27 
     28 #include "core/HTMLNames.h"
     29 #include "core/dom/Document.h"
     30 #include "core/fetch/ImageResource.h"
     31 #include "core/rendering/GraphicsContextAnnotator.h"
     32 #include "core/rendering/HitTestResult.h"
     33 #include "core/rendering/PaintInfo.h"
     34 #include "core/rendering/RenderTableCell.h"
     35 #include "core/rendering/RenderView.h"
     36 #include "core/rendering/SubtreeLayoutScope.h"
     37 #include "core/rendering/style/StyleInheritedData.h"
     38 
     39 namespace WebCore {
     40 
     41 using namespace HTMLNames;
     42 
     43 RenderTableRow::RenderTableRow(Element* element)
     44     : RenderBox(element)
     45     , m_rowIndex(unsetRowIndex)
     46 {
     47     // init RenderObject attributes
     48     setInline(false);   // our object is not Inline
     49 }
     50 
     51 void RenderTableRow::willBeRemovedFromTree()
     52 {
     53     RenderBox::willBeRemovedFromTree();
     54 
     55     section()->setNeedsCellRecalc();
     56 }
     57 
     58 static bool borderWidthChanged(const RenderStyle* oldStyle, const RenderStyle* newStyle)
     59 {
     60     return oldStyle->borderLeftWidth() != newStyle->borderLeftWidth()
     61         || oldStyle->borderTopWidth() != newStyle->borderTopWidth()
     62         || oldStyle->borderRightWidth() != newStyle->borderRightWidth()
     63         || oldStyle->borderBottomWidth() != newStyle->borderBottomWidth();
     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 (section() && oldStyle && style()->logicalHeight() != oldStyle->logicalHeight())
     74         section()->rowLogicalHeightChanged(rowIndex());
     75 
     76     // If border was changed, notify table.
     77     if (parent()) {
     78         RenderTable* table = this->table();
     79         if (table && !table->selfNeedsLayout() && !table->normalChildNeedsLayout() && oldStyle && oldStyle->border() != style()->border())
     80             table->invalidateCollapsedBorders();
     81 
     82         if (table && oldStyle && diff.needsFullLayout() && needsLayout() && table->collapseBorders() && borderWidthChanged(oldStyle, style())) {
     83             // If the border width changes on a row, we need to make sure the cells in the row know to lay out again.
     84             // This only happens when borders are collapsed, since they end up affecting the border sides of the cell
     85             // itself.
     86             for (RenderBox* childBox = firstChildBox(); childBox; childBox = childBox->nextSiblingBox()) {
     87                 if (!childBox->isTableCell())
     88                     continue;
     89                 childBox->setChildNeedsLayout();
     90             }
     91         }
     92     }
     93 }
     94 
     95 const BorderValue& RenderTableRow::borderAdjoiningStartCell(const RenderTableCell* cell) const
     96 {
     97     ASSERT_UNUSED(cell, cell->isFirstOrLastCellInRow());
     98     // FIXME: https://webkit.org/b/79272 - Add support for mixed directionality at the cell level.
     99     return style()->borderStart();
    100 }
    101 
    102 const BorderValue& RenderTableRow::borderAdjoiningEndCell(const RenderTableCell* cell) const
    103 {
    104     ASSERT_UNUSED(cell, cell->isFirstOrLastCellInRow());
    105     // FIXME: https://webkit.org/b/79272 - Add support for mixed directionality at the cell level.
    106     return style()->borderEnd();
    107 }
    108 
    109 void RenderTableRow::addChild(RenderObject* child, RenderObject* beforeChild)
    110 {
    111     if (!child->isTableCell()) {
    112         RenderObject* last = beforeChild;
    113         if (!last)
    114             last = lastCell();
    115         if (last && last->isAnonymous() && last->isTableCell() && !last->isBeforeOrAfterContent()) {
    116             RenderTableCell* lastCell = toRenderTableCell(last);
    117             if (beforeChild == lastCell)
    118                 beforeChild = lastCell->firstChild();
    119             lastCell->addChild(child, beforeChild);
    120             return;
    121         }
    122 
    123         if (beforeChild && !beforeChild->isAnonymous() && beforeChild->parent() == this) {
    124             RenderObject* cell = beforeChild->previousSibling();
    125             if (cell && cell->isTableCell() && cell->isAnonymous()) {
    126                 cell->addChild(child);
    127                 return;
    128             }
    129         }
    130 
    131         // If beforeChild is inside an anonymous cell, insert into the cell.
    132         if (last && !last->isTableCell() && last->parent() && last->parent()->isAnonymous() && !last->parent()->isBeforeOrAfterContent()) {
    133             last->parent()->addChild(child, beforeChild);
    134             return;
    135         }
    136 
    137         RenderTableCell* cell = RenderTableCell::createAnonymousWithParentRenderer(this);
    138         addChild(cell, beforeChild);
    139         cell->addChild(child);
    140         return;
    141     }
    142 
    143     if (beforeChild && beforeChild->parent() != this)
    144         beforeChild = splitAnonymousBoxesAroundChild(beforeChild);
    145 
    146     RenderTableCell* cell = toRenderTableCell(child);
    147 
    148     // Generated content can result in us having a null section so make sure to null check our parent.
    149     if (parent())
    150         section()->addCell(cell, this);
    151 
    152     ASSERT(!beforeChild || beforeChild->isTableCell());
    153     RenderBox::addChild(cell, beforeChild);
    154 
    155     if (beforeChild || nextRow())
    156         section()->setNeedsCellRecalc();
    157 }
    158 
    159 void RenderTableRow::layout()
    160 {
    161     ASSERT(needsLayout());
    162 
    163     // Table rows do not add translation.
    164     LayoutState state(*this, LayoutSize());
    165 
    166     for (RenderTableCell* cell = firstCell(); cell; cell = cell->nextCell()) {
    167         SubtreeLayoutScope layouter(*cell);
    168         if (!cell->needsLayout())
    169             cell->markForPaginationRelayoutIfNeeded(layouter);
    170         if (cell->needsLayout()) {
    171             cell->computeAndSetBlockDirectionMargins(table());
    172             cell->layout();
    173         }
    174     }
    175 
    176     m_overflow.clear();
    177     addVisualEffectOverflow();
    178 
    179     // We only ever need to issue paint invalidations if our cells didn't, which means that they didn't need
    180     // layout, so we know that our bounds didn't change. This code is just making up for
    181     // the fact that we did not invalidate paints in setStyle() because we had a layout hint.
    182     // We cannot call repaint() because our clippedOverflowRectForPaintInvalidation() is taken from the
    183     // parent table, and being mid-layout, that is invalid. Instead, we issue paint invalidations for our cells.
    184     if (selfNeedsLayout() && checkForPaintInvalidation()) {
    185         for (RenderTableCell* cell = firstCell(); cell; cell = cell->nextCell()) {
    186             if (RuntimeEnabledFeatures::repaintAfterLayoutEnabled()) {
    187                 // FIXME: Is this needed with Repaint After Layout?
    188                 cell->setShouldDoFullPaintInvalidationAfterLayout(true);
    189             } else {
    190                 cell->paintInvalidationForWholeRenderer();
    191             }
    192         }
    193     }
    194 
    195     // RenderTableSection::layoutRows will set our logical height and width later, so it calls updateLayerTransform().
    196     clearNeedsLayout();
    197 }
    198 
    199 // Hit Testing
    200 bool RenderTableRow::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action)
    201 {
    202     // Table rows cannot ever be hit tested.  Effectively they do not exist.
    203     // Just forward to our children always.
    204     for (RenderTableCell* cell = lastCell(); cell; cell = cell->previousCell()) {
    205         // FIXME: We have to skip over inline flows, since they can show up inside table rows
    206         // at the moment (a demoted inline <form> for example). If we ever implement a
    207         // table-specific hit-test method (which we should do for performance reasons anyway),
    208         // then we can remove this check.
    209         if (!cell->hasSelfPaintingLayer()) {
    210             LayoutPoint cellPoint = flipForWritingModeForChild(cell, accumulatedOffset);
    211             if (cell->nodeAtPoint(request, result, locationInContainer, cellPoint, action)) {
    212                 updateHitTestResult(result, locationInContainer.point() - toLayoutSize(cellPoint));
    213                 return true;
    214             }
    215         }
    216     }
    217 
    218     return false;
    219 }
    220 
    221 void RenderTableRow::paintOutlineForRowIfNeeded(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
    222 {
    223     LayoutPoint adjustedPaintOffset = paintOffset + location();
    224     PaintPhase paintPhase = paintInfo.phase;
    225     if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseSelfOutline) && style()->visibility() == VISIBLE)
    226         paintOutline(paintInfo, LayoutRect(adjustedPaintOffset, size()));
    227 }
    228 
    229 void RenderTableRow::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
    230 {
    231     ASSERT(hasSelfPaintingLayer());
    232     ANNOTATE_GRAPHICS_CONTEXT(paintInfo, this);
    233 
    234     paintOutlineForRowIfNeeded(paintInfo, paintOffset);
    235     for (RenderTableCell* cell = firstCell(); cell; cell = cell->nextCell()) {
    236         // Paint the row background behind the cell.
    237         if (paintInfo.phase == PaintPhaseBlockBackground || paintInfo.phase == PaintPhaseChildBlockBackground)
    238             cell->paintBackgroundsBehindCell(paintInfo, paintOffset, this);
    239         if (!cell->hasSelfPaintingLayer())
    240             cell->paint(paintInfo, paintOffset);
    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     paintInvalidationForWholeRenderer();
    248 }
    249 
    250 RenderTableRow* RenderTableRow::createAnonymous(Document* document)
    251 {
    252     RenderTableRow* renderer = new RenderTableRow(0);
    253     renderer->setDocumentForAnonymous(document);
    254     return renderer;
    255 }
    256 
    257 RenderTableRow* RenderTableRow::createAnonymousWithParentRenderer(const RenderObject* parent)
    258 {
    259     RenderTableRow* newRow = RenderTableRow::createAnonymous(&parent->document());
    260     RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(parent->style(), TABLE_ROW);
    261     newRow->setStyle(newStyle.release());
    262     return newRow;
    263 }
    264 
    265 } // namespace WebCore
    266