1 /* 2 * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All rights reserved. 3 * 4 * Portions are Copyright (C) 1998 Netscape Communications Corporation. 5 * 6 * Other contributors: 7 * Robert O'Callahan <roc+@cs.cmu.edu> 8 * David Baron <dbaron (at) fas.harvard.edu> 9 * Christian Biesinger <cbiesinger (at) web.de> 10 * Randall Jesup <rjesup (at) wgate.com> 11 * Roland Mainz <roland.mainz (at) informatik.med.uni-giessen.de> 12 * Josh Soref <timeless (at) mac.com> 13 * Boris Zbarsky <bzbarsky (at) mit.edu> 14 * 15 * This library is free software; you can redistribute it and/or 16 * modify it under the terms of the GNU Lesser General Public 17 * License as published by the Free Software Foundation; either 18 * version 2.1 of the License, or (at your option) any later version. 19 * 20 * This library is distributed in the hope that it will be useful, 21 * but WITHOUT ANY WARRANTY; without even the implied warranty of 22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 23 * Lesser General Public License for more details. 24 * 25 * You should have received a copy of the GNU Lesser General Public 26 * License along with this library; if not, write to the Free Software 27 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 28 * 29 * Alternatively, the contents of this file may be used under the terms 30 * of either the Mozilla Public License Version 1.1, found at 31 * http://www.mozilla.org/MPL/ (the "MPL") or the GNU General Public 32 * License Version 2.0, found at http://www.fsf.org/copyleft/gpl.html 33 * (the "GPL"), in which case the provisions of the MPL or the GPL are 34 * applicable instead of those above. If you wish to allow use of your 35 * version of this file only under the terms of one of those two 36 * licenses (the MPL or the GPL) and not to allow others to use your 37 * version of this file under the LGPL, indicate your decision by 38 * deletingthe provisions above and replace them with the notice and 39 * other provisions required by the MPL or the GPL, as the case may be. 40 * If you do not delete the provisions above, a recipient may use your 41 * version of this file under any of the LGPL, the MPL or the GPL. 42 */ 43 44 #include "config.h" 45 #include "core/rendering/RenderLayerRepainter.h" 46 47 #include "core/rendering/CompositedLayerMapping.h" 48 #include "core/rendering/FilterEffectRenderer.h" 49 #include "core/rendering/RenderLayer.h" 50 #include "core/rendering/RenderView.h" 51 52 namespace WebCore { 53 54 RenderLayerRepainter::RenderLayerRepainter(RenderLayerModelObject* renderer) 55 : m_renderer(renderer) 56 , m_repaintStatus(NeedsNormalRepaint) 57 { 58 } 59 60 void RenderLayerRepainter::repaintAfterLayout(RenderGeometryMap* geometryMap, bool shouldCheckForRepaint) 61 { 62 if (m_renderer->layer()->hasVisibleContent()) { 63 RenderView* view = m_renderer->view(); 64 ASSERT(view); 65 // FIXME: LayoutState does not work with RenderLayers as there is not a 1-to-1 66 // mapping between them and the RenderObjects. It would be neat to enable 67 // LayoutState outside the layout() phase and use it here. 68 ASSERT(!view->layoutStateEnabled()); 69 70 RenderLayerModelObject* repaintContainer = m_renderer->containerForRepaint(); 71 LayoutRect oldRepaintRect = m_repaintRect; 72 LayoutRect oldOutlineBox = m_outlineBox; 73 computeRepaintRects(repaintContainer, geometryMap); 74 75 // FIXME: Should ASSERT that value calculated for m_outlineBox using the cached offset is the same 76 // as the value not using the cached offset, but we can't due to https://bugs.webkit.org/show_bug.cgi?id=37048 77 if (shouldCheckForRepaint) { 78 if (view && !view->document().printing()) { 79 if (m_repaintStatus & NeedsFullRepaint) { 80 m_renderer->repaintUsingContainer(repaintContainer, pixelSnappedIntRect(oldRepaintRect)); 81 if (m_repaintRect != oldRepaintRect) 82 m_renderer->repaintUsingContainer(repaintContainer, pixelSnappedIntRect(m_repaintRect)); 83 } else if (shouldRepaintAfterLayout()) { 84 m_renderer->repaintAfterLayoutIfNeeded(repaintContainer, m_renderer->selfNeedsLayout(), oldRepaintRect, oldOutlineBox, &m_repaintRect, &m_outlineBox); 85 } 86 } 87 } 88 } else { 89 clearRepaintRects(); 90 } 91 92 m_repaintStatus = NeedsNormalRepaint; 93 94 } 95 96 void RenderLayerRepainter::clearRepaintRects() 97 { 98 ASSERT(!m_renderer->layer()->hasVisibleContent()); 99 100 m_repaintRect = IntRect(); 101 m_outlineBox = IntRect(); 102 } 103 104 void RenderLayerRepainter::computeRepaintRects(const RenderLayerModelObject* repaintContainer, const RenderGeometryMap* geometryMap) 105 { 106 m_repaintRect = m_renderer->clippedOverflowRectForRepaint(repaintContainer); 107 m_outlineBox = m_renderer->outlineBoundsForRepaint(repaintContainer, geometryMap); 108 } 109 110 void RenderLayerRepainter::computeRepaintRectsIncludingDescendants() 111 { 112 // FIXME: computeRepaintRects() has to walk up the parent chain for every layer to compute the rects. 113 // We should make this more efficient. 114 // FIXME: it's wrong to call this when layout is not up-to-date, which we do. 115 computeRepaintRects(m_renderer->containerForRepaint()); 116 117 for (RenderLayer* layer = m_renderer->layer()->firstChild(); layer; layer = layer->nextSibling()) 118 layer->repainter().computeRepaintRectsIncludingDescendants(); 119 } 120 121 inline bool RenderLayerRepainter::shouldRepaintAfterLayout() const 122 { 123 if (m_repaintStatus == NeedsNormalRepaint) 124 return true; 125 126 // Composited layers that were moved during a positioned movement only 127 // layout, don't need to be repainted. They just need to be recomposited. 128 ASSERT(m_repaintStatus == NeedsFullRepaintForPositionedMovementLayout); 129 return m_renderer->compositingState() != PaintsIntoOwnBacking; 130 } 131 132 // Since we're only painting non-composited layers, we know that they all share the same repaintContainer. 133 void RenderLayerRepainter::repaintIncludingNonCompositingDescendants(RenderLayerModelObject* repaintContainer) 134 { 135 m_renderer->repaintUsingContainer(repaintContainer, pixelSnappedIntRect(m_renderer->clippedOverflowRectForRepaint(repaintContainer))); 136 137 for (RenderLayer* curr = m_renderer->layer()->firstChild(); curr; curr = curr->nextSibling()) { 138 if (!curr->hasCompositedLayerMapping()) 139 curr->repainter().repaintIncludingNonCompositingDescendants(repaintContainer); 140 } 141 } 142 143 LayoutRect RenderLayerRepainter::repaintRectIncludingNonCompositingDescendants() const 144 { 145 LayoutRect repaintRect = m_repaintRect; 146 for (RenderLayer* child = m_renderer->layer()->firstChild(); child; child = child->nextSibling()) { 147 // Don't include repaint rects for composited child layers; they will paint themselves and have a different origin. 148 if (child->hasCompositedLayerMapping()) 149 continue; 150 151 repaintRect.unite(child->repainter().repaintRectIncludingNonCompositingDescendants()); 152 } 153 return repaintRect; 154 } 155 156 void RenderLayerRepainter::setBackingNeedsRepaint() 157 { 158 ASSERT(m_renderer->compositingState() != NotComposited); 159 160 if (m_renderer->compositingState() == PaintsIntoGroupedBacking) { 161 // FIXME: should probably setNeedsDisplayInRect for this layer's bounds only. 162 m_renderer->groupedMapping()->squashingLayer()->setNeedsDisplay(); 163 } else { 164 m_renderer->compositedLayerMapping()->setContentsNeedDisplay(); 165 } 166 } 167 168 void RenderLayerRepainter::setBackingNeedsRepaintInRect(const LayoutRect& r) 169 { 170 // https://bugs.webkit.org/show_bug.cgi?id=61159 describes an unreproducible crash here, 171 // so assert but check that the layer is composited. 172 ASSERT(m_renderer->compositingState() != NotComposited); 173 if (m_renderer->compositingState() == NotComposited) { 174 // If we're trying to repaint the placeholder document layer, propagate the 175 // repaint to the native view system. 176 LayoutRect absRect(r); 177 LayoutPoint delta; 178 m_renderer->layer()->convertToLayerCoords(m_renderer->layer()->root(), delta); 179 absRect.moveBy(delta); 180 181 RenderView* view = m_renderer->view(); 182 if (view) 183 view->repaintViewRectangle(absRect); 184 } else { 185 if (m_renderer->compositingState() == PaintsIntoGroupedBacking) { 186 // FIXME: LayoutRect rounding to IntRect is probably not a good idea. 187 IntRect offsetRect = pixelSnappedIntRect(r); 188 if (m_renderer->hasTransform()) 189 offsetRect = m_renderer->layer()->transform()->mapRect(pixelSnappedIntRect(r)); 190 191 offsetRect.move(-m_renderer->layer()->offsetFromSquashingLayerOrigin()); 192 m_renderer->groupedMapping()->squashingLayer()->setNeedsDisplayInRect(offsetRect); 193 } else { 194 m_renderer->compositedLayerMapping()->setContentsNeedDisplayInRect(pixelSnappedIntRect(r)); 195 } 196 } 197 } 198 199 void RenderLayerRepainter::repaintIncludingDescendants() 200 { 201 m_renderer->repaint(); 202 for (RenderLayer* curr = m_renderer->layer()->firstChild(); curr; curr = curr->nextSibling()) 203 curr->repainter().repaintIncludingDescendants(); 204 } 205 206 void RenderLayerRepainter::setFilterBackendNeedsRepaintingInRect(const LayoutRect& rect) 207 { 208 if (rect.isEmpty()) 209 return; 210 211 LayoutRect rectForRepaint = rect; 212 m_renderer->style()->filterOutsets().expandRect(rectForRepaint); 213 214 RenderLayerFilterInfo* filterInfo = m_renderer->layer()->filterInfo(); 215 ASSERT(filterInfo); 216 filterInfo->expandDirtySourceRect(rectForRepaint); 217 218 ASSERT(filterInfo->renderer()); 219 if (filterInfo->renderer()->hasCustomShaderFilter()) { 220 // If we have at least one custom shader, we need to update the whole bounding box of the layer, because the 221 // shader can address any ouput pixel. 222 // Note: This is only for output rect, so there's no need to expand the dirty source rect. 223 rectForRepaint.unite(m_renderer->layer()->calculateLayerBounds(m_renderer->layer())); 224 } 225 226 RenderLayer* parentLayer = enclosingFilterRepaintLayer(); 227 ASSERT(parentLayer); 228 FloatQuad repaintQuad(rectForRepaint); 229 LayoutRect parentLayerRect = m_renderer->localToContainerQuad(repaintQuad, parentLayer->renderer()).enclosingBoundingBox(); 230 231 if (parentLayer->hasCompositedLayerMapping()) { 232 parentLayer->repainter().setBackingNeedsRepaintInRect(parentLayerRect); 233 return; 234 } 235 236 if (parentLayer->paintsWithFilters()) { 237 parentLayer->repainter().setFilterBackendNeedsRepaintingInRect(parentLayerRect); 238 return; 239 } 240 241 if (parentLayer->isRootLayer()) { 242 RenderView* view = toRenderView(parentLayer->renderer()); 243 view->repaintViewRectangle(parentLayerRect); 244 return; 245 } 246 247 ASSERT_NOT_REACHED(); 248 } 249 250 RenderLayer* RenderLayerRepainter::enclosingFilterRepaintLayer() const 251 { 252 for (const RenderLayer* curr = m_renderer->layer(); curr; curr = curr->parent()) { 253 if ((curr != m_renderer->layer() && curr->requiresFullLayerImageForFilters()) || curr->compositingState() == PaintsIntoOwnBacking || curr->isRootLayer()) 254 return const_cast<RenderLayer*>(curr); 255 } 256 return 0; 257 } 258 259 } // Namespace WebCore 260