Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / page / scrolling / ScrollingCoordinator.cpp
index ca72786..ec2352f 100644 (file)
 
 #include "RuntimeEnabledFeatures.h"
 #include "core/dom/Document.h"
+#include "core/dom/FullscreenElementStack.h"
 #include "core/dom/Node.h"
 #include "core/dom/WheelController.h"
-#include "core/html/HTMLElement.h"
-#include "core/frame/Frame.h"
+#include "core/frame/EventHandlerRegistry.h"
 #include "core/frame/FrameView.h"
+#include "core/frame/LocalFrame.h"
+#include "core/frame/Settings.h"
+#include "core/html/HTMLElement.h"
 #include "core/page/Page.h"
-#include "core/page/Settings.h"
-#include "core/platform/ScrollAnimator.h"
-#include "core/platform/ScrollbarTheme.h"
-#include "core/platform/chromium/support/WebScrollbarImpl.h"
-#include "core/platform/chromium/support/WebScrollbarThemeGeometryNative.h"
-#include "core/platform/graphics/GraphicsLayer.h"
+#include "core/plugins/PluginView.h"
+#include "core/rendering/RenderGeometryMap.h"
+#include "core/rendering/RenderView.h"
+#include "core/rendering/compositing/CompositedLayerMapping.h"
+#include "core/rendering/compositing/RenderLayerCompositor.h"
 #include "platform/TraceEvent.h"
+#include "platform/exported/WebScrollbarImpl.h"
+#include "platform/exported/WebScrollbarThemeGeometryNative.h"
 #include "platform/geometry/Region.h"
 #include "platform/geometry/TransformState.h"
+#include "platform/graphics/GraphicsLayer.h"
 #if OS(MACOSX)
-#include "core/platform/mac/ScrollAnimatorMac.h"
+#include "platform/mac/ScrollAnimatorMac.h"
 #endif
-#include "core/plugins/PluginView.h"
-#include "core/rendering/CompositedLayerMapping.h"
-#include "core/rendering/RenderGeometryMap.h"
-#include "core/rendering/RenderLayerCompositor.h"
-#include "core/rendering/RenderView.h"
-#include "platform/geometry/IntRect.h"
+#include "platform/scroll/ScrollAnimator.h"
+#include "platform/scroll/ScrollbarTheme.h"
 #include "public/platform/Platform.h"
 #include "public/platform/WebCompositorSupport.h"
 #include "public/platform/WebLayerPositionConstraint.h"
 #include "public/platform/WebScrollbarThemePainter.h"
 #include "wtf/text/StringBuilder.h"
 
-using WebKit::WebLayer;
-using WebKit::WebLayerPositionConstraint;
-using WebKit::WebRect;
-using WebKit::WebScrollbarLayer;
-using WebKit::WebVector;
+using blink::WebLayer;
+using blink::WebLayerPositionConstraint;
+using blink::WebRect;
+using blink::WebScrollbarLayer;
+using blink::WebVector;
 
