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 "RuntimeEnabledFeatures.h"
     31 #include "core/dom/Document.h"
     32 #include "core/dom/Node.h"
     33 #include "core/html/HTMLElement.h"
     34 #include "core/page/Frame.h"
     35 #include "core/page/FrameView.h"
     36 #include "core/page/Page.h"
     37 #include "core/page/Settings.h"
     38 #include "core/platform/PlatformWheelEvent.h"
     39 #include "core/platform/ScrollAnimator.h"
     40 #include "core/platform/ScrollbarTheme.h"
     41 #include "core/platform/chromium/TraceEvent.h"
     42 #include "core/platform/chromium/support/WebScrollbarImpl.h"
     43 #include "core/platform/chromium/support/WebScrollbarThemeGeometryNative.h"
     44 #include "core/platform/graphics/GraphicsLayer.h"
     45 #include "core/platform/graphics/IntRect.h"
     46 #include "core/platform/graphics/Region.h"
     47 #include "core/platform/graphics/transforms/TransformState.h"
     48 #if OS(DARWIN)
     49 #include "core/platform/mac/ScrollAnimatorMac.h"
     50 #endif
     51 #include "core/plugins/PluginView.h"
     52 #include "core/rendering/RenderLayerBacking.h"
     53 #include "core/rendering/RenderLayerCompositor.h"
     54 #include "core/rendering/RenderView.h"
     55 #include "public/platform/Platform.h"
     56 #include "public/platform/WebCompositorSupport.h"
     57 #include "public/platform/WebLayerPositionConstraint.h"
     58 #include "public/platform/WebScrollbarLayer.h"
     59 #include "public/platform/WebScrollbarThemeGeometry.h"
     60 #include "public/platform/WebScrollbarThemePainter.h"
     61 #include "wtf/text/StringBuilder.h"
     62 
     63 using WebKit::WebLayer;
     64 using WebKit::WebLayerPositionConstraint;
     65 using WebKit::WebRect;
     66 using WebKit::WebScrollbarLayer;
     67 using WebKit::WebVector;
     68 
     69 
     70 namespace WebCore {
     71 
     72 static WebLayer* scrollingWebLayerForGraphicsLayer(GraphicsLayer* layer)
     73 {
     74     return layer->platformLayer();
     75 }
     76 
     77 WebLayer* ScrollingCoordinator::scrollingWebLayerForScrollableArea(ScrollableArea* scrollableArea)
     78 {
     79     GraphicsLayer* graphicsLayer = scrollLayerForScrollableArea(scrollableArea);
     80     return graphicsLayer ? scrollingWebLayerForGraphicsLayer(graphicsLayer) : 0;
     81 }
     82 
     83 PassRefPtr<ScrollingCoordinator> ScrollingCoordinator::create(Page* page)
     84 {
     85     return adoptRef(new ScrollingCoordinator(page));
     86 }
     87 
     88 ScrollingCoordinator::ScrollingCoordinator(Page* page)
     89     : m_page(page)
     90 {
     91 }
     92 
     93 ScrollingCoordinator::~ScrollingCoordinator()
     94 {
     95     ASSERT(!m_page);
     96     for (ScrollbarMap::iterator it = m_horizontalScrollbars.begin(); it != m_horizontalScrollbars.end(); ++it)
     97         GraphicsLayer::unregisterContentsLayer(it->value->layer());
     98     for (ScrollbarMap::iterator it = m_verticalScrollbars.begin(); it != m_verticalScrollbars.end(); ++it)
     99         GraphicsLayer::unregisterContentsLayer(it->value->layer());
    100 
    101 }
    102 
    103 bool ScrollingCoordinator::touchHitTestingEnabled() const
    104 {
    105     RenderView* contentRenderer = m_page->mainFrame()->contentRenderer();
    106     Settings* settings = m_page->mainFrame()->document()->settings();
    107     return RuntimeEnabledFeatures::touchEnabled() && settings->compositorTouchHitTesting() && contentRenderer && contentRenderer->usesCompositing();
    108 }
    109 
    110 void ScrollingCoordinator::setShouldHandleScrollGestureOnMainThreadRegion(const Region& region)
    111 {
    112     if (WebLayer* scrollLayer = scrollingWebLayerForScrollableArea(m_page->mainFrame()->view())) {
    113         Vector<IntRect> rects = region.rects();
    114         WebVector<WebRect> webRects(rects.size());
    115         for (size_t i = 0; i < rects.size(); ++i)
    116             webRects[i] = rects[i];
    117         scrollLayer->setNonFastScrollableRegion(webRects);
    118     }
    119 }
    120 
    121 void ScrollingCoordinator::frameViewLayoutUpdated(FrameView* frameView)
    122 {
    123     TRACE_EVENT0("input", "ScrollingCoordinator::frameViewLayoutUpdated");
    124 
    125     // Compute the region of the page where we can't handle scroll gestures and mousewheel events
    126     // on the impl thread. This currently includes:
    127     // 1. All scrollable areas, such as subframes, overflow divs and list boxes, whose composited
    128     // scrolling are not enabled. We need to do this even if the frame view whose layout was updated
    129     // is not the main frame.
    130     // 2. Resize control areas, e.g. the small rect at the right bottom of div/textarea/iframe when
    131     // CSS property "resize" is enabled.
    132     // 3. Plugin areas.
    133     Region shouldHandleScrollGestureOnMainThreadRegion = computeShouldHandleScrollGestureOnMainThreadRegion(m_page->mainFrame(), IntPoint());
    134     setShouldHandleScrollGestureOnMainThreadRegion(shouldHandleScrollGestureOnMainThreadRegion);
    135 
    136     if (touchHitTestingEnabled()) {
    137         LayerHitTestRects touchEventTargetRects;
    138         computeTouchEventTargetRects(touchEventTargetRects);
    139         setTouchEventTargetRects(touchEventTargetRects);
    140     }
    141 
    142     if (WebLayer* scrollLayer = scrollingWebLayerForScrollableArea(frameView))
    143         scrollLayer->setBounds(frameView->contentsSize());
    144 }
    145 
    146 void ScrollingCoordinator::setLayerIsContainerForFixedPositionLayers(GraphicsLayer* layer, bool enable)
    147 {
    148     if (WebLayer* scrollableLayer = scrollingWebLayerForGraphicsLayer(layer))
    149         scrollableLayer->setIsContainerForFixedPositionLayers(enable);
    150 }
    151 
    152 static void clearPositionConstraintExceptForLayer(GraphicsLayer* layer, GraphicsLayer* except)
    153 {
    154     if (layer && layer != except && scrollingWebLayerForGraphicsLayer(layer))
    155         scrollingWebLayerForGraphicsLayer(layer)->setPositionConstraint(WebLayerPositionConstraint());
    156 }
    157 
    158 static WebLayerPositionConstraint computePositionConstraint(const RenderLayer* layer)
    159 {
    160     ASSERT(layer->isComposited());
    161     do {
    162         if (layer->renderer()->style()->position() == FixedPosition) {
    163             const RenderObject* fixedPositionObject = layer->renderer();
    164             bool fixedToRight = !fixedPositionObject->style()->right().isAuto();
    165             bool fixedToBottom = !fixedPositionObject->style()->bottom().isAuto();
    166             return WebLayerPositionConstraint::fixedPosition(fixedToRight, fixedToBottom);
    167         }
    168 
    169         layer = layer->parent();
    170     } while (layer && !layer->isComposited());
    171     return WebLayerPositionConstraint();
    172 }
    173 
    174 void ScrollingCoordinator::updateLayerPositionConstraint(RenderLayer* layer)
    175 {
    176     ASSERT(layer->backing());
    177     RenderLayerBacking* backing = layer->backing();
    178     GraphicsLayer* mainLayer = backing->childForSuperlayers();
    179 
    180     // Avoid unnecessary commits
    181     clearPositionConstraintExceptForLayer(backing->ancestorClippingLayer(), mainLayer);
    182     clearPositionConstraintExceptForLayer(backing->graphicsLayer(), mainLayer);
    183 
    184     if (WebLayer* scrollableLayer = scrollingWebLayerForGraphicsLayer(mainLayer))
    185         scrollableLayer->setPositionConstraint(computePositionConstraint(layer));
    186 }
    187 
    188 void ScrollingCoordinator::willDestroyScrollableArea(ScrollableArea* scrollableArea)
    189 {
    190     removeWebScrollbarLayer(scrollableArea, HorizontalScrollbar);
    191     removeWebScrollbarLayer(scrollableArea, VerticalScrollbar);
    192 }
    193 
    194 void ScrollingCoordinator::removeWebScrollbarLayer(ScrollableArea* scrollableArea, ScrollbarOrientation orientation)
    195 {
    196     ScrollbarMap& scrollbars = orientation == HorizontalScrollbar ? m_horizontalScrollbars : m_verticalScrollbars;
    197     if (OwnPtr<WebScrollbarLayer> scrollbarLayer = scrollbars.take(scrollableArea))
    198         GraphicsLayer::unregisterContentsLayer(scrollbarLayer->layer());
    199 }
    200 
    201 static PassOwnPtr<WebScrollbarLayer> createScrollbarLayer(Scrollbar* scrollbar)
    202 {
    203     ScrollbarTheme* theme = scrollbar->theme();
    204     WebKit::WebScrollbarThemePainter painter(theme, scrollbar);
    205     OwnPtr<WebKit::WebScrollbarThemeGeometry> geometry(WebKit::WebScrollbarThemeGeometryNative::create(theme));
    206 
    207     OwnPtr<WebScrollbarLayer> scrollbarLayer = adoptPtr(WebKit::Platform::current()->compositorSupport()->createScrollbarLayer(new WebKit::WebScrollbarImpl(scrollbar), painter, geometry.leakPtr()));
    208     GraphicsLayer::registerContentsLayer(scrollbarLayer->layer());
    209     return scrollbarLayer.release();
    210 }
    211 
    212 static void detachScrollbarLayer(GraphicsLayer* scrollbarGraphicsLayer)
    213 {
    214     ASSERT(scrollbarGraphicsLayer);
    215 
    216     scrollbarGraphicsLayer->setContentsToPlatformLayer(0);
    217     scrollbarGraphicsLayer->setDrawsContent(true);
    218 }
    219 
    220 static void setupScrollbarLayer(GraphicsLayer* scrollbarGraphicsLayer, WebScrollbarLayer* scrollbarLayer, WebLayer* scrollLayer)
    221 {
    222     ASSERT(scrollbarGraphicsLayer);
    223     ASSERT(scrollbarLayer);
    224 
    225     if (!scrollLayer) {
    226         detachScrollbarLayer(scrollbarGraphicsLayer);
    227         return;
    228     }
    229     scrollbarLayer->setScrollLayer(scrollLayer);
    230     scrollbarGraphicsLayer->setContentsToPlatformLayer(scrollbarLayer->layer());
    231     scrollbarGraphicsLayer->setDrawsContent(false);
    232 }
    233 
    234 WebScrollbarLayer* ScrollingCoordinator::addWebScrollbarLayer(ScrollableArea* scrollableArea, ScrollbarOrientation orientation, PassOwnPtr<WebKit::WebScrollbarLayer> scrollbarLayer)
    235 {
    236     ScrollbarMap& scrollbars = orientation == HorizontalScrollbar ? m_horizontalScrollbars : m_verticalScrollbars;
    237     return scrollbars.add(scrollableArea, scrollbarLayer).iterator->value.get();
    238 }
    239 
    240 WebScrollbarLayer* ScrollingCoordinator::getWebScrollbarLayer(ScrollableArea* scrollableArea, ScrollbarOrientation orientation)
    241 {
    242     ScrollbarMap& scrollbars = orientation == HorizontalScrollbar ? m_horizontalScrollbars : m_verticalScrollbars;
    243     return scrollbars.get(scrollableArea);
    244 }
    245 
    246 void ScrollingCoordinator::scrollableAreaScrollbarLayerDidChange(ScrollableArea* scrollableArea, ScrollbarOrientation orientation)
    247 {
    248 // FIXME: Instead of hardcode here, we should make a setting flag.
    249 #if OS(DARWIN)
    250     static const bool platformSupportsCoordinatedScrollbar = ScrollAnimatorMac::canUseCoordinatedScrollbar();
    251     static const bool platformSupportsMainFrameOnly = false; // Don't care.
    252 #elif OS(ANDROID)
    253     static const bool platformSupportsCoordinatedScrollbar = true;
    254     static const bool platformSupportsMainFrameOnly = false;
    255 #else
    256     static const bool platformSupportsCoordinatedScrollbar = true;
    257     static const bool platformSupportsMainFrameOnly = true;
    258 #endif
    259     if (!platformSupportsCoordinatedScrollbar)
    260         return;
    261 
    262     bool isMainFrame = isForMainFrame(scrollableArea);
    263     if (!isMainFrame && platformSupportsMainFrameOnly)
    264         return;
    265 
    266     GraphicsLayer* scrollbarGraphicsLayer = orientation == HorizontalScrollbar ? horizontalScrollbarLayerForScrollableArea(scrollableArea) : verticalScrollbarLayerForScrollableArea(scrollableArea);
    267     if (scrollbarGraphicsLayer) {
    268         Scrollbar* scrollbar = orientation == HorizontalScrollbar ? scrollableArea->horizontalScrollbar() : scrollableArea->verticalScrollbar();
    269         if (scrollbar->isCustomScrollbar()) {
    270             detachScrollbarLayer(scrollbarGraphicsLayer);
    271             return;
    272         }
    273 
    274         WebScrollbarLayer* scrollbarLayer = getWebScrollbarLayer(scrollableArea, orientation);
    275         if (!scrollbarLayer)
    276             scrollbarLayer = addWebScrollbarLayer(scrollableArea, orientation, createScrollbarLayer(scrollbar));
    277 
    278         // Root layer non-overlay scrollbars should be marked opaque to disable
    279         // blending.
    280         bool isOpaqueScrollbar = !scrollbar->isOverlayScrollbar();
    281         if (!scrollbarGraphicsLayer->contentsOpaque())
    282             scrollbarGraphicsLayer->setContentsOpaque(isMainFrame && isOpaqueScrollbar);
    283         scrollbarLayer->layer()->setOpaque(scrollbarGraphicsLayer->contentsOpaque());
    284 
    285         setupScrollbarLayer(scrollbarGraphicsLayer, scrollbarLayer, scrollingWebLayerForScrollableArea(scrollableArea));
    286     } else
    287         removeWebScrollbarLayer(scrollableArea, orientation);
    288 }
    289 
    290 bool ScrollingCoordinator::scrollableAreaScrollLayerDidChange(ScrollableArea* scrollableArea)
    291 {
    292     GraphicsLayer* scrollLayer = scrollLayerForScrollableArea(scrollableArea);
    293     if (scrollLayer) {
    294         bool isMainFrame = isForMainFrame(scrollableArea);
    295         scrollLayer->setScrollableArea(scrollableArea, isMainFrame);
    296     }
    297 
    298     WebLayer* webLayer = scrollingWebLayerForScrollableArea(scrollableArea);
    299     if (webLayer) {
    300         webLayer->setScrollable(true);
    301         webLayer->setScrollPosition(IntPoint(scrollableArea->scrollPosition() - scrollableArea->minimumScrollPosition()));
    302         webLayer->setMaxScrollPosition(IntSize(scrollableArea->scrollSize(HorizontalScrollbar), scrollableArea->scrollSize(VerticalScrollbar)));
    303     }
    304     if (WebScrollbarLayer* scrollbarLayer = getWebScrollbarLayer(scrollableArea, HorizontalScrollbar)) {
    305         GraphicsLayer* horizontalScrollbarLayer = horizontalScrollbarLayerForScrollableArea(scrollableArea);
    306         if (horizontalScrollbarLayer)
    307             setupScrollbarLayer(horizontalScrollbarLayer, scrollbarLayer, webLayer);
    308     }
    309     if (WebScrollbarLayer* scrollbarLayer = getWebScrollbarLayer(scrollableArea, VerticalScrollbar)) {
    310         GraphicsLayer* verticalScrollbarLayer = verticalScrollbarLayerForScrollableArea(scrollableArea);
    311         if (verticalScrollbarLayer)
    312             setupScrollbarLayer(verticalScrollbarLayer, scrollbarLayer, webLayer);
    313     }
    314 
    315     return !!webLayer;
    316 }
    317 
    318 static void convertLayerRectsToEnclosingCompositedLayer(const LayerHitTestRects& layerRects, LayerHitTestRects& compositorRects)
    319 {
    320     TRACE_EVENT0("input", "ScrollingCoordinator::convertLayerRectsToEnclosingCompositedLayer");
    321 
    322     // We have a set of rects per RenderLayer, we need to map them to their bounding boxes in their
    323     // enclosing composited layer.
    324     for (LayerHitTestRects::const_iterator layerIter = layerRects.begin(); layerIter != layerRects.end(); ++layerIter) {
    325         // Find the enclosing composited layer when it's in another document (for non-composited iframes).
    326         RenderLayer* compositedLayer = 0;
    327         for (const RenderLayer* layer = layerIter->key; !compositedLayer;) {
    328             compositedLayer = layer->enclosingCompositingLayerForRepaint();
    329             if (!compositedLayer) {
    330                 RenderObject* owner = layer->renderer()->frame()->ownerRenderer();
    331                 if (!owner)
    332                     break;
    333                 layer = owner->enclosingLayer();
    334             }
    335         }
    336         if (!compositedLayer) {
    337             // Since this machinery is used only when accelerated compositing is enabled, we expect
    338             // that every layer should have an enclosing composited layer.
    339             ASSERT_NOT_REACHED();
    340             continue;
    341         }
    342 
    343         LayerHitTestRects::iterator compIter = compositorRects.find(compositedLayer);
    344         if (compIter == compositorRects.end())
    345             compIter = compositorRects.add(compositedLayer, Vector<LayoutRect>()).iterator;
    346         // Transform each rect to the co-ordinate space of it's enclosing composited layer.
    347         // Ideally we'd compute a transformation matrix once and re-use it for each rect.
    348         // RenderGeometryMap can be used for this (but needs to be updated to support crossing
    349         // iframe boundaries), but in practice doesn't appear to provide much performance benefit.
    350         for (size_t i = 0; i < layerIter->value.size(); ++i) {
    351             FloatQuad localQuad(layerIter->value[i]);
    352             TransformState transformState(TransformState::ApplyTransformDirection, localQuad);
    353             MapCoordinatesFlags flags = ApplyContainerFlip | UseTransforms | TraverseDocumentBoundaries;
    354             layerIter->key->renderer()->mapLocalToContainer(compositedLayer->renderer(), transformState, flags);
    355             transformState.flatten();
    356             LayoutRect compositorRect = LayoutRect(transformState.lastPlanarQuad().boundingBox());
    357             compIter->value.append(compositorRect);
    358         }
    359     }
    360 }
    361 
    362 // Note that in principle this could be called more often than computeTouchEventTargetRects, for
    363 // example during a non-composited scroll (although that's not yet implemented - crbug.com/261307).
    364 void ScrollingCoordinator::setTouchEventTargetRects(const LayerHitTestRects& layerRects)
    365 {
    366     TRACE_EVENT0("input", "ScrollingCoordinator::setTouchEventTargetRects");
    367 
    368     LayerHitTestRects compositorRects;
    369     convertLayerRectsToEnclosingCompositedLayer(layerRects, compositorRects);
    370 
    371     // Inform any observers (i.e. for testing) of these new rects.
    372     HashSet<TouchEventTargetRectsObserver*>::iterator stop = m_touchEventTargetRectsObservers.end();
    373     for (HashSet<TouchEventTargetRectsObserver*>::iterator it = m_touchEventTargetRectsObservers.begin(); it != stop; ++it)
    374         (*it)->touchEventTargetRectsChanged(compositorRects);
    375 
    376     // Note that ideally we'd clear the touch event handler region on all layers first,
    377     // in case there are others that no longer have any handlers. But it's unlikely to
    378     // matter much in practice (just makes us more conservative).
    379     for (LayerHitTestRects::const_iterator iter = compositorRects.begin(); iter != compositorRects.end(); ++iter) {
    380         WebVector<WebRect> webRects(iter->value.size());
    381         for (size_t i = 0; i < iter->value.size(); ++i)
    382             webRects[i] = enclosingIntRect(iter->value[i]);
    383         RenderLayerBacking* backing = iter->key->backing();
    384         // If the layer is using composited scrolling, then it's the contents that these
    385         // rects apply to.
    386         GraphicsLayer* graphicsLayer = backing->scrollingContentsLayer();
    387         if (!graphicsLayer)
    388             graphicsLayer = backing->graphicsLayer();
    389         graphicsLayer->platformLayer()->setTouchEventHandlerRegion(webRects);
    390     }
    391 }
    392 
    393 void ScrollingCoordinator::touchEventTargetRectsDidChange(const Document*)
    394 {
    395     if (!touchHitTestingEnabled())
    396         return;
    397 
    398     // Wait until after layout to update.
    399     if (m_page->mainFrame()->view()->needsLayout())
    400         return;
    401 
    402     TRACE_EVENT0("input", "ScrollingCoordinator::touchEventTargetRectsDidChange");
    403 
    404     LayerHitTestRects touchEventTargetRects;
    405     computeTouchEventTargetRects(touchEventTargetRects);
    406     setTouchEventTargetRects(touchEventTargetRects);
    407 }
    408 
    409 void ScrollingCoordinator::setWheelEventHandlerCount(unsigned count)
    410 {
    411     if (WebLayer* scrollLayer = scrollingWebLayerForScrollableArea(m_page->mainFrame()->view()))
    412         scrollLayer->setHaveWheelEventHandlers(count > 0);
    413 }
    414 
    415 void ScrollingCoordinator::recomputeWheelEventHandlerCountForFrameView(FrameView* frameView)
    416 {
    417     UNUSED_PARAM(frameView);
    418     setWheelEventHandlerCount(computeCurrentWheelEventHandlerCount());
    419 }
    420 
    421 void ScrollingCoordinator::setShouldUpdateScrollLayerPositionOnMainThread(MainThreadScrollingReasons reasons)
    422 {
    423     if (WebLayer* scrollLayer = scrollingWebLayerForScrollableArea(m_page->mainFrame()->view()))
    424         scrollLayer->setShouldScrollOnMainThread(reasons);
    425 }
    426 
    427 void ScrollingCoordinator::pageDestroyed()
    428 {
    429     ASSERT(m_page);
    430     m_page = 0;
    431 }
    432 
    433 bool ScrollingCoordinator::coordinatesScrollingForFrameView(FrameView* frameView) const
    434 {
    435     ASSERT(isMainThread());
    436     ASSERT(m_page);
    437 
    438     // We currently only handle the main frame.
    439     if (frameView->frame() != m_page->mainFrame())
    440         return false;
    441 
    442     // We currently only support composited mode.
    443     RenderView* renderView = m_page->mainFrame()->contentRenderer();
    444     if (!renderView)
    445         return false;
    446     return renderView->usesCompositing();
    447 }
    448 
    449 Region ScrollingCoordinator::computeShouldHandleScrollGestureOnMainThreadRegion(const Frame* frame, const IntPoint& frameLocation) const
    450 {
    451     Region shouldHandleScrollGestureOnMainThreadRegion;
    452     FrameView* frameView = frame->view();
    453     if (!frameView)
    454         return shouldHandleScrollGestureOnMainThreadRegion;
    455 
    456     IntPoint offset = frameLocation;
    457     offset.moveBy(frameView->frameRect().location());
    458 
    459     if (const FrameView::ScrollableAreaSet* scrollableAreas = frameView->scrollableAreas()) {
    460         for (FrameView::ScrollableAreaSet::const_iterator it = scrollableAreas->begin(), end = scrollableAreas->end(); it != end; ++it) {
    461             ScrollableArea* scrollableArea = *it;
    462             // Composited scrollable areas can be scrolled off the main thread.
    463             if (scrollableArea->usesCompositedScrolling())
    464                 continue;
    465             IntRect box = scrollableArea->scrollableAreaBoundingBox();
    466             box.moveBy(offset);
    467             shouldHandleScrollGestureOnMainThreadRegion.unite(box);
    468         }
    469     }
    470 
    471     // We use GestureScrollBegin/Update/End for moving the resizer handle. So we mark these
    472     // small resizer areas as non-fast-scrollable to allow the scroll gestures to be passed to
    473     // main thread if they are targeting the resizer area. (Resizing is done in EventHandler.cpp
    474     // on main thread).
    475     if (const FrameView::ResizerAreaSet* resizerAreas = frameView->resizerAreas()) {
    476         for (FrameView::ResizerAreaSet::const_iterator it = resizerAreas->begin(), end = resizerAreas->end(); it != end; ++it) {
    477             RenderLayer* layer = *it;
    478             IntRect bounds = layer->renderer()->absoluteBoundingBoxRect();
    479             IntRect corner = layer->resizerCornerRect(bounds, RenderLayer::ResizerForTouch);
    480             corner.moveBy(offset);
    481             shouldHandleScrollGestureOnMainThreadRegion.unite(corner);
    482         }
    483     }
    484 
    485     if (const HashSet<RefPtr<Widget> >* children = frameView->children()) {
    486         for (HashSet<RefPtr<Widget> >::const_iterator it = children->begin(), end = children->end(); it != end; ++it) {
    487             if (!(*it)->isPluginView())
    488                 continue;
    489 
    490             PluginView* pluginView = toPluginView((*it).get());
    491             if (pluginView->wantsWheelEvents())
    492                 shouldHandleScrollGestureOnMainThreadRegion.unite(pluginView->frameRect());
    493         }
    494     }
    495 
    496     FrameTree* tree = frame->tree();
    497     for (Frame* subFrame = tree->firstChild(); subFrame; subFrame = subFrame->tree()->nextSibling())
    498         shouldHandleScrollGestureOnMainThreadRegion.unite(computeShouldHandleScrollGestureOnMainThreadRegion(subFrame, offset));
    499 
    500     return shouldHandleScrollGestureOnMainThreadRegion;
    501 }
    502 
    503 void ScrollingCoordinator::addTouchEventTargetRectsObserver(TouchEventTargetRectsObserver* observer)
    504 {
    505     m_touchEventTargetRectsObservers.add(observer);
    506 }
    507 
    508 void ScrollingCoordinator::removeTouchEventTargetRectsObserver(TouchEventTargetRectsObserver* observer)
    509 {
    510     m_touchEventTargetRectsObservers.remove(observer);
    511 }
    512 
    513 static void accumulateDocumentTouchEventTargetRects(LayerHitTestRects& rects, const Document* document)
    514 {
    515     ASSERT(document);
    516     if (!document->touchEventTargets())
    517         return;
    518 
    519     const TouchEventTargetSet* targets = document->touchEventTargets();
    520 
    521     // If there's a handler on the document, html or body element (fairly common in practice),
    522     // then we can quickly mark the entire document and skip looking at any other handlers.
    523     // Note that technically a handler on the body doesn't cover the whole document, but it's
    524     // reasonable to be conservative and report the whole document anyway.
    525     for (TouchEventTargetSet::const_iterator iter = targets->begin(); iter != targets->end(); ++iter) {
    526         Node* target = iter->key;
    527         if (target == document || target == document->documentElement() || target == document->body()) {
    528             if (RenderObject* renderer = document->renderer()) {
    529                 renderer->computeLayerHitTestRects(rects);
    530             }
    531             return;
    532         }
    533     }
    534 
    535     for (TouchEventTargetSet::const_iterator iter = targets->begin(); iter != targets->end(); ++iter) {
    536         const Node* target = iter->key;
    537         if (!target->inDocument())
    538             continue;
    539 
    540         if (target->isDocumentNode()) {
    541             ASSERT(target != document);
    542             accumulateDocumentTouchEventTargetRects(rects, toDocument(target));
    543         } else if (RenderObject* renderer = target->renderer()) {
    544             // If the set also contains one of our ancestor nodes then processing
    545             // this node would be redundant.
    546             bool hasTouchEventTargetAncestor = false;
    547             for (Node* ancestor = target->parentNode(); ancestor && !hasTouchEventTargetAncestor; ancestor = ancestor->parentNode()) {
    548                 if (targets->contains(ancestor))
    549                     hasTouchEventTargetAncestor = true;
    550             }
    551             if (!hasTouchEventTargetAncestor)
    552                 renderer->computeLayerHitTestRects(rects);
    553         }
    554     }
    555 
    556 }
    557 
    558 void ScrollingCoordinator::computeTouchEventTargetRects(LayerHitTestRects& rects)
    559 {
    560     TRACE_EVENT0("input", "ScrollingCoordinator::computeTouchEventTargetRects");
    561     ASSERT(touchHitTestingEnabled());
    562 
    563     Document* document = m_page->mainFrame()->document();
    564     if (!document || !document->view())
    565         return;
    566 
    567     accumulateDocumentTouchEventTargetRects(rects, document);
    568 }
    569 
    570 unsigned ScrollingCoordinator::computeCurrentWheelEventHandlerCount()
    571 {
    572     unsigned wheelEventHandlerCount = 0;
    573 
    574     for (Frame* frame = m_page->mainFrame(); frame; frame = frame->tree()->traverseNext()) {
    575         if (frame->document())
    576             wheelEventHandlerCount += frame->document()->wheelEventHandlerCount();
    577     }
    578 
    579     return wheelEventHandlerCount;
    580 }
    581 
    582 void ScrollingCoordinator::frameViewWheelEventHandlerCountChanged(FrameView* frameView)
    583 {
    584     ASSERT(isMainThread());
    585     ASSERT(m_page);
    586 
    587     recomputeWheelEventHandlerCountForFrameView(frameView);
    588 }
    589 
    590 void ScrollingCoordinator::frameViewHasSlowRepaintObjectsDidChange(FrameView* frameView)
    591 {
    592     ASSERT(isMainThread());
    593     ASSERT(m_page);
    594 
    595     if (!coordinatesScrollingForFrameView(frameView))
    596         return;
    597 
    598     updateShouldUpdateScrollLayerPositionOnMainThread();
    599 }
    600 
    601 void ScrollingCoordinator::frameViewFixedObjectsDidChange(FrameView* frameView)
    602 {
    603     ASSERT(isMainThread());
    604     ASSERT(m_page);
    605 
    606     if (!coordinatesScrollingForFrameView(frameView))
    607         return;
    608 
    609     updateShouldUpdateScrollLayerPositionOnMainThread();
    610 }
    611 
    612 GraphicsLayer* ScrollingCoordinator::scrollLayerForScrollableArea(ScrollableArea* scrollableArea)
    613 {
    614     return scrollableArea->layerForScrolling();
    615 }
    616 
    617 GraphicsLayer* ScrollingCoordinator::horizontalScrollbarLayerForScrollableArea(ScrollableArea* scrollableArea)
    618 {
    619     return scrollableArea->layerForHorizontalScrollbar();
    620 }
    621 
    622 GraphicsLayer* ScrollingCoordinator::verticalScrollbarLayerForScrollableArea(ScrollableArea* scrollableArea)
    623 {
    624     return scrollableArea->layerForVerticalScrollbar();
    625 }
    626 
    627 bool ScrollingCoordinator::isForMainFrame(ScrollableArea* scrollableArea) const
    628 {
    629     return scrollableArea == m_page->mainFrame()->view();
    630 }
    631 
    632 GraphicsLayer* ScrollingCoordinator::scrollLayerForFrameView(FrameView* frameView)
    633 {
    634     Frame* frame = frameView->frame();
    635     if (!frame)
    636         return 0;
    637 
    638     RenderView* renderView = frame->contentRenderer();
    639     if (!renderView)
    640         return 0;
    641     return renderView->compositor()->scrollLayer();
    642 }
    643 
    644 GraphicsLayer* ScrollingCoordinator::counterScrollingLayerForFrameView(FrameView*)
    645 {
    646     return 0;
    647 }
    648 
    649 void ScrollingCoordinator::frameViewRootLayerDidChange(FrameView* frameView)
    650 {
    651     ASSERT(isMainThread());
    652     ASSERT(m_page);
    653 
    654     if (!coordinatesScrollingForFrameView(frameView))
    655         return;
    656 
    657     frameViewLayoutUpdated(frameView);
    658     recomputeWheelEventHandlerCountForFrameView(frameView);
    659     updateShouldUpdateScrollLayerPositionOnMainThread();
    660 }
    661 
    662 #if OS(DARWIN)
    663 void ScrollingCoordinator::handleWheelEventPhase(PlatformWheelEventPhase phase)
    664 {
    665     ASSERT(isMainThread());
    666 
    667     if (!m_page)
    668         return;
    669 
    670     FrameView* frameView = m_page->mainFrame()->view();
    671     if (!frameView)
    672         return;
    673 
    674     frameView->scrollAnimator()->handleWheelEventPhase(phase);
    675 }
    676 #endif
    677 
    678 bool ScrollingCoordinator::hasVisibleSlowRepaintViewportConstrainedObjects(FrameView* frameView) const
    679 {
    680     const FrameView::ViewportConstrainedObjectSet* viewportConstrainedObjects = frameView->viewportConstrainedObjects();
    681     if (!viewportConstrainedObjects)
    682         return false;
    683 
    684     for (FrameView::ViewportConstrainedObjectSet::const_iterator it = viewportConstrainedObjects->begin(), end = viewportConstrainedObjects->end(); it != end; ++it) {
    685         RenderObject* viewportConstrainedObject = *it;
    686         if (!viewportConstrainedObject->isBoxModelObject() || !viewportConstrainedObject->hasLayer())
    687             return true;
    688         RenderLayer* layer = toRenderBoxModelObject(viewportConstrainedObject)->layer();
    689         // Any explicit reason that a fixed position element is not composited shouldn't cause slow scrolling.
    690         if (!layer->isComposited() && layer->viewportConstrainedNotCompositedReason() == RenderLayer::NoNotCompositedReason)
    691             return true;
    692     }
    693     return false;
    694 }
    695 
    696 MainThreadScrollingReasons ScrollingCoordinator::mainThreadScrollingReasons() const
    697 {
    698     FrameView* frameView = m_page->mainFrame()->view();
    699     if (!frameView)
    700         return static_cast<MainThreadScrollingReasons>(0);
    701 
    702     MainThreadScrollingReasons mainThreadScrollingReasons = (MainThreadScrollingReasons)0;
    703 
    704     if (frameView->hasSlowRepaintObjects())
    705         mainThreadScrollingReasons |= HasSlowRepaintObjects;
    706     if (hasVisibleSlowRepaintViewportConstrainedObjects(frameView))
    707         mainThreadScrollingReasons |= HasNonLayerViewportConstrainedObjects;
    708 
    709     return mainThreadScrollingReasons;
    710 }
    711 
    712 void ScrollingCoordinator::updateShouldUpdateScrollLayerPositionOnMainThread()
    713 {
    714     setShouldUpdateScrollLayerPositionOnMainThread(mainThreadScrollingReasons());
    715 }
    716 
    717 String ScrollingCoordinator::mainThreadScrollingReasonsAsText(MainThreadScrollingReasons reasons)
    718 {
    719     StringBuilder stringBuilder;
    720 
    721     if (reasons & ScrollingCoordinator::HasSlowRepaintObjects)
    722         stringBuilder.append("Has slow repaint objects, ");
    723     if (reasons & ScrollingCoordinator::HasViewportConstrainedObjectsWithoutSupportingFixedLayers)
    724         stringBuilder.append("Has viewport constrained objects without supporting fixed layers, ");
    725     if (reasons & ScrollingCoordinator::HasNonLayerViewportConstrainedObjects)
    726         stringBuilder.append("Has non-layer viewport-constrained objects, ");
    727 
    728     if (stringBuilder.length())
    729         stringBuilder.resize(stringBuilder.length() - 2);
    730     return stringBuilder.toString();
    731 }
    732 
    733 String ScrollingCoordinator::mainThreadScrollingReasonsAsText() const
    734 {
    735     return mainThreadScrollingReasonsAsText(mainThreadScrollingReasons());
    736 }
    737 
    738 } // namespace WebCore
    739