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