+namespace {
 
-namespace WebCore {
-
-static WebLayer* scrollingWebLayerForGraphicsLayer(GraphicsLayer* layer)
+WebLayer* toWebLayer(WebCore::GraphicsLayer* layer)
 {
-    return layer->platformLayer();
+    return layer ? layer->platformLayer() : 0;
 }
 
-WebLayer* ScrollingCoordinator::scrollingWebLayerForScrollableArea(ScrollableArea* scrollableArea)
-{
-    GraphicsLayer* graphicsLayer = scrollLayerForScrollableArea(scrollableArea);
-    return graphicsLayer ? scrollingWebLayerForGraphicsLayer(graphicsLayer) : 0;
-}
+} // namespace
 
-PassRefPtr<ScrollingCoordinator> ScrollingCoordinator::create(Page* page)
+namespace WebCore {
+
+PassOwnPtr<ScrollingCoordinator> ScrollingCoordinator::create(Page* page)
 {
-    return adoptRef(new ScrollingCoordinator(page));
+    return adoptPtr(new ScrollingCoordinator(page));
 }
 
 ScrollingCoordinator::ScrollingCoordinator(Page* page)
     : m_page(page)
     , m_scrollGestureRegionIsDirty(false)
     , m_touchEventTargetRectsAreDirty(false)
+    , m_shouldScrollOnMainThreadDirty(false)
+    , m_wasFrameScrollable(false)
+    , m_lastMainThreadScrollingReasons(0)
 {
 }
 
 ScrollingCoordinator::~ScrollingCoordinator()
 {
-    ASSERT(!m_page);
-    for (ScrollbarMap::iterator it = m_horizontalScrollbars.begin(); it != m_horizontalScrollbars.end(); ++it)
-        GraphicsLayer::unregisterContentsLayer(it->value->layer());
-    for (ScrollbarMap::iterator it = m_verticalScrollbars.begin(); it != m_verticalScrollbars.end(); ++it)
-        GraphicsLayer::unregisterContentsLayer(it->value->layer());
-
 }
 
 bool ScrollingCoordinator::touchHitTestingEnabled() const
@@ -112,7 +107,7 @@ bool ScrollingCoordinator::touchHitTestingEnabled() const
 
 void ScrollingCoordinator::setShouldHandleScrollGestureOnMainThreadRegion(const Region& region)
 {
-    if (WebLayer* scrollLayer = scrollingWebLayerForScrollableArea(m_page->mainFrame()->view())) {
+    if (WebLayer* scrollLayer = toWebLayer(m_page->mainFrame()->view()->layerForScrolling())) {
         Vector<IntRect> rects = region.rects();
         WebVector<WebRect> webRects(rects.size());
         for (size_t i = 0; i < rects.size(); ++i)
@@ -123,9 +118,9 @@ void ScrollingCoordinator::setShouldHandleScrollGestureOnMainThreadRegion(const
 
 void ScrollingCoordinator::notifyLayoutUpdated()
 {
-    // These computations need to happen after compositing is updated.
     m_scrollGestureRegionIsDirty = true;
     m_touchEventTargetRectsAreDirty = true;
+    m_shouldScrollOnMainThreadDirty = true;
 }
 
 void ScrollingCoordinator::updateAfterCompositingChange()
@@ -151,28 +146,48 @@ void ScrollingCoordinator::updateAfterCompositingChange()
         m_touchEventTargetRectsAreDirty = false;
     }
 
+    FrameView* frameView = m_page->mainFrame()->view();
+    bool frameIsScrollable = frameView && frameView->isScrollable();
+    if (m_shouldScrollOnMainThreadDirty || m_wasFrameScrollable != frameIsScrollable) {
+        setShouldUpdateScrollLayerPositionOnMainThread(mainThreadScrollingReasons());
+        m_shouldScrollOnMainThreadDirty = false;
+    }
+    m_wasFrameScrollable = frameIsScrollable;
+
+    // The mainFrame view doesn't get included in the FrameTree below, so we
+    // update its size separately.
+    if (WebLayer* scrollingWebLayer = frameView ? toWebLayer(frameView->layerForScrolling()) : 0) {
+        scrollingWebLayer->setBounds(frameView->contentsSize());
+        // If there is a fullscreen element, set the scroll clip layer to 0 so main frame won't scroll.
+        Element* fullscreenElement = FullscreenElementStack::fullscreenElementFrom(*(m_page->mainFrame()->document()));
+        if (fullscreenElement)
+            scrollingWebLayer->setScrollClipLayer(0);
+        else
+            scrollingWebLayer->setScrollClipLayer(toWebLayer(frameView->layerForContainer()));
+    }
+
     const FrameTree& tree = m_page->mainFrame()->tree();
-    for (const Frame* child = tree.firstChild(); child; child = child->tree().nextSibling()) {
-        if (WebLayer* scrollLayer = scrollingWebLayerForScrollableArea(child->view()))
+    for (const LocalFrame* child = tree.firstChild(); child; child = child->tree().nextSibling()) {
+        if (WebLayer* scrollLayer = toWebLayer(child->view()->layerForScrolling()))
             scrollLayer->setBounds(child->view()->contentsSize());
     }
 }
 
 void ScrollingCoordinator::setLayerIsContainerForFixedPositionLayers(GraphicsLayer* layer, bool enable)
 {
-    if (WebLayer* scrollableLayer = scrollingWebLayerForGraphicsLayer(layer))
+    if (WebLayer* scrollableLayer = toWebLayer(layer))
         scrollableLayer->setIsContainerForFixedPositionLayers(enable);
 }
 
 static void clearPositionConstraintExceptForLayer(GraphicsLayer* layer, GraphicsLayer* except)
 {
-    if (layer && layer != except && scrollingWebLayerForGraphicsLayer(layer))
-        scrollingWebLayerForGraphicsLayer(layer)->setPositionConstraint(WebLayerPositionConstraint());
+    if (layer && layer != except && toWebLayer(layer))
+        toWebLayer(layer)->setPositionConstraint(WebLayerPositionConstraint());
 }
 
 static WebLayerPositionConstraint computePositionConstraint(const RenderLayer* layer)
 {
-    ASSERT(layer->compositedLayerMapping());
+    ASSERT(layer->hasCompositedLayerMapping());
     do {
         if (layer->renderer()->style()->position() == FixedPosition) {
             const RenderObject* fixedPositionObject = layer->renderer();
@@ -185,21 +200,21 @@ static WebLayerPositionConstraint computePositionConstraint(const RenderLayer* l
 
         // Composited layers that inherit a fixed position state will be positioned with respect to the nearest compositedLayerMapping's GraphicsLayer.
         // So, once we find a layer that has its own compositedLayerMapping, we can stop searching for a fixed position RenderObject.
-    } while (layer && layer->compositedLayerMapping());
+    } while (layer && !layer->hasCompositedLayerMapping());
     return WebLayerPositionConstraint();
 }
 
 void ScrollingCoordinator::updateLayerPositionConstraint(RenderLayer* layer)
 {
-    ASSERT(layer->compositedLayerMapping());
-    CompositedLayerMapping* compositedLayerMapping = layer->compositedLayerMapping();
-    GraphicsLayer* mainLayer = compositedLayerMapping->childForSuperlayers();
+    ASSERT(layer->hasCompositedLayerMapping());
+    CompositedLayerMappingPtr compositedLayerMapping = layer->compositedLayerMapping();
+    GraphicsLayer* mainLayer = compositedLayerMapping->localRootForOwningLayer();
 
     // Avoid unnecessary commits
     clearPositionConstraintExceptForLayer(compositedLayerMapping->ancestorClippingLayer(), mainLayer);
     clearPositionConstraintExceptForLayer(compositedLayerMapping->mainGraphicsLayer(), mainLayer);
 
-    if (WebLayer* scrollableLayer = scrollingWebLayerForGraphicsLayer(mainLayer))
+    if (WebLayer* scrollableLayer = toWebLayer(mainLayer))
         scrollableLayer->setPositionConstraint(computePositionConstraint(layer));
 }
 
@@ -219,18 +234,18 @@ void ScrollingCoordinator::removeWebScrollbarLayer(ScrollableArea* scrollableAre
 static PassOwnPtr<WebScrollbarLayer> createScrollbarLayer(Scrollbar* scrollbar)
 {
     ScrollbarTheme* theme = scrollbar->theme();
-    WebKit::WebScrollbarThemePainter painter(theme, scrollbar);
-    OwnPtr<WebKit::WebScrollbarThemeGeometry> geometry(WebKit::WebScrollbarThemeGeometryNative::create(theme));
+    blink::WebScrollbarThemePainter painter(theme, scrollbar);
+    OwnPtr<blink::WebScrollbarThemeGeometry> geometry(blink::WebScrollbarThemeGeometryNative::create(theme));
 
-    OwnPtr<WebScrollbarLayer> scrollbarLayer = adoptPtr(WebKit::Platform::current()->compositorSupport()->createScrollbarLayer(new WebKit::WebScrollbarImpl(scrollbar), painter, geometry.leakPtr()));
+    OwnPtr<WebScrollbarLayer> scrollbarLayer = adoptPtr(blink::Platform::current()->compositorSupport()->createScrollbarLayer(new blink::WebScrollbarImpl(scrollbar), painter, geometry.leakPtr()));
     GraphicsLayer::registerContentsLayer(scrollbarLayer->layer());
     return scrollbarLayer.release();
 }
 
-PassOwnPtr<WebScrollbarLayer> ScrollingCoordinator::createSolidColorScrollbarLayer(ScrollbarOrientation orientation, int thumbThickness, bool isLeftSideVerticalScrollbar)
+PassOwnPtr<WebScrollbarLayer> ScrollingCoordinator::createSolidColorScrollbarLayer(ScrollbarOrientation orientation, int thumbThickness, int trackStart, bool isLeftSideVerticalScrollbar)
 {
-    WebKit::WebScrollbar::Orientation webOrientation = (orientation == HorizontalScrollbar) ? WebKit::WebScrollbar::Horizontal : WebKit::WebScrollbar::Vertical;
-    OwnPtr<WebScrollbarLayer> scrollbarLayer = adoptPtr(WebKit::Platform::current()->compositorSupport()->createSolidColorScrollbarLayer(webOrientation, thumbThickness, isLeftSideVerticalScrollbar));
+    blink::WebScrollbar::Orientation webOrientation = (orientation == HorizontalScrollbar) ? blink::WebScrollbar::Horizontal : blink::WebScrollbar::Vertical;
+    OwnPtr<WebScrollbarLayer> scrollbarLayer = adoptPtr(blink::Platform::current()->compositorSupport()->createSolidColorScrollbarLayer(webOrientation, thumbThickness, trackStart, isLeftSideVerticalScrollbar));
     GraphicsLayer::registerContentsLayer(scrollbarLayer->layer());
     return scrollbarLayer.release();
 }
@@ -243,7 +258,7 @@ static void detachScrollbarLayer(GraphicsLayer* scrollbarGraphicsLayer)
     scrollbarGraphicsLayer->setDrawsContent(true);
 }
 
-static void setupScrollbarLayer(GraphicsLayer* scrollbarGraphicsLayer, WebScrollbarLayer* scrollbarLayer, WebLayer* scrollLayer)
+static void setupScrollbarLayer(GraphicsLayer* scrollbarGraphicsLayer, WebScrollbarLayer* scrollbarLayer, WebLayer* scrollLayer, WebLayer* containerLayer)
 {
     ASSERT(scrollbarGraphicsLayer);
     ASSERT(scrollbarLayer);
@@ -253,14 +268,15 @@ static void setupScrollbarLayer(GraphicsLayer* scrollbarGraphicsLayer, WebScroll
         return;
     }
     scrollbarLayer->setScrollLayer(scrollLayer);
+    scrollbarLayer->setClipLayer(containerLayer);
     scrollbarGraphicsLayer->setContentsToPlatformLayer(scrollbarLayer->layer());
     scrollbarGraphicsLayer->setDrawsContent(false);
 }
 
-WebScrollbarLayer* ScrollingCoordinator::addWebScrollbarLayer(ScrollableArea* scrollableArea, ScrollbarOrientation orientation, PassOwnPtr<WebKit::WebScrollbarLayer> scrollbarLayer)
+WebScrollbarLayer* ScrollingCoordinator::addWebScrollbarLayer(ScrollableArea* scrollableArea, ScrollbarOrientation orientation, PassOwnPtr<blink::WebScrollbarLayer> scrollbarLayer)
 {
     ScrollbarMap& scrollbars = orientation == HorizontalScrollbar ? m_horizontalScrollbars : m_verticalScrollbars;
-    return scrollbars.add(scrollableArea, scrollbarLayer).iterator->value.get();
+    return scrollbars.add(scrollableArea, scrollbarLayer).storedValue->value.get();
 }
 
 WebScrollbarLayer* ScrollingCoordinator::getWebScrollbarLayer(ScrollableArea* scrollableArea, ScrollbarOrientation orientation)
@@ -289,7 +305,10 @@ void ScrollingCoordinator::scrollableAreaScrollbarLayerDidChange(ScrollableArea*
     if (!isMainFrame && platformSupportsMainFrameOnly)
         return;
 
-    GraphicsLayer* scrollbarGraphicsLayer = orientation == HorizontalScrollbar ? horizontalScrollbarLayerForScrollableArea(scrollableArea) : verticalScrollbarLayerForScrollableArea(scrollableArea);
+    GraphicsLayer* scrollbarGraphicsLayer = orientation == HorizontalScrollbar
+        ? scrollableArea->layerForHorizontalScrollbar()
+        : scrollableArea->layerForVerticalScrollbar();
+
     if (scrollbarGraphicsLayer) {
         Scrollbar* scrollbar = orientation == HorizontalScrollbar ? scrollableArea->horizontalScrollbar() : scrollableArea->verticalScrollbar();
         if (scrollbar->isCustomScrollbar()) {
@@ -304,7 +323,7 @@ void ScrollingCoordinator::scrollableAreaScrollbarLayerDidChange(ScrollableArea*
             OwnPtr<WebScrollbarLayer> webScrollbarLayer;
             if (settings->useSolidColorScrollbars()) {
                 ASSERT(RuntimeEnabledFeatures::overlayScrollbarsEnabled());
-                webScrollbarLayer = createSolidColorScrollbarLayer(orientation, scrollbar->theme()->thumbThickness(scrollbar), scrollableArea->shouldPlaceVerticalScrollbarOnLeft());
+                webScrollbarLayer = createSolidColorScrollbarLayer(orientation, scrollbar->theme()->thumbThickness(scrollbar), scrollbar->theme()->trackPosition(scrollbar), scrollableArea->shouldPlaceVerticalScrollbarOnLeft());
             } else {
                 webScrollbarLayer = createScrollbarLayer(scrollbar);
             }
@@ -318,64 +337,97 @@ void ScrollingCoordinator::scrollableAreaScrollbarLayerDidChange(ScrollableArea*
             scrollbarGraphicsLayer->setContentsOpaque(isMainFrame && isOpaqueScrollbar);
         scrollbarLayer->layer()->setOpaque(scrollbarGraphicsLayer->contentsOpaque());
 
-        setupScrollbarLayer(scrollbarGraphicsLayer, scrollbarLayer, scrollingWebLayerForScrollableArea(scrollableArea));
+        WebLayer* scrollLayer = toWebLayer(scrollableArea->layerForScrolling());
+        WebLayer* containerLayer = toWebLayer(scrollableArea->layerForContainer());
+        setupScrollbarLayer(scrollbarGraphicsLayer, scrollbarLayer, scrollLayer, containerLayer);
     } else
         removeWebScrollbarLayer(scrollableArea, orientation);
 }
 
 bool ScrollingCoordinator::scrollableAreaScrollLayerDidChange(ScrollableArea* scrollableArea)
 {
-    GraphicsLayer* scrollLayer = scrollLayerForScrollableArea(scrollableArea);
+    GraphicsLayer* scrollLayer = scrollableArea->layerForScrolling();
+
     if (scrollLayer) {
-        bool isMainFrame = isForMainFrame(scrollableArea);
-        scrollLayer->setScrollableArea(scrollableArea, isMainFrame);
+        ASSERT(m_page);
+        // With pinch virtual viewport we no longer need to special case the main frame.
+        bool pinchVirtualViewportEnabled = m_page->settings().pinchVirtualViewportEnabled();
+        bool layerScrollShouldFireGraphicsLayerDidScroll = isForMainFrame(scrollableArea) && !pinchVirtualViewportEnabled;
+        scrollLayer->setScrollableArea(scrollableArea, layerScrollShouldFireGraphicsLayerDidScroll);
     }
 
-    WebLayer* webLayer = scrollingWebLayerForScrollableArea(scrollableArea);
+    WebLayer* webLayer = toWebLayer(scrollableArea->layerForScrolling());
+    WebLayer* containerLayer = toWebLayer(scrollableArea->layerForContainer());
     if (webLayer) {
-        webLayer->setScrollable(true);
+        webLayer->setScrollClipLayer(containerLayer);
         webLayer->setScrollPosition(IntPoint(scrollableArea->scrollPosition() - scrollableArea->minimumScrollPosition()));
-        webLayer->setMaxScrollPosition(IntSize(scrollableArea->scrollSize(HorizontalScrollbar), scrollableArea->scrollSize(VerticalScrollbar)));
+        webLayer->setBounds(scrollableArea->contentsSize());
         bool canScrollX = scrollableArea->userInputScrollable(HorizontalScrollbar);
         bool canScrollY = scrollableArea->userInputScrollable(VerticalScrollbar);
         webLayer->setUserScrollable(canScrollX, canScrollY);
     }
     if (WebScrollbarLayer* scrollbarLayer = getWebScrollbarLayer(scrollableArea, HorizontalScrollbar)) {
-        GraphicsLayer* horizontalScrollbarLayer = horizontalScrollbarLayerForScrollableArea(scrollableArea);
+        GraphicsLayer* horizontalScrollbarLayer = scrollableArea->layerForHorizontalScrollbar();
         if (horizontalScrollbarLayer)
-            setupScrollbarLayer(horizontalScrollbarLayer, scrollbarLayer, webLayer);
+            setupScrollbarLayer(horizontalScrollbarLayer, scrollbarLayer, webLayer, containerLayer);
     }
     if (WebScrollbarLayer* scrollbarLayer = getWebScrollbarLayer(scrollableArea, VerticalScrollbar)) {
-        GraphicsLayer* verticalScrollbarLayer = verticalScrollbarLayerForScrollableArea(scrollableArea);
+        GraphicsLayer* verticalScrollbarLayer = scrollableArea->layerForVerticalScrollbar();
         if (verticalScrollbarLayer)
-            setupScrollbarLayer(verticalScrollbarLayer, scrollbarLayer, webLayer);
+            setupScrollbarLayer(verticalScrollbarLayer, scrollbarLayer, webLayer, containerLayer);
     }
 
     return !!webLayer;
 }
 
+typedef WTF::HashMap<const GraphicsLayer*, Vector<LayoutRect> > GraphicsLayerHitTestRects;
+
 // In order to do a DFS cross-frame walk of the RenderLayer tree, we need to know which
 // RenderLayers have child frames inside of them. This computes a mapping for the
 // current frame which we can consult while walking the layers of that frame.
 // Whenever we descend into a new frame, a new map will be created.
-typedef HashMap<const RenderLayer*, Vector<const Frame*> > LayerFrameMap;
-static void makeLayerChildFrameMap(const Frame* currentFrame, LayerFrameMap* map)
+typedef HashMap<const RenderLayer*, Vector<const LocalFrame*> > LayerFrameMap;
+static void makeLayerChildFrameMap(const LocalFrame* currentFrame, LayerFrameMap* map)
 {
     map->clear();
     const FrameTree& tree = currentFrame->tree();
-    for (const Frame* child = tree.firstChild(); child; child = child->tree().nextSibling()) {
-        const RenderLayer* containingLayer = child->ownerRenderer()->enclosingLayer();
+    for (const LocalFrame* child = tree.firstChild(); child; child = child->tree().nextSibling()) {
+        const RenderObject* ownerRenderer = child->ownerRenderer();
+        if (!ownerRenderer)
+            continue;
+        const RenderLayer* containingLayer = ownerRenderer->enclosingLayer();
         LayerFrameMap::iterator iter = map->find(containingLayer);
         if (iter == map->end())
-            iter = map->add(containingLayer, Vector<const Frame*>()).iterator;
-        iter->value.append(child);
+            map->add(containingLayer, Vector<const LocalFrame*>()).storedValue->value.append(child);
+        else
+            iter->value.append(child);
     }
 }
 
-static void convertLayerRectsToEnclosingCompositedLayerRecursive(
+// Return the enclosingCompositedLayerForRepaint for the given RenderLayer
+// including crossing frame boundaries.
+static const RenderLayer* enclosingCompositedLayer(const RenderLayer* layer)
+{
+    RenderLayer* compositedLayer = 0;
+    while (!compositedLayer) {
+        compositedLayer = layer->enclosingCompositingLayerForRepaint();
+        if (!compositedLayer) {
+            RenderObject* owner = layer->renderer()->frame()->ownerRenderer();
+            if (!owner)
+                break;
+            layer = owner->enclosingLayer();
+        }
+    }
+    // Since this machinery is used only when accelerated compositing is enabled, we expect
+    // that every layer should have an enclosing composited layer.
+    ASSERT(compositedLayer);
+    return compositedLayer;
+}
+
+static void projectRectsToGraphicsLayerSpaceRecursive(
     const RenderLayer* curLayer,
     const LayerHitTestRects& layerRects,
-    LayerHitTestRects& compositorRects,
+    GraphicsLayerHitTestRects& graphicsRects,
     RenderGeometryMap& geometryMap,
     HashSet<const RenderLayer*>& layersWithRects,
     LayerFrameMap& layerChildFrameMap)
@@ -384,27 +436,39 @@ static void convertLayerRectsToEnclosingCompositedLayerRecursive(
     LayerHitTestRects::const_iterator layerIter = layerRects.find(curLayer);
     if (layerIter != layerRects.end()) {
         // Find the enclosing composited layer when it's in another document (for non-composited iframes).
-        RenderLayer* compositedLayer = 0;
-        for (const RenderLayer* layer = layerIter->key; !compositedLayer;) {
-            compositedLayer = layer->enclosingCompositingLayerForRepaint();
-            if (!compositedLayer) {
-                RenderObject* owner = layer->renderer()->frame()->ownerRenderer();
-                if (!owner)
-                    break;
-                layer = owner->enclosingLayer();
-            }
-        }
-        if (!compositedLayer) {
-            // Since this machinery is used only when accelerated compositing is enabled, we expect
-            // that every layer should have an enclosing composited layer.
-            ASSERT_NOT_REACHED();
+        const RenderLayer* compositedLayer = enclosingCompositedLayer(layerIter->key);
+        if (!compositedLayer)
             return;
+
+        // Find the appropriate GraphicsLayer for the composited RenderLayer.
+        GraphicsLayer* graphicsLayer;
+        LayoutSize extraOffset;
+        if (compositedLayer->compositingState() == PaintsIntoGroupedBacking) {
+            graphicsLayer = compositedLayer->groupedMapping()->squashingLayer();
+            extraOffset = -compositedLayer->offsetFromSquashingLayerOrigin();
+        } else {
+            ASSERT(compositedLayer->hasCompositedLayerMapping());
+            CompositedLayerMappingPtr compositedLayerMapping = compositedLayer->compositedLayerMapping();
+            // The origin for the graphics layer does not have to be the same
+            // as the composited layer (e.g. when a child layer has negative
+            // offset and paints into this layer), so when projecting rects to
+            // graphics layer space they have to be offset by the origin for
+            // the composited layer.
+            extraOffset = compositedLayerMapping->contentOffsetInCompositingLayer();
+            // If the layer is using composited scrolling, then it's the contents that these
+            // rects apply to.
+            graphicsLayer = compositedLayerMapping->scrollingContentsLayer();
+            if (!graphicsLayer)
+                graphicsLayer = compositedLayerMapping->mainGraphicsLayer();
         }
 
-        LayerHitTestRects::iterator compIter = compositorRects.find(compositedLayer);
-        if (compIter == compositorRects.end())
-            compIter = compositorRects.add(compositedLayer, Vector<LayoutRect>()).iterator;
-        // Transform each rect to the co-ordinate space of it's enclosing composited layer.
+        GraphicsLayerHitTestRects::iterator glIter = graphicsRects.find(graphicsLayer);
+        Vector<LayoutRect>* glRects;
+        if (glIter == graphicsRects.end())
+            glRects = &graphicsRects.add(graphicsLayer, Vector<LayoutRect>()).storedValue->value;
+        else
+            glRects = &glIter->value;
+        // Transform each rect to the co-ordinate space of the graphicsLayer.
         for (size_t i = 0; i < layerIter->value.size(); ++i) {
             LayoutRect rect = layerIter->value[i];
             if (compositedLayer != curLayer) {
@@ -416,7 +480,8 @@ static void convertLayerRectsToEnclosingCompositedLayerRecursive(
                 if (compositedLayer->renderer()->hasOverflowClip())
                     rect.move(compositedLayer->renderBox()->scrolledContentOffset());
             }
-            compIter->value.append(rect);
+            rect.move(extraOffset);
+            glRects->append(rect);
         }
     }
 
@@ -424,7 +489,7 @@ static void convertLayerRectsToEnclosingCompositedLayerRecursive(
     for (const RenderLayer* childLayer = curLayer->firstChild(); childLayer; childLayer = childLayer->nextSibling()) {
         if (layersWithRects.contains(childLayer)) {
             geometryMap.pushMappingsToAncestor(childLayer, curLayer);
-            convertLayerRectsToEnclosingCompositedLayerRecursive(childLayer, layerRects, compositorRects, geometryMap, layersWithRects, layerChildFrameMap);
+            projectRectsToGraphicsLayerSpaceRecursive(childLayer, layerRects, graphicsRects, geometryMap, layersWithRects, layerChildFrameMap);
             geometryMap.popMappingsToAncestor(curLayer);
         }
     }
@@ -433,22 +498,22 @@ static void convertLayerRectsToEnclosingCompositedLayerRecursive(
     LayerFrameMap::iterator mapIter = layerChildFrameMap.find(curLayer);
     if (mapIter != layerChildFrameMap.end()) {
         for (size_t i = 0; i < mapIter->value.size(); i++) {
-            const Frame* childFrame = mapIter->value[i];
+            const LocalFrame* childFrame = mapIter->value[i];
             const RenderLayer* childLayer = childFrame->view()->renderView()->layer();
             if (layersWithRects.contains(childLayer)) {
                 LayerFrameMap newLayerChildFrameMap;
                 makeLayerChildFrameMap(childFrame, &newLayerChildFrameMap);
                 geometryMap.pushMappingsToAncestor(childLayer, curLayer);
-                convertLayerRectsToEnclosingCompositedLayerRecursive(childLayer, layerRects, compositorRects, geometryMap, layersWithRects, newLayerChildFrameMap);
+                projectRectsToGraphicsLayerSpaceRecursive(childLayer, layerRects, graphicsRects, geometryMap, layersWithRects, newLayerChildFrameMap);
                 geometryMap.popMappingsToAncestor(curLayer);
             }
         }
     }
 }
 
-static void convertLayerRectsToEnclosingCompositedLayer(Frame* mainFrame, const LayerHitTestRects& layerRects, LayerHitTestRects& compositorRects)
+static void projectRectsToGraphicsLayerSpace(LocalFrame* mainFrame, const LayerHitTestRects& layerRects, GraphicsLayerHitTestRects& graphicsRects)
 {
-    TRACE_EVENT0("input", "ScrollingCoordinator::convertLayerRectsToEnclosingCompositedLayer");
+    TRACE_EVENT0("input", "ScrollingCoordinator::projectRectsToGraphicsLayerSpace");
     bool touchHandlerInChildFrame = false;
 
     // We have a set of rects per RenderLayer, we need to map them to their bounding boxes in their
@@ -475,10 +540,12 @@ static void convertLayerRectsToEnclosingCompositedLayer(Frame* mainFrame, const
     MapCoordinatesFlags flags = UseTransforms;
     if (touchHandlerInChildFrame)
         flags |= TraverseDocumentBoundaries;
+    RenderLayer* rootLayer = mainFrame->contentRenderer()->layer();
     RenderGeometryMap geometryMap(flags);
+    geometryMap.pushMappingsToAncestor(rootLayer, 0);
     LayerFrameMap layerChildFrameMap;
     makeLayerChildFrameMap(mainFrame, &layerChildFrameMap);
-    convertLayerRectsToEnclosingCompositedLayerRecursive(mainFrame->contentRenderer()->layer(), layerRects, compositorRects, geometryMap, layersWithRects, layerChildFrameMap);
+    projectRectsToGraphicsLayerSpaceRecursive(rootLayer, layerRects, graphicsRects, geometryMap, layersWithRects, layerChildFrameMap);
 }
 
 void ScrollingCoordinator::updateTouchEventTargetRectsIfNeeded()
@@ -493,46 +560,61 @@ void ScrollingCoordinator::updateTouchEventTargetRectsIfNeeded()
     setTouchEventTargetRects(touchEventTargetRects);
 }
 
+void ScrollingCoordinator::reset()
+{
+    for (ScrollbarMap::iterator it = m_horizontalScrollbars.begin(); it != m_horizontalScrollbars.end(); ++it)
+        GraphicsLayer::unregisterContentsLayer(it->value->layer());
+    for (ScrollbarMap::iterator it = m_verticalScrollbars.begin(); it != m_verticalScrollbars.end(); ++it)
+        GraphicsLayer::unregisterContentsLayer(it->value->layer());
+
+    m_horizontalScrollbars.clear();
+    m_verticalScrollbars.clear();
+    m_layersWithTouchRects.clear();
+    m_wasFrameScrollable = false;
+
+    // This is retained for testing.
+    m_lastMainThreadScrollingReasons = 0;
+    setShouldUpdateScrollLayerPositionOnMainThread(m_lastMainThreadScrollingReasons);
+}
+
 // Note that in principle this could be called more often than computeTouchEventTargetRects, for
 // example during a non-composited scroll (although that's not yet implemented - crbug.com/261307).
-void ScrollingCoordinator::setTouchEventTargetRects(const LayerHitTestRects& layerRects)
+void ScrollingCoordinator::setTouchEventTargetRects(LayerHitTestRects& layerRects)
 {
     TRACE_EVENT0("input", "ScrollingCoordinator::setTouchEventTargetRects");
 
-    LayerHitTestRects compositorRects;
-    convertLayerRectsToEnclosingCompositedLayer(m_page->mainFrame(), layerRects, compositorRects);
-
+    // Update the list of layers with touch hit rects.
     HashSet<const RenderLayer*> oldLayersWithTouchRects;
     m_layersWithTouchRects.swap(oldLayersWithTouchRects);
+    for (LayerHitTestRects::iterator it = layerRects.begin(); it != layerRects.end(); ++it) {
+        if (!it->value.isEmpty()) {
+            const RenderLayer* compositedLayer = enclosingCompositedLayer(it->key);
+            if (compositedLayer)
+                m_layersWithTouchRects.add(compositedLayer);
+        }
+    }
 
-    for (LayerHitTestRects::const_iterator iter = compositorRects.begin(); iter != compositorRects.end(); ++iter) {
-        const RenderLayer* layer = iter->key;
+    // Ensure we have an entry for each composited layer that previously had rects (so that old
+    // ones will get cleared out). Note that ideally we'd track this on GraphicsLayer instead of
+    // RenderLayer, but we have no good hook into the lifetime of a GraphicsLayer.
+    for (HashSet<const RenderLayer*>::iterator it = oldLayersWithTouchRects.begin(); it != oldLayersWithTouchRects.end(); ++it) {
+        if (!layerRects.contains(*it))
+            layerRects.add(*it, Vector<LayoutRect>());
+    }
+
+    GraphicsLayerHitTestRects graphicsLayerRects;
+    projectRectsToGraphicsLayerSpace(m_page->mainFrame(), layerRects, graphicsLayerRects);
+
+    for (GraphicsLayerHitTestRects::const_iterator iter = graphicsLayerRects.begin(); iter != graphicsLayerRects.end(); ++iter) {
+        const GraphicsLayer* graphicsLayer = iter->key;
         WebVector<WebRect> webRects(iter->value.size());
         for (size_t i = 0; i < iter->value.size(); ++i)
             webRects[i] = enclosingIntRect(iter->value[i]);
-        CompositedLayerMapping* compositedLayerMapping = layer->compositedLayerMapping();
-        // If the layer is using composited scrolling, then it's the contents that these
-        // rects apply to.
-        GraphicsLayer* graphicsLayer = compositedLayerMapping->scrollingContentsLayer();
-        if (!graphicsLayer)
-            graphicsLayer = compositedLayerMapping->mainGraphicsLayer();
         graphicsLayer->platformLayer()->setTouchEventHandlerRegion(webRects);
-        oldLayersWithTouchRects.remove(layer);
-        m_layersWithTouchRects.add(layer);
-    }
-
-    // If there are any layers left that we haven't updated, clear them out.
-    for (HashSet<const RenderLayer*>::iterator it = oldLayersWithTouchRects.begin(); it != oldLayersWithTouchRects.end(); ++it) {
-        if (CompositedLayerMapping* compositedLayerMapping = (*it)->compositedLayerMapping()) {
-            GraphicsLayer* graphicsLayer = compositedLayerMapping->scrollingContentsLayer();
-            if (!graphicsLayer)
-                graphicsLayer = compositedLayerMapping->mainGraphicsLayer();
-            graphicsLayer->platformLayer()->setTouchEventHandlerRegion(WebVector<WebRect>());
-        }
     }
 }
 
-void ScrollingCoordinator::touchEventTargetRectsDidChange(const Document*)
+void ScrollingCoordinator::touchEventTargetRectsDidChange()
 {
     if (!touchHitTestingEnabled())
         return;
@@ -544,7 +626,7 @@ void ScrollingCoordinator::touchEventTargetRectsDidChange(const Document*)
     // FIXME: scheduleAnimation() is just a method of forcing the compositor to realize that it
     // needs to commit here. We should expose a cleaner API for this.
     RenderView* renderView = m_page->mainFrame()->contentRenderer();
-    if (renderView && renderView->compositor() && renderView->compositor()->inCompositingMode())
+    if (renderView && renderView->compositor() && renderView->compositor()->staleInCompositingMode())
         m_page->mainFrame()->view()->scheduleAnimation();
 
     m_touchEventTargetRectsAreDirty = true;
@@ -553,8 +635,8 @@ void ScrollingCoordinator::touchEventTargetRectsDidChange(const Document*)
 void ScrollingCoordinator::updateScrollParentForGraphicsLayer(GraphicsLayer* child, RenderLayer* parent)
 {
     WebLayer* scrollParentWebLayer = 0;
-    if (parent && parent->compositedLayerMapping())
-        scrollParentWebLayer = scrollingWebLayerForGraphicsLayer(parent->compositedLayerMapping()->parentForSublayers());
+    if (parent && parent->hasCompositedLayerMapping())
+        scrollParentWebLayer = toWebLayer(parent->compositedLayerMapping()->parentForSublayers());
 
     child->setScrollParent(scrollParentWebLayer);
 }
@@ -562,8 +644,8 @@ void ScrollingCoordinator::updateScrollParentForGraphicsLayer(GraphicsLayer* chi
 void ScrollingCoordinator::updateClipParentForGraphicsLayer(GraphicsLayer* child, RenderLayer* parent)
 {
     WebLayer* clipParentWebLayer = 0;
-    if (parent && parent->compositedLayerMapping())
-        clipParentWebLayer = scrollingWebLayerForGraphicsLayer(parent->compositedLayerMapping()->parentForSublayers());
+    if (parent && parent->hasCompositedLayerMapping())
+        clipParentWebLayer = toWebLayer(parent->compositedLayerMapping()->parentForSublayers());
 
     child->setClipParent(clipParentWebLayer);
 }
@@ -573,28 +655,52 @@ void ScrollingCoordinator::willDestroyRenderLayer(RenderLayer* layer)
     m_layersWithTouchRects.remove(layer);
 }
 
-void ScrollingCoordinator::setWheelEventHandlerCount(unsigned count)
+void ScrollingCoordinator::updateHaveWheelEventHandlers()
 {
-    if (WebLayer* scrollLayer = scrollingWebLayerForScrollableArea(m_page->mainFrame()->view()))
-        scrollLayer->setHaveWheelEventHandlers(count > 0);
+    ASSERT(isMainThread());
+    ASSERT(m_page);
+
+    if (WebLayer* scrollLayer = toWebLayer(m_page->mainFrame()->view()->layerForScrolling())) {
+        unsigned wheelEventHandlerCount = 0;
+
+        for (LocalFrame* frame = m_page->mainFrame(); frame; frame = frame->tree().traverseNext()) {
+            wheelEventHandlerCount += WheelController::from(*frame->document())->wheelEventHandlerCount();
+        }
+
+        scrollLayer->setHaveWheelEventHandlers(wheelEventHandlerCount);
+    }
 }
 
-void ScrollingCoordinator::recomputeWheelEventHandlerCountForFrameView(FrameView* frameView)
+void ScrollingCoordinator::updateHaveScrollEventHandlers()
 {
-    UNUSED_PARAM(frameView);
-    setWheelEventHandlerCount(computeCurrentWheelEventHandlerCount());
+    ASSERT(isMainThread());
+    ASSERT(m_page);
+
+    // Currently the compositor only cares whether there are scroll handlers anywhere on the page
+    // instead on a per-layer basis. We therefore only update this information for the root
+    // scrolling layer.
+    if (WebLayer* scrollLayer = toWebLayer(m_page->mainFrame()->view()->layerForScrolling())) {
+        bool haveHandlers = m_page->frameHost().eventHandlerRegistry().hasEventHandlers(EventHandlerRegistry::ScrollEvent);
+        scrollLayer->setHaveScrollEventHandlers(haveHandlers);
+    }
 }
 
 void ScrollingCoordinator::setShouldUpdateScrollLayerPositionOnMainThread(MainThreadScrollingReasons reasons)
 {
-    if (WebLayer* scrollLayer = scrollingWebLayerForScrollableArea(m_page->mainFrame()->view()))
+    if (WebLayer* scrollLayer = toWebLayer(m_page->mainFrame()->view()->layerForScrolling())) {
+        m_lastMainThreadScrollingReasons = reasons;
         scrollLayer->setShouldScrollOnMainThread(reasons);
+    }
 }
 
-void ScrollingCoordinator::pageDestroyed()
+void ScrollingCoordinator::willBeDestroyed()
 {
     ASSERT(m_page);
     m_page = 0;
+    for (ScrollbarMap::iterator it = m_horizontalScrollbars.begin(); it != m_horizontalScrollbars.end(); ++it)
+        GraphicsLayer::unregisterContentsLayer(it->value->layer());
+    for (ScrollbarMap::iterator it = m_verticalScrollbars.begin(); it != m_verticalScrollbars.end(); ++it)
+        GraphicsLayer::unregisterContentsLayer(it->value->layer());
 }
 
 bool ScrollingCoordinator::coordinatesScrollingForFrameView(FrameView* frameView) const
@@ -613,7 +719,7 @@ bool ScrollingCoordinator::coordinatesScrollingForFrameView(FrameView* frameView
     return renderView->usesCompositing();
 }
 
-Region ScrollingCoordinator::computeShouldHandleScrollGestureOnMainThreadRegion(const Frame* frame, const IntPoint& frameLocation) const
+Region ScrollingCoordinator::computeShouldHandleScrollGestureOnMainThreadRegion(const LocalFrame* frame, const IntPoint& frameLocation) const
 {
     Region shouldHandleScrollGestureOnMainThreadRegion;
     FrameView* frameView = frame->view();
@@ -661,7 +767,7 @@ Region ScrollingCoordinator::computeShouldHandleScrollGestureOnMainThreadRegion(
     }
 
     const FrameTree& tree = frame->tree();
-    for (Frame* subFrame = tree.firstChild(); subFrame; subFrame = subFrame->tree().nextSibling())
+    for (LocalFrame* subFrame = tree.firstChild(); subFrame; subFrame = subFrame->tree().nextSibling())
         shouldHandleScrollGestureOnMainThreadRegion.unite(computeShouldHandleScrollGestureOnMainThreadRegion(subFrame, offset));
 
     return shouldHandleScrollGestureOnMainThreadRegion;
@@ -705,8 +811,24 @@ static void accumulateDocumentTouchEventTargetRects(LayerHitTestRects& rects, co
                 if (targets->contains(ancestor))
                     hasTouchEventTargetAncestor = true;
             }
-            if (!hasTouchEventTargetAncestor)
+            if (!hasTouchEventTargetAncestor) {
+                // Walk up the tree to the outermost non-composited scrollable layer.
+                RenderLayer* enclosingNonCompositedScrollLayer = 0;
+                for (RenderLayer* parent = renderer->enclosingLayer(); parent && parent->compositingState() == NotComposited; parent = parent->parent()) {
+                    if (parent->scrollsOverflow())
+                        enclosingNonCompositedScrollLayer = parent;
+                }
+
+                // Report the whole non-composited scroll layer as a touch hit rect because any
+                // rects inside of it may move around relative to their enclosing composited layer
+                // without causing the rects to be recomputed. Non-composited scrolling occurs on
+                // the main thread, so we're not getting much benefit from compositor touch hit
+                // testing in this case anyway.
+                if (enclosingNonCompositedScrollLayer)
+                    enclosingNonCompositedScrollLayer->computeSelfHitTestRects(rects);
+
                 renderer->computeLayerHitTestRects(rects);
+            }
         }
     }
 
@@ -724,26 +846,6 @@ void ScrollingCoordinator::computeTouchEventTargetRects(LayerHitTestRects& rects
     accumulateDocumentTouchEventTargetRects(rects, document);
 }
 
-unsigned ScrollingCoordinator::computeCurrentWheelEventHandlerCount()
-{
-    unsigned wheelEventHandlerCount = 0;
-
-    for (Frame* frame = m_page->mainFrame(); frame; frame = frame->tree().traverseNext()) {
-        if (frame->document())
-            wheelEventHandlerCount += WheelController::from(frame->document())->wheelEventHandlerCount();
-    }
-
-    return wheelEventHandlerCount;
-}
-
-void ScrollingCoordinator::frameViewWheelEventHandlerCountChanged(FrameView* frameView)
-{
-    ASSERT(isMainThread());
-    ASSERT(m_page);
-
-    recomputeWheelEventHandlerCountForFrameView(frameView);
-}
-
 void ScrollingCoordinator::frameViewHasSlowRepaintObjectsDidChange(FrameView* frameView)
 {
     ASSERT(isMainThread());
@@ -752,7 +854,7 @@ void ScrollingCoordinator::frameViewHasSlowRepaintObjectsDidChange(FrameView* fr
     if (!coordinatesScrollingForFrameView(frameView))
         return;
 
-    updateShouldUpdateScrollLayerPositionOnMainThread();
+    m_shouldScrollOnMainThreadDirty = true;
 }
 
 void ScrollingCoordinator::frameViewFixedObjectsDidChange(FrameView* frameView)
@@ -763,22 +865,7 @@ void ScrollingCoordinator::frameViewFixedObjectsDidChange(FrameView* frameView)
     if (!coordinatesScrollingForFrameView(frameView))
         return;
 
-    updateShouldUpdateScrollLayerPositionOnMainThread();
-}
-
-GraphicsLayer* ScrollingCoordinator::scrollLayerForScrollableArea(ScrollableArea* scrollableArea)
-{
-    return scrollableArea->layerForScrolling();
-}
-
-GraphicsLayer* ScrollingCoordinator::horizontalScrollbarLayerForScrollableArea(ScrollableArea* scrollableArea)
-{
-    return scrollableArea->layerForHorizontalScrollbar();
-}
-
-GraphicsLayer* ScrollingCoordinator::verticalScrollbarLayerForScrollableArea(ScrollableArea* scrollableArea)
-{
-    return scrollableArea->layerForVerticalScrollbar();
+    m_shouldScrollOnMainThreadDirty = true;
 }
 
 bool ScrollingCoordinator::isForMainFrame(ScrollableArea* scrollableArea) const
@@ -786,19 +873,6 @@ bool ScrollingCoordinator::isForMainFrame(ScrollableArea* scrollableArea) const
     return scrollableArea == m_page->mainFrame()->view();
 }
 
-GraphicsLayer* ScrollingCoordinator::scrollLayerForFrameView(FrameView* frameView)
-{
-    RenderView* renderView = frameView->frame().contentRenderer();
-    if (!renderView)
-        return 0;
-    return renderView->compositor()->scrollLayer();
-}
-
-GraphicsLayer* ScrollingCoordinator::counterScrollingLayerForFrameView(FrameView*)
-{
-    return 0;
-}
-
 void ScrollingCoordinator::frameViewRootLayerDidChange(FrameView* frameView)
 {
     ASSERT(isMainThread());
@@ -808,8 +882,8 @@ void ScrollingCoordinator::frameViewRootLayerDidChange(FrameView* frameView)
         return;
 
     notifyLayoutUpdated();
-    recomputeWheelEventHandlerCountForFrameView(frameView);
-    updateShouldUpdateScrollLayerPositionOnMainThread();
+    updateHaveWheelEventHandlers();
+    updateHaveScrollEventHandlers();
 }
 
 #if OS(MACOSX)
@@ -853,6 +927,9 @@ bool ScrollingCoordinator::hasVisibleSlowRepaintViewportConstrainedObjects(Frame
 
 MainThreadScrollingReasons ScrollingCoordinator::mainThreadScrollingReasons() const
 {
+    // The main thread scrolling reasons are applicable to scrolls of the main
+    // frame. If it does not exist or if it is not scrollable, there is no
+    // reason to force main thread scrolling.
     FrameView* frameView = m_page->mainFrame()->view();
     if (!frameView)
         return static_cast<MainThreadScrollingReasons>(0);
@@ -867,11 +944,6 @@ MainThreadScrollingReasons ScrollingCoordinator::mainThreadScrollingReasons() co
     return mainThreadScrollingReasons;
 }
 
-void ScrollingCoordinator::updateShouldUpdateScrollLayerPositionOnMainThread()
-{
-    setShouldUpdateScrollLayerPositionOnMainThread(mainThreadScrollingReasons());
-}
-
 String ScrollingCoordinator::mainThreadScrollingReasonsAsText(MainThreadScrollingReasons reasons)
 {
     StringBuilder stringBuilder;
@@ -890,7 +962,20 @@ String ScrollingCoordinator::mainThreadScrollingReasonsAsText(MainThreadScrollin
 
 String ScrollingCoordinator::mainThreadScrollingReasonsAsText() const
 {
-    return mainThreadScrollingReasonsAsText(mainThreadScrollingReasons());
+    ASSERT(m_page->mainFrame()->document()->lifecycle().state() >= DocumentLifecycle::CompositingClean);
+    return mainThreadScrollingReasonsAsText(m_lastMainThreadScrollingReasons);
+}
+
+bool ScrollingCoordinator::frameViewIsDirty() const
+{
+    FrameView* frameView = m_page->mainFrame()->view();
+    bool frameIsScrollable = frameView && frameView->isScrollable();
+    if (frameIsScrollable != m_wasFrameScrollable)
+        return true;
+
+    if (WebLayer* scrollLayer = frameView ? toWebLayer(frameView->layerForScrolling()) : 0)
+        return blink::WebSize(frameView->contentsSize()) != scrollLayer->bounds();
+    return false;
 }
 
 } // namespace WebCore