Home | History | Annotate | Download | only in scrolling
      1 /*
      2  * Copyright (C) 2011 Apple Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  * 1. Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  * 2. Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
     14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
     17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
     23  * THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #include "config.h"
     27 
     28 #include "core/page/scrolling/ScrollingCoordinator.h"
     29 
     30 #include "core/dom/Document.h"
     31 #include "core/dom/Fullscreen.h"
     32 #include "core/dom/Node.h"
     33 #include "core/frame/EventHandlerRegistry.h"
     34 #include "core/frame/FrameView.h"
     35 #include "core/frame/LocalFrame.h"
     36 #include "core/frame/Settings.h"
     37 #include "core/html/HTMLElement.h"
     38 #include "core/page/Page.h"
     39 #include "core/plugins/PluginView.h"
     40 #include "core/rendering/RenderGeometryMap.h"
     41 #include "core/rendering/RenderPart.h"
     42 #include "core/rendering/RenderView.h"
     43 #include "core/rendering/compositing/CompositedLayerMapping.h"
     44 #include "core/rendering/compositing/RenderLayerCompositor.h"
     45 #include "platform/RuntimeEnabledFeatures.h"
     46 #include "platform/TraceEvent.h"
     47 #include "platform/exported/WebScrollbarImpl.h"
     48 #include "platform/exported/WebScrollbarThemeGeometryNative.h"
     49 #include "platform/geometry/Region.h"
     50 #include "platform/geometry/TransformState.h"
     51 #include "platform/graphics/GraphicsLayer.h"
     52 #if OS(MACOSX)
     53 #include "platform/mac/ScrollAnimatorMac.h"
     54 #endif
     55 #include "platform/scroll/ScrollAnimator.h"
     56 #include "platform/scroll/ScrollbarTheme.h"
     57 #include "public/platform/Platform.h"
     58 #include "public/platform/WebCompositorSupport.h"
     59 #include "public/platform/WebLayerPositionConstraint.h"
     60 #include "public/platform/WebScrollbarLayer.h"
     61 #include "public/platform/WebScrollbarThemeGeometry.h"
     62 #include "public/platform/WebScrollbarThemePainter.h"
     63 #include "wtf/text/StringBuilder.h"
     64 
     65 using blink::WebLayer;
     66 using blink::WebLayerPositionConstraint;
     67 using blink::WebRect;
     68 using blink::WebScrollbarLayer;
     69 using blink::WebVector;
     70 
     71 namespace {
     72 
     73 WebLayer* toWebLayer(blink::GraphicsLayer* layer)
     74 {
     75     return layer ? layer->platformLayer() : 0;
     76 }
     77 
     78 } // namespace
     79 
     80 namespace blink {
     81 
     82 PassOwnPtr<ScrollingCoordinator> ScrollingCoordinator::create(Page* page)
     83 {
     84     return adoptPtr(new ScrollingCoordinator(page));
     85 }
     86 
     87 ScrollingCoordinator::ScrollingCoordinator(Page* page)
     88     : m_page(page)
     89     , m_scrollGestureRegionIsDirty(false)
     90     , m_touchEventTargetRectsAreDirty(false)
     91     , m_shouldScrollOnMainThreadDirty(false)
     92     , m_wasFrameScrollable(false)
     93     , m_lastMainThreadScrollingReasons(0)
     94 {
     95 }
     96 
     97 ScrollingCoordinator::~ScrollingCoordinator()
     98 {
     99 }
    100 
    101 void ScrollingCoordinator::setShouldHandleScrollGestureOnMainThreadRegion(const Region& region)
    102 {
    103     if (!m_page->mainFrame()->isLocalFrame())
    104         return;
    105     if (WebLayer* scrollLayer = toWebLayer(m_page->deprecatedLocalMainFrame()->view()->layerForScrolling())) {
    106         Vector<IntRect> rects = region.rects();
    107         WebVector<WebRect> webRects(rects.size());
    108         for (size_t i = 0; i < rects.size(); ++i)
    109             webRects[i] = rects[i];
    110         scrollLayer->setNonFastScrollableRegion(webRects);
    111     }
    112 }
    113 
    114 void ScrollingCoordinator::notifyLayoutUpdated()
    115 {
    116     m_scrollGestureRegionIsDirty = true;
    117     m_touchEventTargetRectsAreDirty = true;
    118     m_shouldScrollOnMainThreadDirty = true;
    119 }
    120 
    121 void ScrollingCoordinator::updateAfterCompositingChangeIfNeeded()
    122 {
    123     if (!m_page->mainFrame()->isLocalFrame())
    124         return;
    125 
    126     if (!shouldUpdateAfterCompositingChange())
    127         return;
    128 
    129     TRACE_EVENT0("input", "ScrollingCoordinator::updateAfterCompositingChangeIfNeeded");
    130 
    131     if (m_scrollGestureRegionIsDirty) {
    132         // Compute the region of the page where we can't handle scroll gestures and mousewheel events
    133         // on the impl thread. This currently includes:
    134         // 1. All scrollable areas, such as subframes, overflow divs and list boxes, whose composited
    135         // scrolling are not enabled. We need to do this even if the frame view whose layout was updated
    136         // is not the main frame.
    137         // 2. Resize control areas, e.g. the small rect at the right bottom of div/textarea/iframe when
    138         // CSS property "resize" is enabled.
    139         // 3. Plugin areas.
    140         Region shouldHandleScrollGestureOnMainThreadRegion = computeShouldHandleScrollGestureOnMainThreadRegion(m_page->deprecatedLocalMainFrame(), IntPoint());
    141         setShouldHandleScrollGestureOnMainThreadRegion(shouldHandleScrollGestureOnMainThreadRegion);
    142         m_scrollGestureRegionIsDirty = false;
    143     }
    144 
    145     if (m_touchEventTargetRectsAreDirty) {
    146         updateTouchEventTargetRectsIfNeeded();
    147         m_touchEventTargetRectsAreDirty = false;
    148     }
    149 
    150     FrameView* frameView = m_page->deprecatedLocalMainFrame()->view();
    151     bool frameIsScrollable = frameView && frameView->isScrollable();
    152     if (m_shouldScrollOnMainThreadDirty || m_wasFrameScrollable != frameIsScrollable) {
    153         setShouldUpdateScrollLayerPositionOnMainThread(mainThreadScrollingReasons());
    154         m_shouldScrollOnMainThreadDirty = false;
    155     }
    156     m_wasFrameScrollable = frameIsScrollable;
    157 
    158     // The mainFrame view doesn't get included in the FrameTree below, so we
    159     // update its size separately.
    160     if (WebLayer* scrollingWebLayer = frameView ? toWebLayer(frameView->layerForScrolling()) : 0) {
    161         // If there is a fullscreen element, set the scroll bounds to empty so the main frame won't scroll.
    162         Document* mainFrameDocument = m_page->deprecatedLocalMainFrame()->document();
    163         Element* fullscreenElement = Fullscreen::fullscreenElementFrom(*mainFrameDocument);
    164         if (fullscreenElement && fullscreenElement != mainFrameDocument->documentElement())
    165             scrollingWebLayer->setBounds(IntSize());
    166         else
    167             scrollingWebLayer->setBounds(frameView->contentsSize());
    168     }
    169 
    170     const FrameTree& tree = m_page->mainFrame()->tree();
    171     for (const Frame* child = tree.firstChild(); child; child = child->tree().nextSibling()) {
    172         if (!child->isLocalFrame())
    173             continue;
    174         if (WebLayer* scrollLayer = toWebLayer(toLocalFrame(child)->view()->layerForScrolling()))
    175             scrollLayer->setBounds(toLocalFrame(child)->view()->contentsSize());
    176     }
    177 }
    178 
    179 void ScrollingCoordinator::setLayerIsContainerForFixedPositionLayers(GraphicsLayer* layer, bool enable)
    180 {
    181     if (WebLayer* scrollableLayer = toWebLayer(layer))
    182         scrollableLayer->setIsContainerForFixedPositionLayers(enable);
    183 }
    184 
    185 static void clearPositionConstraintExceptForLayer(GraphicsLayer* layer, GraphicsLayer* except)
    186 {
    187     if (layer && layer != except && toWebLayer(layer))
    188         toWebLayer(layer)->setPositionConstraint(WebLayerPositionConstraint());
    189 }
    190 
    191 static WebLayerPositionConstraint computePositionConstraint(const RenderLayer* layer)
    192 {
    193     ASSERT(layer->hasCompositedLayerMapping());
    194     do {
    195         if (layer->renderer()->style()->position() == FixedPosition) {
    196             const RenderObject* fixedPositionObject = layer->renderer();
    197             bool fixedToRight = !fixedPositionObject->style()->right().isAuto();
    198             bool fixedToBottom = !fixedPositionObject->style()->bottom().isAuto();
    199             return WebLayerPositionConstraint::fixedPosition(fixedToRight, fixedToBottom);
    200         }
    201 
    202         layer = layer->parent();
    203 
    204         // Composited layers that inherit a fixed position state will be positioned with respect to the nearest compositedLayerMapping's GraphicsLayer.
    205         // So, once we find a layer that has its own compositedLayerMapping, we can stop searching for a fixed position RenderObject.
    206     } while (layer && !layer->hasCompositedLayerMapping());
    207     return WebLayerPositionConstraint();
    208 }
    209 
    210 void ScrollingCoordinator::updateLayerPositionConstraint(RenderLayer* layer)
    211 {
    212     ASSERT(layer->hasCompositedLayerMapping());
    213     CompositedLayerMapping* compositedLayerMapping = layer->compositedLayerMapping();
    214     GraphicsLayer* mainLayer = compositedLayerMapping->childForSuperlayers();
    215 
    216     // Avoid unnecessary commits
    217     clearPositionConstraintExceptForLayer(compositedLayerMapping->squashingContainmentLayer(), mainLayer);
    218     clearPositionConstraintExceptForLayer(compositedLayerMapping->ancestorClippingLayer(), mainLayer);
    219     clearPositionConstraintExceptForLayer(compositedLayerMapping->mainGraphicsLayer(), mainLayer);
    220 
    221     if (WebLayer* scrollableLayer = toWebLayer(mainLayer))
    222         scrollableLayer->setPositionConstraint(computePositionConstraint(layer));
    223 }
    224 
    225 void ScrollingCoordinator::willDestroyScrollableArea(ScrollableArea* scrollableArea)
    226 {
    227     removeWebScrollbarLayer(scrollableArea, HorizontalScrollbar);
    228     removeWebScrollbarLayer(scrollableArea, VerticalScrollbar);
    229 }
    230 
    231 void ScrollingCoordinator::removeWebScrollbarLayer(ScrollableArea* scrollableArea, ScrollbarOrientation orientation)
    232 {
    233     ScrollbarMap& scrollbars = orientation == HorizontalScrollbar ? m_horizontalScrollbars : m_verticalScrollbars;
    234     if (OwnPtr<WebScrollbarLayer> scrollbarLayer = scrollbars.take(scrollableArea))
    235         GraphicsLayer::unregisterContentsLayer(scrollbarLayer->layer());
    236 }
    237 
    238 static PassOwnPtr<WebScrollbarLayer> createScrollbarLayer(Scrollbar* scrollbar)
    239 {
    240     ScrollbarTheme* theme = scrollbar->theme();
    241     blink::WebScrollbarThemePainter painter(theme, scrollbar);
    242     OwnPtr<blink::WebScrollbarThemeGeometry> geometry(blink::WebScrollbarThemeGeometryNative::create(theme));
    243 
    244     OwnPtr<WebScrollbarLayer> scrollbarLayer = adoptPtr(blink::Platform::current()->compositorSupport()->createScrollbarLayer(new blink::WebScrollbarImpl(scrollbar), painter, geometry.leakPtr()));
    245     GraphicsLayer::registerContentsLayer(scrollbarLayer->layer());
    246     return scrollbarLayer.release();
    247 }
    248 
    249 PassOwnPtr<WebScrollbarLayer> ScrollingCoordinator::createSolidColorScrollbarLayer(ScrollbarOrientation orientation, int thumbThickness, int trackStart, bool isLeftSideVerticalScrollbar)
    250 {
    251     blink::WebScrollbar::Orientation webOrientation = (orientation == HorizontalScrollbar) ? blink::WebScrollbar::Horizontal : blink::WebScrollbar::Vertical;
    252     OwnPtr<WebScrollbarLayer> scrollbarLayer = adoptPtr(blink::Platform::current()->compositorSupport()->createSolidColorScrollbarLayer(webOrientation, thumbThickness, trackStart, isLeftSideVerticalScrollbar));
    253     GraphicsLayer::registerContentsLayer(scrollbarLayer->layer());
    254     return scrollbarLayer.release();
    255 }
    256 
    257 static void detachScrollbarLayer(GraphicsLayer* scrollbarGraphicsLayer)
    258 {
    259     ASSERT(scrollbarGraphicsLayer);
    260 
    261     scrollbarGraphicsLayer->setContentsToPlatformLayer(0);
    262     scrollbarGraphicsLayer->setDrawsContent(true);
    263 }
    264 
    265 static void setupScrollbarLayer(GraphicsLayer* scrollbarGraphicsLayer, WebScrollbarLayer* scrollbarLayer, WebLayer* scrollLayer, WebLayer* containerLayer)
    266 {
    267     ASSERT(scrollbarGraphicsLayer);
    268     ASSERT(scrollbarLayer);
    269 
    270     if (!scrollLayer) {
    271         detachScrollbarLayer(scrollbarGraphicsLayer);
    272         return;
    273     }
    274     scrollbarLayer->setScrollLayer(scrollLayer);
    275     scrollbarLayer->setClipLayer(containerLayer);
    276     scrollbarGraphicsLayer->setContentsToPlatformLayer(scrollbarLayer->layer());
    277     scrollbarGraphicsLayer->setDrawsContent(false);
    278 }
    279 
    280 WebScrollbarLayer* ScrollingCoordinator::addWebScrollbarLayer(ScrollableArea* scrollableArea, ScrollbarOrientation orientation, PassOwnPtr<blink::WebScrollbarLayer> scrollbarLayer)
    281 {
    282     ScrollbarMap& scrollbars = orientation == HorizontalScrollbar ? m_horizontalScrollbars : m_verticalScrollbars;
    283     return scrollbars.add(scrollableArea, scrollbarLayer).storedValue->value.get();
    284 }
    285 
    286 WebScrollbarLayer* ScrollingCoordinator::getWebScrollbarLayer(ScrollableArea* scrollableArea, ScrollbarOrientation orientation)
    287 {
    288     ScrollbarMap& scrollbars = orientation == HorizontalScrollbar ? m_horizontalScrollbars : m_verticalScrollbars;
    289     return scrollbars.get(scrollableArea);
    290 }
    291 
    292 void ScrollingCoordinator::scrollableAreaScrollbarLayerDidChange(ScrollableArea* scrollableArea, ScrollbarOrientation orientation)
    293 {
    294 // FIXME: Instead of hardcode here, we should make a setting flag.
    295 #if OS(MACOSX)
    296     static const bool platformSupportsCoordinatedScrollbar = ScrollAnimatorMac::canUseCoordinatedScrollbar();
    297     static const bool platformSupportsMainFrameOnly = false; // Don't care.
    298 #elif OS(ANDROID)
    299     static const bool platformSupportsCoordinatedScrollbar = true;
    300     static const bool platformSupportsMainFrameOnly = false;
    301 #else
    302     static const bool platformSupportsCoordinatedScrollbar = true;
    303     static const bool platformSupportsMainFrameOnly = true;
    304 #endif
    305     if (!platformSupportsCoordinatedScrollbar)
    306         return;
    307 
    308     bool isMainFrame = isForMainFrame(scrollableArea);
    309     if (!isMainFrame && platformSupportsMainFrameOnly)
    310         return;
    311 
    312     GraphicsLayer* scrollbarGraphicsLayer = orientation == HorizontalScrollbar
    313         ? scrollableArea->layerForHorizontalScrollbar()
    314         : scrollableArea->layerForVerticalScrollbar();
    315 
    316     if (scrollbarGraphicsLayer) {
    317         Scrollbar* scrollbar = orientation == HorizontalScrollbar ? scrollableArea->horizontalScrollbar() : scrollableArea->verticalScrollbar();
    318         if (scrollbar->isCustomScrollbar()) {
    319             detachScrollbarLayer(scrollbarGraphicsLayer);
    320             return;
    321         }
    322 
    323         WebScrollbarLayer* scrollbarLayer = getWebScrollbarLayer(scrollableArea, orientation);
    324         if (!scrollbarLayer) {
    325             Settings* settings = m_page->mainFrame()->settings();
    326 
    327             OwnPtr<WebScrollbarLayer> webScrollbarLayer;
    328             if (settings->useSolidColorScrollbars()) {
    329                 ASSERT(RuntimeEnabledFeatures::overlayScrollbarsEnabled());
    330                 webScrollbarLayer = createSolidColorScrollbarLayer(orientation, scrollbar->theme()->thumbThickness(scrollbar), scrollbar->theme()->trackPosition(scrollbar), scrollableArea->shouldPlaceVerticalScrollbarOnLeft());
    331             } else {
    332                 webScrollbarLayer = createScrollbarLayer(scrollbar);
    333             }
    334             scrollbarLayer = addWebScrollbarLayer(scrollableArea, orientation, webScrollbarLayer.release());
    335         }
    336 
    337         // Root layer non-overlay scrollbars should be marked opaque to disable
    338         // blending.
    339         bool isOpaqueScrollbar = !scrollbar->isOverlayScrollbar();
    340         scrollbarGraphicsLayer->setContentsOpaque(isMainFrame && isOpaqueScrollbar);
    341 
    342         WebLayer* scrollLayer = toWebLayer(scrollableArea->layerForScrolling());
    343         WebLayer* containerLayer = toWebLayer(scrollableArea->layerForContainer());
    344         setupScrollbarLayer(scrollbarGraphicsLayer, scrollbarLayer, scrollLayer, containerLayer);
    345     } else
    346         removeWebScrollbarLayer(scrollableArea, orientation);
    347 }
    348 
    349 bool ScrollingCoordinator::scrollableAreaScrollLayerDidChange(ScrollableArea* scrollableArea)
    350 {
    351     GraphicsLayer* scrollLayer = scrollableArea->layerForScrolling();
    352 
    353     if (scrollLayer) {
    354         ASSERT(m_page);
    355         // With pinch virtual viewport we no longer need to special case the main frame.
    356         bool pinchVirtualViewportEnabled = m_page->settings().pinchVirtualViewportEnabled();
    357         bool layerScrollShouldFireGraphicsLayerDidScroll = isForMainFrame(scrollableArea) && !pinchVirtualViewportEnabled;
    358         scrollLayer->setScrollableArea(scrollableArea, layerScrollShouldFireGraphicsLayerDidScroll);
    359     }
    360 
    361     WebLayer* webLayer = toWebLayer(scrollableArea->layerForScrolling());
    362     WebLayer* containerLayer = toWebLayer(scrollableArea->layerForContainer());
    363     if (webLayer) {
    364         webLayer->setScrollClipLayer(containerLayer);
    365         webLayer->setScrollPosition(IntPoint(scrollableArea->scrollPosition() - scrollableArea->minimumScrollPosition()));
    366         webLayer->setBounds(scrollableArea->contentsSize());
    367         bool canScrollX = scrollableArea->userInputScrollable(HorizontalScrollbar);
    368         bool canScrollY = scrollableArea->userInputScrollable(VerticalScrollbar);
    369         webLayer->setUserScrollable(canScrollX, canScrollY);
    370     }
    371     if (WebScrollbarLayer* scrollbarLayer = getWebScrollbarLayer(scrollableArea, HorizontalScrollbar)) {
    372         GraphicsLayer* horizontalScrollbarLayer = scrollableArea->layerForHorizontalScrollbar();
    373         if (horizontalScrollbarLayer)
    374             setupScrollbarLayer(horizontalScrollbarLayer, scrollbarLayer, webLayer, containerLayer);
    375     }
    376     if (WebScrollbarLayer* scrollbarLayer = getWebScrollbarLayer(scrollableArea, VerticalScrollbar)) {
    377         GraphicsLayer* verticalScrollbarLayer = scrollableArea->layerForVerticalScrollbar();
    378         if (verticalScrollbarLayer)
    379             setupScrollbarLayer(verticalScrollbarLayer, scrollbarLayer, webLayer, containerLayer);
    380     }
    381 
    382     return !!webLayer;
    383 }
    384 
    385 typedef WTF::HashMap<const GraphicsLayer*, Vector<LayoutRect> > GraphicsLayerHitTestRects;
    386 
    387 // In order to do a DFS cross-frame walk of the RenderLayer tree, we need to know which
    388 // RenderLayers have child frames inside of them. This computes a mapping for the
    389 // current frame which we can consult while walking the layers of that frame.
    390 // Whenever we descend into a new frame, a new map will be created.
    391 typedef HashMap<const RenderLayer*, Vector<const LocalFrame*> > LayerFrameMap;
    392 static void makeLayerChildFrameMap(const LocalFrame* currentFrame, LayerFrameMap* map)
    393 {
    394     map->clear();
    395     const FrameTree& tree = currentFrame->tree();
    396     for (const Frame* child = tree.firstChild(); child; child = child->tree().nextSibling()) {
    397         if (!child->isLocalFrame())
    398             continue;
    399         const RenderObject* ownerRenderer = toLocalFrame(child)->ownerRenderer();
    400         if (!ownerRenderer)
    401             continue;
    402         const RenderLayer* containingLayer = ownerRenderer->enclosingLayer();
    403         LayerFrameMap::iterator iter = map->find(containingLayer);
    404         if (iter == map->end())
    405             map->add(containingLayer, Vector<const LocalFrame*>()).storedValue->value.append(toLocalFrame(child));
    406         else
    407             iter->value.append(toLocalFrame(child));
    408     }
    409 }
    410 
    411 static void projectRectsToGraphicsLayerSpaceRecursive(
    412     const RenderLayer* curLayer,
    413     const LayerHitTestRects& layerRects,
    414     GraphicsLayerHitTestRects& graphicsRects,
    415     RenderGeometryMap& geometryMap,
    416     HashSet<const RenderLayer*>& layersWithRects,
    417     LayerFrameMap& layerChildFrameMap)
    418 {
    419     // Project any rects for the current layer
    420     LayerHitTestRects::const_iterator layerIter = layerRects.find(curLayer);
    421     if (layerIter != layerRects.end()) {
    422         // Find the enclosing composited layer when it's in another document (for non-composited iframes).
    423         const RenderLayer* compositedLayer = layerIter->key->enclosingLayerForPaintInvalidationCrossingFrameBoundaries();
    424         ASSERT(compositedLayer);
    425 
    426         // Find the appropriate GraphicsLayer for the composited RenderLayer.
    427         GraphicsLayer* graphicsLayer = compositedLayer->graphicsLayerBackingForScrolling();
    428 
    429         GraphicsLayerHitTestRects::iterator glIter = graphicsRects.find(graphicsLayer);
    430         Vector<LayoutRect>* glRects;
    431         if (glIter == graphicsRects.end())
    432             glRects = &graphicsRects.add(graphicsLayer, Vector<LayoutRect>()).storedValue->value;
    433         else
    434             glRects = &glIter->value;
    435 
    436         // Transform each rect to the co-ordinate space of the graphicsLayer.
    437         for (size_t i = 0; i < layerIter->value.size(); ++i) {
    438             LayoutRect rect = layerIter->value[i];
    439             if (compositedLayer != curLayer) {
    440                 FloatQuad compositorQuad = geometryMap.mapToContainer(rect, compositedLayer->renderer());
    441                 rect = LayoutRect(compositorQuad.boundingBox());
    442                 // If the enclosing composited layer itself is scrolled, we have to undo the subtraction
    443                 // of its scroll offset since we want the offset relative to the scrolling content, not
    444                 // the element itself.
    445                 if (compositedLayer->renderer()->hasOverflowClip())
    446                     rect.move(compositedLayer->renderBox()->scrolledContentOffset());
    447             }
    448             RenderLayer::mapRectToPaintBackingCoordinates(compositedLayer->renderer(), rect);
    449             glRects->append(rect);
    450         }
    451     }
    452 
    453     // Walk child layers of interest
    454     for (const RenderLayer* childLayer = curLayer->firstChild(); childLayer; childLayer = childLayer->nextSibling()) {
    455         if (layersWithRects.contains(childLayer)) {
    456             geometryMap.pushMappingsToAncestor(childLayer, curLayer);
    457             projectRectsToGraphicsLayerSpaceRecursive(childLayer, layerRects, graphicsRects, geometryMap, layersWithRects, layerChildFrameMap);
    458             geometryMap.popMappingsToAncestor(curLayer);
    459         }
    460     }
    461 
    462     // If this layer has any frames of interest as a child of it, walk those (with an updated frame map).
    463     LayerFrameMap::iterator mapIter = layerChildFrameMap.find(curLayer);
    464     if (mapIter != layerChildFrameMap.end()) {
    465         for (size_t i = 0; i < mapIter->value.size(); i++) {
    466             const LocalFrame* childFrame = mapIter->value[i];
    467             const RenderLayer* childLayer = childFrame->view()->renderView()->layer();
    468             if (layersWithRects.contains(childLayer)) {
    469                 LayerFrameMap newLayerChildFrameMap;
    470                 makeLayerChildFrameMap(childFrame, &newLayerChildFrameMap);
    471                 geometryMap.pushMappingsToAncestor(childLayer, curLayer);
    472                 projectRectsToGraphicsLayerSpaceRecursive(childLayer, layerRects, graphicsRects, geometryMap, layersWithRects, newLayerChildFrameMap);
    473                 geometryMap.popMappingsToAncestor(curLayer);
    474             }
    475         }
    476     }
    477 }
    478 
    479 static void projectRectsToGraphicsLayerSpace(LocalFrame* mainFrame, const LayerHitTestRects& layerRects, GraphicsLayerHitTestRects& graphicsRects)
    480 {
    481     TRACE_EVENT0("input", "ScrollingCoordinator::projectRectsToGraphicsLayerSpace");
    482     bool touchHandlerInChildFrame = false;
    483 
    484     // We have a set of rects per RenderLayer, we need to map them to their bounding boxes in their
    485     // enclosing composited layer. To do this most efficiently we'll walk the RenderLayer tree using
    486     // RenderGeometryMap. First record all the branches we should traverse in the tree (including
    487     // all documents on the page).
    488     HashSet<const RenderLayer*> layersWithRects;
    489     for (LayerHitTestRects::const_iterator layerIter = layerRects.begin(); layerIter != layerRects.end(); ++layerIter) {
    490         const RenderLayer* layer = layerIter->key;
    491         do {
    492             if (!layersWithRects.add(layer).isNewEntry)
    493                 break;
    494 
    495             if (layer->parent()) {
    496                 layer = layer->parent();
    497             } else if (RenderObject* parentDocRenderer = layer->renderer()->frame()->ownerRenderer()) {
    498                 layer = parentDocRenderer->enclosingLayer();
    499                 touchHandlerInChildFrame = true;
    500             }
    501         } while (layer);
    502     }
    503 
    504     // Now walk the layer projecting rects while maintaining a RenderGeometryMap
    505     MapCoordinatesFlags flags = UseTransforms;
    506     if (touchHandlerInChildFrame)
    507         flags |= TraverseDocumentBoundaries;
    508     RenderLayer* rootLayer = mainFrame->contentRenderer()->layer();
    509     RenderGeometryMap geometryMap(flags);
    510     geometryMap.pushMappingsToAncestor(rootLayer, 0);
    511     LayerFrameMap layerChildFrameMap;
    512     makeLayerChildFrameMap(mainFrame, &layerChildFrameMap);
    513     projectRectsToGraphicsLayerSpaceRecursive(rootLayer, layerRects, graphicsRects, geometryMap, layersWithRects, layerChildFrameMap);
    514 }
    515 
    516 void ScrollingCoordinator::updateTouchEventTargetRectsIfNeeded()
    517 {
    518     TRACE_EVENT0("input", "ScrollingCoordinator::updateTouchEventTargetRectsIfNeeded");
    519 
    520     if (!RuntimeEnabledFeatures::touchEnabled())
    521         return;
    522 
    523     LayerHitTestRects touchEventTargetRects;
    524     computeTouchEventTargetRects(touchEventTargetRects);
    525     setTouchEventTargetRects(touchEventTargetRects);
    526 }
    527 
    528 void ScrollingCoordinator::reset()
    529 {
    530     for (ScrollbarMap::iterator it = m_horizontalScrollbars.begin(); it != m_horizontalScrollbars.end(); ++it)
    531         GraphicsLayer::unregisterContentsLayer(it->value->layer());
    532     for (ScrollbarMap::iterator it = m_verticalScrollbars.begin(); it != m_verticalScrollbars.end(); ++it)
    533         GraphicsLayer::unregisterContentsLayer(it->value->layer());
    534 
    535     m_horizontalScrollbars.clear();
    536     m_verticalScrollbars.clear();
    537     m_layersWithTouchRects.clear();
    538     m_wasFrameScrollable = false;
    539 
    540     // This is retained for testing.
    541     m_lastMainThreadScrollingReasons = 0;
    542     setShouldUpdateScrollLayerPositionOnMainThread(m_lastMainThreadScrollingReasons);
    543 }
    544 
    545 // Note that in principle this could be called more often than computeTouchEventTargetRects, for
    546 // example during a non-composited scroll (although that's not yet implemented - crbug.com/261307).
    547 void ScrollingCoordinator::setTouchEventTargetRects(LayerHitTestRects& layerRects)
    548 {
    549     TRACE_EVENT0("input", "ScrollingCoordinator::setTouchEventTargetRects");
    550 
    551     // Update the list of layers with touch hit rects.
    552     HashSet<const RenderLayer*> oldLayersWithTouchRects;
    553     m_layersWithTouchRects.swap(oldLayersWithTouchRects);
    554     for (LayerHitTestRects::iterator it = layerRects.begin(); it != layerRects.end(); ++it) {
    555         if (!it->value.isEmpty()) {
    556             const RenderLayer* compositedLayer = it->key->enclosingLayerForPaintInvalidationCrossingFrameBoundaries();
    557             ASSERT(compositedLayer);
    558             m_layersWithTouchRects.add(compositedLayer);
    559         }
    560     }
    561 
    562     // Ensure we have an entry for each composited layer that previously had rects (so that old
    563     // ones will get cleared out). Note that ideally we'd track this on GraphicsLayer instead of
    564     // RenderLayer, but we have no good hook into the lifetime of a GraphicsLayer.
    565     for (HashSet<const RenderLayer*>::iterator it = oldLayersWithTouchRects.begin(); it != oldLayersWithTouchRects.end(); ++it) {
    566         if (!layerRects.contains(*it))
    567             layerRects.add(*it, Vector<LayoutRect>());
    568     }
    569 
    570     GraphicsLayerHitTestRects graphicsLayerRects;
    571     projectRectsToGraphicsLayerSpace(m_page->deprecatedLocalMainFrame(), layerRects, graphicsLayerRects);
    572 
    573     for (GraphicsLayerHitTestRects::const_iterator iter = graphicsLayerRects.begin(); iter != graphicsLayerRects.end(); ++iter) {
    574         const GraphicsLayer* graphicsLayer = iter->key;
    575         WebVector<WebRect> webRects(iter->value.size());
    576         for (size_t i = 0; i < iter->value.size(); ++i)
    577             webRects[i] = enclosingIntRect(iter->value[i]);
    578         graphicsLayer->platformLayer()->setTouchEventHandlerRegion(webRects);
    579     }
    580 }
    581 
    582 void ScrollingCoordinator::touchEventTargetRectsDidChange()
    583 {
    584     if (!RuntimeEnabledFeatures::touchEnabled())
    585         return;
    586 
    587     // Wait until after layout to update.
    588     if (!m_page->deprecatedLocalMainFrame()->view() || m_page->deprecatedLocalMainFrame()->view()->needsLayout())
    589         return;
    590 
    591     // FIXME: scheduleAnimation() is just a method of forcing the compositor to realize that it
    592     // needs to commit here. We should expose a cleaner API for this.
    593     RenderView* renderView = m_page->deprecatedLocalMainFrame()->contentRenderer();
    594     if (renderView && renderView->compositor() && renderView->compositor()->staleInCompositingMode())
    595         m_page->deprecatedLocalMainFrame()->view()->scheduleAnimation();
    596 
    597     m_touchEventTargetRectsAreDirty = true;
    598 }
    599 
    600 void ScrollingCoordinator::updateScrollParentForGraphicsLayer(GraphicsLayer* child, RenderLayer* parent)
    601 {
    602     WebLayer* scrollParentWebLayer = 0;
    603     if (parent && parent->hasCompositedLayerMapping())
    604         scrollParentWebLayer = toWebLayer(parent->compositedLayerMapping()->scrollingContentsLayer());
    605 
    606     child->setScrollParent(scrollParentWebLayer);
    607 }
    608 
    609 void ScrollingCoordinator::updateClipParentForGraphicsLayer(GraphicsLayer* child, RenderLayer* parent)
    610 {
    611     WebLayer* clipParentWebLayer = 0;
    612     if (parent && parent->hasCompositedLayerMapping())
    613         clipParentWebLayer = toWebLayer(parent->compositedLayerMapping()->parentForSublayers());
    614 
    615     child->setClipParent(clipParentWebLayer);
    616 }
    617 
    618 void ScrollingCoordinator::willDestroyRenderLayer(RenderLayer* layer)
    619 {
    620     m_layersWithTouchRects.remove(layer);
    621 }
    622 
    623 void ScrollingCoordinator::updateHaveWheelEventHandlers()
    624 {
    625     ASSERT(isMainThread());
    626     ASSERT(m_page);
    627     if (!m_page->mainFrame()->isLocalFrame() || !m_page->deprecatedLocalMainFrame()->view())
    628         return;
    629 
    630     if (WebLayer* scrollLayer = toWebLayer(m_page->deprecatedLocalMainFrame()->view()->layerForScrolling())) {
    631         bool haveHandlers = m_page->frameHost().eventHandlerRegistry().hasEventHandlers(EventHandlerRegistry::WheelEvent);
    632         scrollLayer->setHaveWheelEventHandlers(haveHandlers);
    633     }
    634 }
    635 
    636 void ScrollingCoordinator::updateHaveScrollEventHandlers()
    637 {
    638     ASSERT(isMainThread());
    639     ASSERT(m_page);
    640     if (!m_page->mainFrame()->isLocalFrame() || !m_page->deprecatedLocalMainFrame()->view())
    641         return;
    642 
    643     // Currently the compositor only cares whether there are scroll handlers anywhere on the page
    644     // instead on a per-layer basis. We therefore only update this information for the root
    645     // scrolling layer.
    646     if (WebLayer* scrollLayer = toWebLayer(m_page->deprecatedLocalMainFrame()->view()->layerForScrolling())) {
    647         bool haveHandlers = m_page->frameHost().eventHandlerRegistry().hasEventHandlers(EventHandlerRegistry::ScrollEvent);
    648         scrollLayer->setHaveScrollEventHandlers(haveHandlers);
    649     }
    650 }
    651 
    652 void ScrollingCoordinator::setShouldUpdateScrollLayerPositionOnMainThread(MainThreadScrollingReasons reasons)
    653 {
    654     if (!m_page->mainFrame()->isLocalFrame())
    655         return;
    656     if (WebLayer* scrollLayer = toWebLayer(m_page->deprecatedLocalMainFrame()->view()->layerForScrolling())) {
    657         m_lastMainThreadScrollingReasons = reasons;
    658         scrollLayer->setShouldScrollOnMainThread(reasons);
    659     }
    660 }
    661 
    662 void ScrollingCoordinator::willBeDestroyed()
    663 {
    664     ASSERT(m_page);
    665     m_page = 0;
    666     for (ScrollbarMap::iterator it = m_horizontalScrollbars.begin(); it != m_horizontalScrollbars.end(); ++it)
    667         GraphicsLayer::unregisterContentsLayer(it->value->layer());
    668     for (ScrollbarMap::iterator it = m_verticalScrollbars.begin(); it != m_verticalScrollbars.end(); ++it)
    669         GraphicsLayer::unregisterContentsLayer(it->value->layer());
    670 }
    671 
    672 bool ScrollingCoordinator::coordinatesScrollingForFrameView(FrameView* frameView) const
    673 {
    674     ASSERT(isMainThread());
    675     ASSERT(m_page);
    676 
    677     // We currently only handle the main frame.
    678     if (&frameView->frame() != m_page->mainFrame())
    679         return false;
    680 
    681     if (!m_page->mainFrame()->isLocalFrame())
    682         return false;
    683 
    684     // We currently only support composited mode.
    685     RenderView* renderView = m_page->deprecatedLocalMainFrame()->contentRenderer();
    686     if (!renderView)
    687         return false;
    688     return renderView->usesCompositing();
    689 }
    690 
    691 Region ScrollingCoordinator::computeShouldHandleScrollGestureOnMainThreadRegion(const LocalFrame* frame, const IntPoint& frameLocation) const
    692 {
    693     Region shouldHandleScrollGestureOnMainThreadRegion;
    694     FrameView* frameView = frame->view();
    695     if (!frameView)
    696         return shouldHandleScrollGestureOnMainThreadRegion;
    697 
    698     IntPoint offset = frameLocation;
    699     offset.moveBy(frameView->frameRect().location());
    700 
    701     if (const FrameView::ScrollableAreaSet* scrollableAreas = frameView->scrollableAreas()) {
    702         for (FrameView::ScrollableAreaSet::const_iterator it = scrollableAreas->begin(), end = scrollableAreas->end(); it != end; ++it) {
    703             ScrollableArea* scrollableArea = *it;
    704             // Composited scrollable areas can be scrolled off the main thread.
    705             if (scrollableArea->usesCompositedScrolling())
    706                 continue;
    707             IntRect box = scrollableArea->scrollableAreaBoundingBox();
    708             box.moveBy(offset);
    709             shouldHandleScrollGestureOnMainThreadRegion.unite(box);
    710         }
    711     }
    712 
    713     // We use GestureScrollBegin/Update/End for moving the resizer handle. So we mark these
    714     // small resizer areas as non-fast-scrollable to allow the scroll gestures to be passed to
    715     // main thread if they are targeting the resizer area. (Resizing is done in EventHandler.cpp
    716     // on main thread).
    717     if (const FrameView::ResizerAreaSet* resizerAreas = frameView->resizerAreas()) {
    718         for (FrameView::ResizerAreaSet::const_iterator it = resizerAreas->begin(), end = resizerAreas->end(); it != end; ++it) {
    719             RenderBox* box = *it;
    720             IntRect bounds = box->absoluteBoundingBoxRect();
    721             IntRect corner = box->layer()->scrollableArea()->touchResizerCornerRect(bounds);
    722             corner.moveBy(offset);
    723             shouldHandleScrollGestureOnMainThreadRegion.unite(corner);
    724         }
    725     }
    726 
    727     if (const HashSet<RefPtr<Widget> >* children = frameView->children()) {
    728         for (HashSet<RefPtr<Widget> >::const_iterator it = children->begin(), end = children->end(); it != end; ++it) {
    729             if (!(*it)->isPluginView())
    730                 continue;
    731 
    732             PluginView* pluginView = toPluginView(it->get());
    733             if (pluginView->wantsWheelEvents())
    734                 shouldHandleScrollGestureOnMainThreadRegion.unite(pluginView->frameRect());
    735         }
    736     }
    737 
    738     const FrameTree& tree = frame->tree();
    739     for (Frame* subFrame = tree.firstChild(); subFrame; subFrame = subFrame->tree().nextSibling()) {
    740         if (subFrame->isLocalFrame())
    741             shouldHandleScrollGestureOnMainThreadRegion.unite(computeShouldHandleScrollGestureOnMainThreadRegion(toLocalFrame(subFrame), offset));
    742     }
    743 
    744     return shouldHandleScrollGestureOnMainThreadRegion;
    745 }
    746 
    747 static void accumulateDocumentTouchEventTargetRects(LayerHitTestRects& rects, const Document* document)
    748 {
    749     ASSERT(document);
    750     const EventTargetSet* targets = document->frameHost()->eventHandlerRegistry().eventHandlerTargets(EventHandlerRegistry::TouchEvent);
    751     if (!targets)
    752         return;
    753 
    754     // If there's a handler on the window, document, html or body element (fairly common in practice),
    755     // then we can quickly mark the entire document and skip looking at any other handlers.
    756     // Note that technically a handler on the body doesn't cover the whole document, but it's
    757     // reasonable to be conservative and report the whole document anyway.
    758     //
    759     // Fullscreen HTML5 video when OverlayFullscreenVideo is enabled is implemented by replacing the
    760     // root cc::layer with the video layer so doing this optimization causes the compositor to think
    761     // that there are no handlers, therefore skip it.
    762     if (!document->renderView()->compositor()->inOverlayFullscreenVideo()) {
    763         for (EventTargetSet::const_iterator iter = targets->begin(); iter != targets->end(); ++iter) {
    764             EventTarget* target = iter->key;
    765             Node* node = target->toNode();
    766             if (target->toDOMWindow() || node == document || node == document->documentElement() || node == document->body()) {
    767                 if (RenderView* rendererView = document->renderView()) {
    768                     rendererView->computeLayerHitTestRects(rects);
    769                 }
    770                 return;
    771             }
    772         }
    773     }
    774 
    775     for (EventTargetSet::const_iterator iter = targets->begin(); iter != targets->end(); ++iter) {
    776         EventTarget* target = iter->key;
    777         Node* node = target->toNode();
    778         if (!node || !node->inDocument())
    779             continue;
    780 
    781         // If the document belongs to an invisible subframe it does not have a composited layer
    782         // and should be skipped.
    783         if (node->document().isInInvisibleSubframe())
    784             continue;
    785 
    786         if (node->isDocumentNode() && node != document) {
    787             accumulateDocumentTouchEventTargetRects(rects, toDocument(node));
    788         } else if (RenderObject* renderer = node->renderer()) {
    789             // If the set also contains one of our ancestor nodes then processing
    790             // this node would be redundant.
    791             bool hasTouchEventTargetAncestor = false;
    792             for (Node* ancestor = node->parentNode(); ancestor && !hasTouchEventTargetAncestor; ancestor = ancestor->parentNode()) {
    793                 if (targets->contains(ancestor))
    794                     hasTouchEventTargetAncestor = true;
    795             }
    796             if (!hasTouchEventTargetAncestor) {
    797                 // Walk up the tree to the outermost non-composited scrollable layer.
    798                 RenderLayer* enclosingNonCompositedScrollLayer = 0;
    799                 for (RenderLayer* parent = renderer->enclosingLayer(); parent && parent->compositingState() == NotComposited; parent = parent->parent()) {
    800                     if (parent->scrollsOverflow())
    801                         enclosingNonCompositedScrollLayer = parent;
    802                 }
    803 
    804                 // Report the whole non-composited scroll layer as a touch hit rect because any
    805                 // rects inside of it may move around relative to their enclosing composited layer
    806                 // without causing the rects to be recomputed. Non-composited scrolling occurs on
    807                 // the main thread, so we're not getting much benefit from compositor touch hit
    808                 // testing in this case anyway.
    809                 if (enclosingNonCompositedScrollLayer)
    810                     enclosingNonCompositedScrollLayer->computeSelfHitTestRects(rects);
    811 
    812                 renderer->computeLayerHitTestRects(rects);
    813             }
    814         }
    815     }
    816 }
    817 
    818 void ScrollingCoordinator::computeTouchEventTargetRects(LayerHitTestRects& rects)
    819 {
    820     TRACE_EVENT0("input", "ScrollingCoordinator::computeTouchEventTargetRects");
    821     ASSERT(RuntimeEnabledFeatures::touchEnabled());
    822 
    823     Document* document = m_page->deprecatedLocalMainFrame()->document();
    824     if (!document || !document->view())
    825         return;
    826 
    827     accumulateDocumentTouchEventTargetRects(rects, document);
    828 }
    829 
    830 void ScrollingCoordinator::frameViewHasSlowRepaintObjectsDidChange(FrameView* frameView)
    831 {
    832     ASSERT(isMainThread());
    833     ASSERT(m_page);
    834 
    835     if (!coordinatesScrollingForFrameView(frameView))
    836         return;
    837 
    838     m_shouldScrollOnMainThreadDirty = true;
    839 }
    840 
    841 void ScrollingCoordinator::frameViewFixedObjectsDidChange(FrameView* frameView)
    842 {
    843     ASSERT(isMainThread());
    844     ASSERT(m_page);
    845 
    846     if (!coordinatesScrollingForFrameView(frameView))
    847         return;
    848 
    849     m_shouldScrollOnMainThreadDirty = true;
    850 }
    851 
    852 bool ScrollingCoordinator::isForMainFrame(ScrollableArea* scrollableArea) const
    853 {
    854     return m_page->mainFrame()->isLocalFrame() ? scrollableArea == m_page->deprecatedLocalMainFrame()->view() : false;
    855 }
    856 
    857 void ScrollingCoordinator::frameViewRootLayerDidChange(FrameView* frameView)
    858 {
    859     ASSERT(isMainThread());
    860     ASSERT(m_page);
    861 
    862     if (!coordinatesScrollingForFrameView(frameView))
    863         return;
    864 
    865     notifyLayoutUpdated();
    866     updateHaveWheelEventHandlers();
    867     updateHaveScrollEventHandlers();
    868 }
    869 
    870 #if OS(MACOSX)
    871 void ScrollingCoordinator::handleWheelEventPhase(PlatformWheelEventPhase phase)
    872 {
    873     ASSERT(isMainThread());
    874 
    875     if (!m_page)
    876         return;
    877 
    878     FrameView* frameView = m_page->deprecatedLocalMainFrame()->view();
    879     if (!frameView)
    880         return;
    881 
    882     frameView->scrollAnimator()->handleWheelEventPhase(phase);
    883 }
    884 #endif
    885 
    886 bool ScrollingCoordinator::hasVisibleSlowRepaintViewportConstrainedObjects(FrameView* frameView) const
    887 {
    888     const FrameView::ViewportConstrainedObjectSet* viewportConstrainedObjects = frameView->viewportConstrainedObjects();
    889     if (!viewportConstrainedObjects)
    890         return false;
    891 
    892     for (FrameView::ViewportConstrainedObjectSet::const_iterator it = viewportConstrainedObjects->begin(), end = viewportConstrainedObjects->end(); it != end; ++it) {
    893         RenderObject* renderer = *it;
    894         ASSERT(renderer->isBoxModelObject() && renderer->hasLayer());
    895         ASSERT(renderer->style()->position() == FixedPosition);
    896         RenderLayer* layer = toRenderBoxModelObject(renderer)->layer();
    897 
    898         // Whether the RenderLayer scrolls with the viewport is a tree-depenent
    899         // property and our viewportConstrainedObjects collection is maintained
    900         // with only RenderObject-level information.
    901         if (!layer->scrollsWithViewport())
    902             continue;
    903 
    904         // If the whole subtree is invisible, there's no reason to scroll on
    905         // the main thread because we don't need to generate invalidations
    906         // for invisible content.
    907         if (layer->subtreeIsInvisible())
    908             continue;
    909 
    910         // We're only smart enough to scroll viewport-constrainted objects
    911         // in the compositor if they have their own backing or they paint
    912         // into a grouped back (which necessarily all have the same viewport
    913         // constraints).
    914         CompositingState compositingState = layer->compositingState();
    915         if (compositingState != PaintsIntoOwnBacking && compositingState != PaintsIntoGroupedBacking)
    916             return true;
    917     }
    918     return false;
    919 }
    920 
    921 MainThreadScrollingReasons ScrollingCoordinator::mainThreadScrollingReasons() const
    922 {
    923     MainThreadScrollingReasons reasons = static_cast<MainThreadScrollingReasons>(0);
    924 
    925     if (!m_page->settings().threadedScrollingEnabled())
    926         reasons |= ThreadedScrollingDisabled;
    927 
    928     if (!m_page->mainFrame()->isLocalFrame())
    929         return reasons;
    930     FrameView* frameView = m_page->deprecatedLocalMainFrame()->view();
    931     if (!frameView)
    932         return reasons;
    933 
    934     if (frameView->hasSlowRepaintObjects())
    935         reasons |= HasSlowRepaintObjects;
    936     FrameView::ScrollingReasons scrollingReasons = frameView->scrollingReasons();
    937     const bool mayBeScrolledByInput = (scrollingReasons == FrameView::Scrollable);
    938     const bool mayBeScrolledByScript = mayBeScrolledByInput || (scrollingReasons ==
    939         FrameView::NotScrollableExplicitlyDisabled);
    940 
    941     // TODO(awoloszyn) Currently crbug.com/304810 will let certain
    942     // overflow:hidden elements scroll on the compositor thread, so we should
    943     // not let this move there path as an optimization, when we have slow-repaint
    944     // elements.
    945     if (mayBeScrolledByScript && hasVisibleSlowRepaintViewportConstrainedObjects(frameView)) {
    946         reasons |= HasNonLayerViewportConstrainedObjects;
    947     }
    948 
    949     return reasons;
    950 }
    951 
    952 String ScrollingCoordinator::mainThreadScrollingReasonsAsText(MainThreadScrollingReasons reasons)
    953 {
    954     StringBuilder stringBuilder;
    955 
    956     if (reasons & ScrollingCoordinator::HasSlowRepaintObjects)
    957         stringBuilder.appendLiteral("Has slow repaint objects, ");
    958     if (reasons & ScrollingCoordinator::HasViewportConstrainedObjectsWithoutSupportingFixedLayers)
    959         stringBuilder.appendLiteral("Has viewport constrained objects without supporting fixed layers, ");
    960     if (reasons & ScrollingCoordinator::HasNonLayerViewportConstrainedObjects)
    961         stringBuilder.appendLiteral("Has non-layer viewport-constrained objects, ");
    962     if (reasons & ScrollingCoordinator::ThreadedScrollingDisabled)
    963         stringBuilder.appendLiteral("Threaded scrolling is disabled, ");
    964 
    965     if (stringBuilder.length())
    966         stringBuilder.resize(stringBuilder.length() - 2);
    967     return stringBuilder.toString();
    968 }
    969 
    970 String ScrollingCoordinator::mainThreadScrollingReasonsAsText() const
    971 {
    972     ASSERT(m_page->deprecatedLocalMainFrame()->document()->lifecycle().state() >= DocumentLifecycle::CompositingClean);
    973     return mainThreadScrollingReasonsAsText(m_lastMainThreadScrollingReasons);
    974 }
    975 
    976 bool ScrollingCoordinator::frameViewIsDirty() const
    977 {
    978     FrameView* frameView = m_page->mainFrame()->isLocalFrame() ? m_page->deprecatedLocalMainFrame()->view() : 0;
    979     bool frameIsScrollable = frameView && frameView->isScrollable();
    980     if (frameIsScrollable != m_wasFrameScrollable)
    981         return true;
    982 
    983     if (WebLayer* scrollLayer = frameView ? toWebLayer(frameView->layerForScrolling()) : 0)
    984         return blink::WebSize(frameView->contentsSize()) != scrollLayer->bounds();
    985     return false;
    986 }
    987 
    988 } // namespace blink
    989