• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
toWebLayer(WebCore::GraphicsLayer * layer)72 WebLayer* toWebLayer(WebCore::GraphicsLayer* layer)
73 {
74     return layer ? layer->platformLayer() : 0;
75 }
76 
77 } // namespace
78 
79 namespace WebCore {
80 
create(Page * page)81 PassOwnPtr<ScrollingCoordinator> ScrollingCoordinator::create(Page* page)
82 {
83     return adoptPtr(new ScrollingCoordinator(page));
84 }
85 
ScrollingCoordinator(Page * page)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 
~ScrollingCoordinator()96 ScrollingCoordinator::~ScrollingCoordinator()
97 {
98 }
99 
touchHitTestingEnabled() const100 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 
setShouldHandleScrollGestureOnMainThreadRegion(const Region & region)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 
notifyLayoutUpdated()122 void ScrollingCoordinator::notifyLayoutUpdated()
123 {
124     m_scrollGestureRegionIsDirty = true;
125     m_touchEventTargetRectsAreDirty = true;
126     m_shouldScrollOnMainThreadDirty = true;
127 }
128 
updateAfterCompositingChangeIfNeeded()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 
setLayerIsContainerForFixedPositionLayers(GraphicsLayer * layer,bool enable)188 void ScrollingCoordinator::setLayerIsContainerForFixedPositionLayers(GraphicsLayer* layer, bool enable)
189 {
190     if (WebLayer* scrollableLayer = toWebLayer(layer))
191         scrollableLayer->setIsContainerForFixedPositionLayers(enable);
192 }
193 
clearPositionConstraintExceptForLayer(GraphicsLayer * layer,GraphicsLayer * except)194 static void clearPositionConstraintExceptForLayer(GraphicsLayer* layer, GraphicsLayer* except)
195 {
196     if (layer && layer != except && toWebLayer(layer))
197         toWebLayer(layer)->setPositionConstraint(WebLayerPositionConstraint());
198 }
199 
computePositionConstraint(const RenderLayer * layer)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 
updateLayerPositionConstraint(RenderLayer * layer)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 
willDestroyScrollableArea(ScrollableArea * scrollableArea)233 void ScrollingCoordinator::willDestroyScrollableArea(ScrollableArea* scrollableArea)
234 {
235     removeWebScrollbarLayer(scrollableArea, HorizontalScrollbar);
236     removeWebScrollbarLayer(scrollableArea, VerticalScrollbar);
237 }
238 
removeWebScrollbarLayer(ScrollableArea * scrollableArea,ScrollbarOrientation orientation)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 
createScrollbarLayer(Scrollbar * scrollbar)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 
createSolidColorScrollbarLayer(ScrollbarOrientation orientation,int thumbThickness,int trackStart,bool isLeftSideVerticalScrollbar)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 
detachScrollbarLayer(GraphicsLayer * scrollbarGraphicsLayer)265 static void detachScrollbarLayer(GraphicsLayer* scrollbarGraphicsLayer)
266 {
267     ASSERT(scrollbarGraphicsLayer);
268 
269     scrollbarGraphicsLayer->setContentsToPlatformLayer(0);
270     scrollbarGraphicsLayer->setDrawsContent(true);
271 }
272 
setupScrollbarLayer(GraphicsLayer * scrollbarGraphicsLayer,WebScrollbarLayer * scrollbarLayer,WebLayer * scrollLayer,WebLayer * containerLayer)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 
addWebScrollbarLayer(ScrollableArea * scrollableArea,ScrollbarOrientation orientation,PassOwnPtr<blink::WebScrollbarLayer> scrollbarLayer)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 
getWebScrollbarLayer(ScrollableArea * scrollableArea,ScrollbarOrientation orientation)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 
scrollableAreaScrollbarLayerDidChange(ScrollableArea * scrollableArea,ScrollbarOrientation orientation)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 
scrollableAreaScrollLayerDidChange(ScrollableArea * scrollableArea)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;
makeLayerChildFrameMap(const LocalFrame * currentFrame,LayerFrameMap * map)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.
enclosingCompositedLayer(const RenderLayer * layer)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 
projectRectsToGraphicsLayerSpaceRecursive(const RenderLayer * curLayer,const LayerHitTestRects & layerRects,GraphicsLayerHitTestRects & graphicsRects,RenderGeometryMap & geometryMap,HashSet<const RenderLayer * > & layersWithRects,LayerFrameMap & layerChildFrameMap)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 
projectRectsToGraphicsLayerSpace(LocalFrame * mainFrame,const LayerHitTestRects & layerRects,GraphicsLayerHitTestRects & graphicsRects)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 
updateTouchEventTargetRectsIfNeeded()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 
reset()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).
setTouchEventTargetRects(LayerHitTestRects & layerRects)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 
touchEventTargetRectsDidChange()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 
updateScrollParentForGraphicsLayer(GraphicsLayer * child,RenderLayer * parent)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 
updateClipParentForGraphicsLayer(GraphicsLayer * child,RenderLayer * parent)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 
willDestroyRenderLayer(RenderLayer * layer)667 void ScrollingCoordinator::willDestroyRenderLayer(RenderLayer* layer)
668 {
669     m_layersWithTouchRects.remove(layer);
670 }
671 
updateHaveWheelEventHandlers()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 
updateHaveScrollEventHandlers()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 
setShouldUpdateScrollLayerPositionOnMainThread(MainThreadScrollingReasons reasons)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 
willBeDestroyed()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 
coordinatesScrollingForFrameView(FrameView * frameView) const721 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 
computeShouldHandleScrollGestureOnMainThreadRegion(const LocalFrame * frame,const IntPoint & frameLocation) const740 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 
accumulateDocumentTouchEventTargetRects(LayerHitTestRects & rects,const Document * document)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 
computeTouchEventTargetRects(LayerHitTestRects & rects)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 
frameViewHasSlowRepaintObjectsDidChange(FrameView * frameView)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 
frameViewFixedObjectsDidChange(FrameView * frameView)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 
isForMainFrame(ScrollableArea * scrollableArea) const896 bool ScrollingCoordinator::isForMainFrame(ScrollableArea* scrollableArea) const
897 {
898     return m_page->mainFrame()->isLocalFrame() ? scrollableArea == m_page->deprecatedLocalMainFrame()->view() : false;
899 }
900 
frameViewRootLayerDidChange(FrameView * frameView)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)
handleWheelEventPhase(PlatformWheelEventPhase phase)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 
hasVisibleSlowRepaintViewportConstrainedObjects(FrameView * frameView) const930 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 
mainThreadScrollingReasons() const953 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 
mainThreadScrollingReasonsAsText(MainThreadScrollingReasons reasons)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 
mainThreadScrollingReasonsAsText() const990 String ScrollingCoordinator::mainThreadScrollingReasonsAsText() const
991 {
992     ASSERT(m_page->deprecatedLocalMainFrame()->document()->lifecycle().state() >= DocumentLifecycle::CompositingClean);
993     return mainThreadScrollingReasonsAsText(m_lastMainThreadScrollingReasons);
994 }
995 
frameViewIsDirty() const996 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