diff --git a/LayoutTests/fast/repaint/invalidate-paint-for-fixed-pos-inside-iframe-expected.txt b/LayoutTests/fast/repaint/invalidate-paint-for-fixed-pos-inside-iframe-expected.txt new file mode 100644 index 00000000000..9e173047fea --- /dev/null +++ b/LayoutTests/fast/repaint/invalidate-paint-for-fixed-pos-inside-iframe-expected.txt @@ -0,0 +1,14 @@ +{ + "bounds": [800, 600], + "children": [ + { + "bounds": [800, 600], + "contentsOpaque": true, + "drawsContent": true, + "repaintRects": [ + [18, 418, 50, 50] + ] + } + ] +} + diff --git a/LayoutTests/fast/repaint/invalidate-paint-for-fixed-pos-inside-iframe.html b/LayoutTests/fast/repaint/invalidate-paint-for-fixed-pos-inside-iframe.html new file mode 100644 index 00000000000..9b53f96ec1a --- /dev/null +++ b/LayoutTests/fast/repaint/invalidate-paint-for-fixed-pos-inside-iframe.html @@ -0,0 +1,21 @@ + + + + + + + +
+ diff --git a/LayoutTests/fast/repaint/invalidate-paint-in-iframe-in-composited-layer-expected.txt b/LayoutTests/fast/repaint/invalidate-paint-in-iframe-in-composited-layer-expected.txt new file mode 100644 index 00000000000..e0b97835b53 --- /dev/null +++ b/LayoutTests/fast/repaint/invalidate-paint-in-iframe-in-composited-layer-expected.txt @@ -0,0 +1,22 @@ +{ + "bounds": [785, 616], + "children": [ + { + "bounds": [785, 616], + "contentsOpaque": true, + "drawsContent": true, + "children": [ + { + "position": [8, 408], + "transformOrigin": [100, 100], + "bounds": [304, 200], + "drawsContent": true, + "repaintRects": [ + [10, 10, 50, 50] + ] + } + ] + } + ] +} + diff --git a/LayoutTests/fast/repaint/invalidate-paint-in-iframe-in-composited-layer.html b/LayoutTests/fast/repaint/invalidate-paint-in-iframe-in-composited-layer.html new file mode 100644 index 00000000000..3f07dff91d6 --- /dev/null +++ b/LayoutTests/fast/repaint/invalidate-paint-in-iframe-in-composited-layer.html @@ -0,0 +1,23 @@ + + + + + + + +
+
+ +
diff --git a/LayoutTests/fast/repaint/repaint-in-iframe-expected.txt b/LayoutTests/fast/repaint/repaint-in-iframe-expected.txt index e40490720ef..9e173047fea 100644 --- a/LayoutTests/fast/repaint/repaint-in-iframe-expected.txt +++ b/LayoutTests/fast/repaint/repaint-in-iframe-expected.txt @@ -6,7 +6,7 @@ "contentsOpaque": true, "drawsContent": true, "repaintRects": [ - [18, 418, 284, 50] + [18, 418, 50, 50] ] } ] diff --git a/LayoutTests/fast/repaint/repaint-in-iframe.html b/LayoutTests/fast/repaint/repaint-in-iframe.html index 9141495ff16..0cc28dceac9 100644 --- a/LayoutTests/fast/repaint/repaint-in-iframe.html +++ b/LayoutTests/fast/repaint/repaint-in-iframe.html @@ -18,4 +18,4 @@
- + diff --git a/Source/core/frame/FrameView.cpp b/Source/core/frame/FrameView.cpp index 05659b0f631..6d6e8ef1c20 100644 --- a/Source/core/frame/FrameView.cpp +++ b/Source/core/frame/FrameView.cpp @@ -965,14 +965,14 @@ void FrameView::layout(bool allowSubtree) // See http://crbug.com/306706 void FrameView::invalidateTreeIfNeeded() { - RenderObject* rootForPaintInvalidation = renderView(); - ASSERT(!rootForPaintInvalidation->needsLayout()); + RenderView& rootForPaintInvalidation = *renderView(); + ASSERT(!rootForPaintInvalidation.needsLayout()); - TRACE_EVENT1("blink", "FrameView::invalidateTree", "root", rootForPaintInvalidation->debugName().ascii()); + TRACE_EVENT1("blink", "FrameView::invalidateTree", "root", rootForPaintInvalidation.debugName().ascii()); - PaintInvalidationState rootPaintInvalidationState(*rootForPaintInvalidation); + PaintInvalidationState rootPaintInvalidationState(rootForPaintInvalidation); - rootForPaintInvalidation->invalidateTreeIfNeeded(rootPaintInvalidationState); + rootForPaintInvalidation.invalidateTreeIfNeeded(rootPaintInvalidationState); // Invalidate the paint of the frameviews scrollbars if needed if (hasVerticalBarDamage()) @@ -1604,7 +1604,7 @@ HostWindow* FrameView::hostWindow() const void FrameView::contentRectangleForPaintInvalidation(const IntRect& r) { ASSERT(paintInvalidationIsAllowed()); - ASSERT(!m_frame->owner()); + ASSERT(!m_frame->ownerRenderer()); if (m_isTrackingPaintInvalidations) { IntRect paintInvalidationRect = r; diff --git a/Source/core/rendering/PaintInvalidationState.cpp b/Source/core/rendering/PaintInvalidationState.cpp index 12753da0aa2..c5287961dc8 100644 --- a/Source/core/rendering/PaintInvalidationState.cpp +++ b/Source/core/rendering/PaintInvalidationState.cpp @@ -13,32 +13,25 @@ namespace blink { -PaintInvalidationState::PaintInvalidationState(RenderObject& renderer) +PaintInvalidationState::PaintInvalidationState(const RenderView& renderView) : m_clipped(false) , m_cachedOffsetsEnabled(true) , m_forceCheckForPaintInvalidation(false) - , m_paintInvalidationContainer(*renderer.containerForPaintInvalidation()) - , m_renderer(renderer) + , m_paintInvalidationContainer(*renderView.containerForPaintInvalidation()) + , m_renderer(renderView) { bool establishesPaintInvalidationContainer = &m_renderer == &m_paintInvalidationContainer; if (!establishesPaintInvalidationContainer) { - if (!renderer.supportsPaintInvalidationStateCachedOffsets()) { + if (!renderView.supportsPaintInvalidationStateCachedOffsets()) { m_cachedOffsetsEnabled = false; return; } - bool invalidationContainerSkipped; - RenderObject* container = renderer.container(&m_paintInvalidationContainer, &invalidationContainerSkipped); - if (container && !invalidationContainerSkipped) { - FloatPoint point = container->localToContainerPoint(FloatPoint(), &m_paintInvalidationContainer); - if (container->isTableRow()) - point = FloatPoint(point.x() - toRenderBox(container)->x().toFloat(), point.y() - toRenderBox(container)->y().toFloat()); - m_paintOffset = LayoutSize(point.x(), point.y()); - - applyClipIfNeeded(*container); - } - } else { - applyClipIfNeeded(m_renderer); + FloatPoint point = renderView.localToContainerPoint(FloatPoint(), &m_paintInvalidationContainer, TraverseDocumentBoundaries); + m_paintOffset = LayoutSize(point.x(), point.y()); } + m_clipRect = renderView.viewRect(); + m_clipRect.move(m_paintOffset); + m_clipped = true; } PaintInvalidationState::PaintInvalidationState(const PaintInvalidationState& next, RenderLayerModelObject& renderer, const RenderLayerModelObject& paintInvalidationContainer) @@ -50,7 +43,7 @@ PaintInvalidationState::PaintInvalidationState(const PaintInvalidationState& nex { // FIXME: SVG could probably benefit from a stack-based optimization like html does. crbug.com/391054 bool establishesPaintInvalidationContainer = &m_renderer == &m_paintInvalidationContainer; - bool fixed = m_renderer.isOutOfFlowPositioned() && m_renderer.style()->position() == FixedPosition; + bool fixed = m_renderer.style()->position() == FixedPosition; if (establishesPaintInvalidationContainer) { // When we hit a new paint invalidation container, we don't need to @@ -61,12 +54,11 @@ PaintInvalidationState::PaintInvalidationState(const PaintInvalidationState& nex if (!renderer.supportsPaintInvalidationStateCachedOffsets() || !next.m_cachedOffsetsEnabled) { m_cachedOffsetsEnabled = false; } else { - LayoutSize offset = m_renderer.isBox() && !m_renderer.isTableRow() ? toRenderBox(renderer).locationOffset() : LayoutSize(); if (fixed) { - // FIXME: This doesn't work correctly with transforms. - FloatPoint fixedOffset = m_renderer.view()->localToAbsolute(FloatPoint(), IsFixed); - m_paintOffset = LayoutSize(fixedOffset.x(), fixedOffset.y()) + offset; + FloatPoint fixedOffset = m_renderer.localToContainerPoint(FloatPoint(), &m_paintInvalidationContainer, TraverseDocumentBoundaries); + m_paintOffset = LayoutSize(fixedOffset.x(), fixedOffset.y()); } else { + LayoutSize offset = m_renderer.isBox() && !m_renderer.isTableRow() ? toRenderBox(renderer).locationOffset() : LayoutSize(); m_paintOffset = next.m_paintOffset + offset; } diff --git a/Source/core/rendering/PaintInvalidationState.h b/Source/core/rendering/PaintInvalidationState.h index 8f0765857de..d7dcd2ec013 100644 --- a/Source/core/rendering/PaintInvalidationState.h +++ b/Source/core/rendering/PaintInvalidationState.h @@ -14,6 +14,7 @@ class RenderBox; class RenderInline; class RenderLayerModelObject; class RenderObject; +class RenderView; class RenderSVGModelObject; class PaintInvalidationState { @@ -21,7 +22,7 @@ class PaintInvalidationState { public: PaintInvalidationState(const PaintInvalidationState& next, RenderLayerModelObject& renderer, const RenderLayerModelObject& paintInvalidationContainer); - explicit PaintInvalidationState(RenderObject&); + explicit PaintInvalidationState(const RenderView&); const LayoutRect& clipRect() const { return m_clipRect; } const LayoutSize& paintOffset() const { return m_paintOffset; } @@ -33,7 +34,7 @@ class PaintInvalidationState { void setForceCheckForPaintInvalidation() { m_forceCheckForPaintInvalidation = true; } const RenderLayerModelObject& paintInvalidationContainer() const { return m_paintInvalidationContainer; } - RenderObject& renderer() const { return m_renderer; } + const RenderObject& renderer() const { return m_renderer; } bool canMapToContainer(const RenderLayerModelObject* container) const { @@ -55,7 +56,7 @@ class PaintInvalidationState { const RenderLayerModelObject& m_paintInvalidationContainer; - RenderObject& m_renderer; + const RenderObject& m_renderer; }; } // namespace blink diff --git a/Source/core/rendering/RenderLayerRepainter.cpp b/Source/core/rendering/RenderLayerRepainter.cpp index 29e712e8e91..62336f56365 100644 --- a/Source/core/rendering/RenderLayerRepainter.cpp +++ b/Source/core/rendering/RenderLayerRepainter.cpp @@ -110,23 +110,7 @@ void RenderLayerRepainter::setBackingNeedsPaintInvalidationInRect(const LayoutRe // https://bugs.webkit.org/show_bug.cgi?id=61159 describes an unreproducible crash here, // so assert but check that the layer is composited. ASSERT(m_renderer.compositingState() != NotComposited); - if (m_renderer.compositingState() == NotComposited) { - // If we're trying to issue paint invalidations of the placeholder document layer, propagate the - // paint invalidation to the native view system. - LayoutRect absRect(r); - LayoutPoint delta; - m_renderer.layer()->convertToLayerCoords(m_renderer.layer()->root(), delta); - absRect.moveBy(delta); - - if (absRect.isEmpty()) - return; - - RenderView* view = m_renderer.view(); - if (view) - view->invalidatePaintForRectangle(absRect); - return; - } - // FIXME: generalize accessors to backing GraphicsLayers so that this code is squasphing-agnostic. + // FIXME: generalize accessors to backing GraphicsLayers so that this code is squashing-agnostic. if (m_renderer.layer()->groupedMapping()) { LayoutRect paintInvalidationRect = r; paintInvalidationRect.move(m_renderer.layer()->subpixelAccumulation()); diff --git a/Source/core/rendering/RenderObject.cpp b/Source/core/rendering/RenderObject.cpp index c976c3aee3d..0186feb8cbc 100644 --- a/Source/core/rendering/RenderObject.cpp +++ b/Source/core/rendering/RenderObject.cpp @@ -66,6 +66,7 @@ #include "core/rendering/RenderListItem.h" #include "core/rendering/RenderMarquee.h" #include "core/rendering/RenderObjectInlines.h" +#include "core/rendering/RenderPart.h" #include "core/rendering/RenderScrollbarPart.h" #include "core/rendering/RenderTableCaption.h" #include "core/rendering/RenderTableCell.h" @@ -1445,13 +1446,11 @@ const RenderLayerModelObject* RenderObject::containerForPaintInvalidation() cons const RenderLayerModelObject* RenderObject::enclosingCompositedContainer() const { RenderLayerModelObject* container = 0; - if (view()->usesCompositing()) { - // FIXME: CompositingState is not necessarily up to date for many callers of this function. - DisableCompositingQueryAsserts disabler; + // FIXME: CompositingState is not necessarily up to date for many callers of this function. + DisableCompositingQueryAsserts disabler; - if (RenderLayer* compositingLayer = enclosingLayer()->enclosingLayerForPaintInvalidation()) - container = compositingLayer->renderer(); - } + if (RenderLayer* compositingLayer = enclosingLayer()->enclosingLayerForPaintInvalidationCrossingFrameBoundaries()) + container = compositingLayer->renderer(); return container; } @@ -1466,7 +1465,14 @@ const RenderLayerModelObject* RenderObject::adjustCompositedContainerForSpecialA if (!paintInvalidationContainer || paintInvalidationContainer->flowThreadContainingBlock() != parentRenderFlowThread) paintInvalidationContainer = parentRenderFlowThread; } - return paintInvalidationContainer ? paintInvalidationContainer : view(); + + if (paintInvalidationContainer) + return paintInvalidationContainer; + + RenderView* renderView = view(); + while (renderView->frame()->ownerRenderer()) + renderView = renderView->frame()->ownerRenderer()->view(); + return renderView; } bool RenderObject::isPaintInvalidationContainer() const @@ -1525,14 +1531,11 @@ void RenderObject::invalidatePaintUsingContainer(const RenderLayerModelObject* p return; } - RenderView* v = view(); if (paintInvalidationContainer->isRenderView()) { - ASSERT(paintInvalidationContainer == v); - v->invalidatePaintForRectangle(r); + toRenderView(paintInvalidationContainer)->invalidatePaintForRectangle(r); return; } - - if (v->usesCompositing()) { + if (paintInvalidationContainer->view()->usesCompositing()) { ASSERT(paintInvalidationContainer->hasLayer() && (paintInvalidationContainer->layer()->compositingState() == PaintsIntoOwnBacking || paintInvalidationContainer->layer()->compositingState() == PaintsIntoGroupedBacking)); paintInvalidationContainer->layer()->paintInvalidator().setBackingNeedsPaintInvalidationInRect(r); } @@ -1763,6 +1766,11 @@ LayoutRect RenderObject::rectWithOutlineForPaintInvalidation(const RenderLayerMo return r; } +LayoutRect RenderObject::absoluteClippedOverflowRect() const +{ + return clippedOverflowRectForPaintInvalidation(view()); +} + LayoutRect RenderObject::clippedOverflowRectForPaintInvalidation(const RenderLayerModelObject*, const PaintInvalidationState*) const { ASSERT_NOT_REACHED(); diff --git a/Source/core/rendering/RenderObject.h b/Source/core/rendering/RenderObject.h index 6759aed9f69..61543211182 100644 --- a/Source/core/rendering/RenderObject.h +++ b/Source/core/rendering/RenderObject.h @@ -890,10 +890,7 @@ class RenderObject : public NoBaseWillBeGarbageCollectedFinalized, // Returns the rect that should have paint invalidated whenever this object changes. The rect is in the view's // coordinate space. This method deals with outlines and overflow. - LayoutRect absoluteClippedOverflowRect() const - { - return clippedOverflowRectForPaintInvalidation(0); - } + LayoutRect absoluteClippedOverflowRect() const; IntRect pixelSnappedAbsoluteClippedOverflowRect() const; virtual LayoutRect clippedOverflowRectForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer, const PaintInvalidationState* = 0) const; virtual LayoutRect rectWithOutlineForPaintInvalidation(const RenderLayerModelObject* paintInvalidationContainer, LayoutUnit outlineWidth, const PaintInvalidationState* = 0) const; diff --git a/Source/core/rendering/RenderView.cpp b/Source/core/rendering/RenderView.cpp index 36d94d166d7..8e8549ff5f0 100644 --- a/Source/core/rendering/RenderView.cpp +++ b/Source/core/rendering/RenderView.cpp @@ -294,10 +294,6 @@ void RenderView::mapLocalToContainer(const RenderLayerModelObject* paintInvalida return; } } - - // If a container was specified, and was not 0 or the RenderView, - // then we should have found it by now. - ASSERT_ARG(paintInvalidationContainer, !paintInvalidationContainer); } const RenderObject* RenderView::pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap& geometryMap) const @@ -438,9 +434,12 @@ void RenderView::invalidateTreeIfNeeded(const PaintInvalidationState& paintInval // We specifically need to issue paint invalidations for the viewRect since other renderers // short-circuit on full-paint invalidation. - if (doingFullPaintInvalidation() && !viewRect().isEmpty()) - invalidatePaintForRectangle(viewRect()); - + LayoutRect dirtyRect = viewRect(); + if (doingFullPaintInvalidation() && !dirtyRect.isEmpty()) { + const RenderLayerModelObject* paintInvalidationContainer = &paintInvalidationState.paintInvalidationContainer(); + mapRectToPaintInvalidationBacking(paintInvalidationContainer, dirtyRect, IsNotFixedPosition, &paintInvalidationState); + invalidatePaintUsingContainer(paintInvalidationContainer, dirtyRect, InvalidationFull); + } RenderBlock::invalidateTreeIfNeeded(paintInvalidationState); } @@ -451,24 +450,12 @@ void RenderView::invalidatePaintForRectangle(const LayoutRect& paintInvalidation if (document().printing() || !m_frameView) return; - // We always just invalidate the root view, since we could be an iframe that is clipped out - // or even invisible. - HTMLFrameOwnerElement* owner = document().ownerElement(); + ASSERT(layer()->compositingState() == PaintsIntoOwnBacking || !frame()->ownerRenderer()); + if (layer()->compositingState() == PaintsIntoOwnBacking) { layer()->paintInvalidator().setBackingNeedsPaintInvalidationInRect(paintInvalidationRect); - } else if (!owner) { + } else { m_frameView->contentRectangleForPaintInvalidation(pixelSnappedIntRect(paintInvalidationRect)); - } else if (RenderBox* obj = owner->renderBox()) { - // Intersect the viewport with the paint invalidation rect. - LayoutRect viewRectangle = viewRect(); - LayoutRect rectToInvalidate = intersection(paintInvalidationRect, viewRectangle); - - // Adjust for scroll offset of the view. - rectToInvalidate.moveBy(-viewRectangle.location()); - - // Adjust for frame border. - rectToInvalidate.moveBy(obj->contentBoxRect().location()); - obj->invalidatePaintRectangle(rectToInvalidate); } } @@ -483,12 +470,8 @@ void RenderView::invalidatePaintForViewAndCompositedLayers() compositor()->fullyInvalidatePaint(); } -void RenderView::mapRectToPaintInvalidationBacking(const RenderLayerModelObject* paintInvalidationContainer, LayoutRect& rect, ViewportConstrainedPosition viewportConstraint, const PaintInvalidationState*) const +void RenderView::mapRectToPaintInvalidationBacking(const RenderLayerModelObject* paintInvalidationContainer, LayoutRect& rect, ViewportConstrainedPosition viewportConstraint, const PaintInvalidationState* state) const { - // If a container was specified, and was not 0 or the RenderView, - // then we should have found it by now. - ASSERT_ARG(paintInvalidationContainer, !paintInvalidationContainer || paintInvalidationContainer == this); - if (document().printing()) return; @@ -513,8 +496,30 @@ void RenderView::mapRectToPaintInvalidationBacking(const RenderLayerModelObject* // Apply our transform if we have one (because of full page zooming). if (!paintInvalidationContainer && layer() && layer()->transform()) rect = layer()->transform()->mapRect(rect); + + ASSERT(paintInvalidationContainer); + if (paintInvalidationContainer == this) + return; + + Element* owner = document().ownerElement(); + if (!owner) + return; + + if (RenderBox* obj = owner->renderBox()) { + // Intersect the viewport with the paint invalidation rect. + LayoutRect viewRectangle = viewRect(); + rect.intersect(viewRectangle); + + // Adjust for scroll offset of the view. + rect.moveBy(-viewRectangle.location()); + + // Adjust for frame border. + rect.moveBy(obj->contentBoxRect().location()); + obj->mapRectToPaintInvalidationBacking(paintInvalidationContainer, rect, IsNotFixedPosition, 0); + } } + void RenderView::absoluteRects(Vector& rects, const LayoutPoint& accumulatedOffset) const { rects.append(pixelSnappedIntRect(accumulatedOffset, layer()->size())); diff --git a/Source/core/rendering/RenderView.h b/Source/core/rendering/RenderView.h index 352a73d43b0..00ddd9ca4c1 100644 --- a/Source/core/rendering/RenderView.h +++ b/Source/core/rendering/RenderView.h @@ -156,6 +156,7 @@ class RenderView FINAL : public RenderBlockFlow { void pushLayoutState(LayoutState&); void popLayoutState(); + virtual void invalidateTreeIfNeeded(const PaintInvalidationState&) OVERRIDE FINAL; private: virtual void mapLocalToContainer(const RenderLayerModelObject* paintInvalidationContainer, TransformState&, MapCoordinatesFlags = ApplyContainerFlip, bool* wasFixed = 0, const PaintInvalidationState* = 0) const OVERRIDE; @@ -163,7 +164,6 @@ class RenderView FINAL : public RenderBlockFlow { virtual void mapAbsoluteToLocalPoint(MapCoordinatesFlags, TransformState&) const OVERRIDE; virtual void computeSelfHitTestRects(Vector&, const LayoutPoint& layerOffset) const OVERRIDE; - virtual void invalidateTreeIfNeeded(const PaintInvalidationState&) OVERRIDE FINAL; bool shouldInvalidatePaint(const LayoutRect&) const;