| Index: Source/core/frame/FrameView.cpp
 | 
| diff --git a/Source/core/frame/FrameView.cpp b/Source/core/frame/FrameView.cpp
 | 
| index 5d42bdac25b2d6c954d44fa2973ecd91db2e3f19..d6f1a05b7b738ee62b0e63bc18d6ee8fd178878a 100644
 | 
| --- a/Source/core/frame/FrameView.cpp
 | 
| +++ b/Source/core/frame/FrameView.cpp
 | 
| @@ -1224,12 +1224,18 @@ void FrameView::scrollContentsIfNeededRecursive()
 | 
|      }
 | 
|  }
 | 
|  
 | 
| -void FrameView::scrollContentsIfNeeded()
 | 
| +// FIXME: If we had a flag to force invalidations in a whole subtree, we could get rid of this function (crbug.com/410097).
 | 
| +static void setShouldDoFullPaintInvalidationIncludingNonCompositingDescendants(const RenderLayer* layer)
 | 
|  {
 | 
| -    bool didScroll = !pendingScrollDelta().isZero();
 | 
| -    ScrollView::scrollContentsIfNeeded();
 | 
| -    if (didScroll)
 | 
| -        updateFixedElementPaintInvalidationRectsAfterScroll();
 | 
| +    layer->renderer()->setShouldDoFullPaintInvalidation(true);
 | 
| +
 | 
| +    for (RenderLayer* child = layer->firstChild(); child; child = child->nextSibling()) {
 | 
| +        // Don't include paint invalidation rects for composited child layers; they will paint themselves and have a different origin.
 | 
| +        if (child->isPaintInvalidationContainer())
 | 
| +            continue;
 | 
| +
 | 
| +        setShouldDoFullPaintInvalidationIncludingNonCompositingDescendants(child);
 | 
| +    }
 | 
|  }
 | 
|  
 | 
|  bool FrameView::scrollContentsFastPath(const IntSize& scrollDelta)
 | 
| @@ -1242,7 +1248,6 @@ bool FrameView::scrollContentsFastPath(const IntSize& scrollDelta)
 | 
|          return true;
 | 
|      }
 | 
|  
 | 
| -    Region regionToUpdate;
 | 
|      ViewportConstrainedObjectSet::const_iterator end = m_viewportConstrainedObjects->end();
 | 
|      for (ViewportConstrainedObjectSet::const_iterator it = m_viewportConstrainedObjects->begin(); it != end; ++it) {
 | 
|          RenderObject* renderer = *it;
 | 
| @@ -1250,8 +1255,7 @@ bool FrameView::scrollContentsFastPath(const IntSize& scrollDelta)
 | 
|          ASSERT(renderer->hasLayer());
 | 
|          RenderLayer* layer = toRenderBoxModelObject(renderer)->layer();
 | 
|  
 | 
| -        CompositingState state = layer->compositingState();
 | 
| -        if (state == PaintsIntoOwnBacking || state == PaintsIntoGroupedBacking)
 | 
| +        if (layer->isPaintInvalidationContainer())
 | 
|              continue;
 | 
|  
 | 
|          if (layer->subtreeIsInvisible())
 | 
| @@ -1262,39 +1266,10 @@ bool FrameView::scrollContentsFastPath(const IntSize& scrollDelta)
 | 
|          if (layer->hasAncestorWithFilterOutsets())
 | 
|              return false;
 | 
|  
 | 
| -        IntRect updateRect = pixelSnappedIntRect(layer->paintInvalidator().paintInvalidationRectIncludingNonCompositingDescendants());
 | 
| -
 | 
| -        const RenderLayerModelObject* repaintContainer = layer->renderer()->containerForPaintInvalidation();
 | 
| -        if (repaintContainer && !repaintContainer->isRenderView()) {
 | 
| -            // Invalidate the old and new locations of fixed position elements that are not drawn into the RenderView.
 | 
| -            updateRect.moveBy(scrollPosition());
 | 
| -            IntRect previousRect = updateRect;
 | 
| -            previousRect.move(scrollDelta);
 | 
| -            // FIXME: Rather than uniting the rects, we should just issue both invalidations.
 | 
| -            updateRect.unite(previousRect);
 | 
| -            layer->renderer()->invalidatePaintUsingContainer(repaintContainer, updateRect, InvalidationScroll);
 | 
| -        } else {
 | 
| -            // Coalesce the paint invalidations that will be issued to the renderView.
 | 
| -            updateRect = contentsToRootView(updateRect);
 | 
| -            if (!updateRect.isEmpty())
 | 
| -                regionToUpdate.unite(updateRect);
 | 
| -        }
 | 
| +        setShouldDoFullPaintInvalidationIncludingNonCompositingDescendants(layer);
 | 
|      }
 | 
