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