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