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