|  
 | 
|      InspectorInstrumentation::didScroll(page());
 | 
| -
 | 
| -    // Invalidate the old and new locations of fixed position elements that are drawn into the RenderView.
 | 
| -    Vector<IntRect> subRectsToUpdate = regionToUpdate.rects();
 | 
| -    size_t viewportConstrainedObjectsCount = subRectsToUpdate.size();
 | 
| -    for (size_t i = 0; i < viewportConstrainedObjectsCount; ++i) {
 | 
| -        IntRect updateRect = subRectsToUpdate[i];
 | 
| -        IntRect scrolledRect = updateRect;
 | 
| -        scrolledRect.move(-scrollDelta);
 | 
| -        updateRect.unite(scrolledRect);
 | 
| -        // FIXME: We should be able to issue these invalidations separately and before we actually scroll.
 | 
| -        renderView()->layer()->paintInvalidator().setBackingNeedsPaintInvalidationInRect(rootViewToContents(updateRect));
 | 
| -    }
 | 
| -
 | 
|      return true;
 | 
|  }
 | 
|  
 | 
| @@ -1524,32 +1499,6 @@ void FrameView::updateLayersAndCompositingAfterScrollIfNeeded()
 | 
|      }
 | 
|  }
 | 
|  
 | 
| -void FrameView::updateFixedElementPaintInvalidationRectsAfterScroll()
 | 
| -{
 | 
| -    if (!hasViewportConstrainedObjects())
 | 
| -        return;
 | 
| -
 | 
| -    // Update the paint invalidation rects for fixed elements after scrolling and invalidation to reflect
 | 
| -    // the new scroll position.
 | 
| -    ViewportConstrainedObjectSet::const_iterator end = m_viewportConstrainedObjects->end();
 | 
| -    for (ViewportConstrainedObjectSet::const_iterator it = m_viewportConstrainedObjects->begin(); it != end; ++it) {
 | 
| -        RenderObject* renderer = *it;
 | 
| -        // m_viewportConstrainedObjects should not contain non-viewport constrained objects.
 | 
| -        ASSERT(renderer->style()->hasViewportConstrainedPosition());
 | 
| -
 | 
| -        // Fixed items should always have layers.
 | 
| -        ASSERT(renderer->hasLayer());
 | 
| -
 | 
| -        RenderLayer* layer = toRenderBoxModelObject(renderer)->layer();
 | 
| -
 | 
| -        // Don't need to do this for composited fixed items.
 | 
| -        if (layer->compositingState() == PaintsIntoOwnBacking)
 | 
| -            continue;
 | 
| -
 | 
| -        layer->paintInvalidator().computePaintInvalidationRectsIncludingNonCompositingDescendants();
 | 
| -    }
 | 
| -}
 | 
| -
 | 
|  void FrameView::updateCompositedSelectionBoundsIfNeeded()
 | 
|  {
 | 
|      if (!RuntimeEnabledFeatures::compositedSelectionUpdatesEnabled())
 | 
| @@ -2543,7 +2492,8 @@ void FrameView::updateLayoutAndStyleForPainting()
 | 
|  
 | 
|      updateWidgetPositionsIfNeeded();
 | 
|  
 | 
| -    if (RenderView* view = renderView()) {
 | 
| +    RenderView* view = renderView();
 | 
| +    if (view) {
 | 
|          TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "UpdateLayerTree", "frame", m_frame.get());
 | 
|          // FIXME(361045): remove InspectorInstrumentation calls once DevTools Timeline migrates to tracing.
 | 
|          InspectorInstrumentation::willUpdateLayerTree(m_frame.get());
 | 
| @@ -2556,11 +2506,13 @@ void FrameView::updateLayoutAndStyleForPainting()
 | 
|          updateCompositedSelectionBoundsIfNeeded();
 | 
|  
 | 
|          InspectorInstrumentation::didUpdateLayerTree(m_frame.get());
 | 
| -
 | 
| -        invalidateTreeIfNeededRecursive();
 | 
|      }
 | 
|  
 | 
|      scrollContentsIfNeededRecursive();
 | 
| +
 | 
| +    if (view)
 | 
| +        invalidateTreeIfNeededRecursive();
 | 
| +
 | 
|      ASSERT(lifecycle().state() == DocumentLifecycle::PaintInvalidationClean);
 | 
|  }
 | 
|  
 | 
| 
 |