a641b65cba48572c5a8c6ac2ae8e5c3d16adc1d7
[WebKit-https.git] / Source / WebCore / 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 "ScrollingCoordinator.h"
29
30 #include "Document.h"
31 #include "FrameView.h"
32 #include "GraphicsLayer.h"
33 #include "IntRect.h"
34 #include "MainFrame.h"
35 #include "Page.h"
36 #include "PlatformWheelEvent.h"
37 #include "PluginViewBase.h"
38 #include "Region.h"
39 #include "RenderLayerCompositor.h"
40 #include "RenderView.h"
41 #include "ScrollAnimator.h"
42 #include "Settings.h"
43 #include <wtf/MainThread.h>
44 #include <wtf/text/StringBuilder.h>
45
46 #if USE(COORDINATED_GRAPHICS)
47 #include "ScrollingCoordinatorCoordinatedGraphics.h"
48 #endif
49
50 #if ENABLE(WEB_REPLAY)
51 #include "ReplayController.h"
52 #include <replay/InputCursor.h>
53 #endif
54
55 namespace WebCore {
56
57 #if !PLATFORM(COCOA)
58 PassRefPtr<ScrollingCoordinator> ScrollingCoordinator::create(Page* page)
59 {
60 #if USE(COORDINATED_GRAPHICS)
61     return adoptRef(new ScrollingCoordinatorCoordinatedGraphics(page));
62 #endif
63
64     return adoptRef(new ScrollingCoordinator(page));
65 }
66 #endif
67
68 ScrollingCoordinator::ScrollingCoordinator(Page* page)
69     : m_page(page)
70     , m_forceSynchronousScrollLayerPositionUpdates(false)
71 {
72 }
73
74 ScrollingCoordinator::~ScrollingCoordinator()
75 {
76     ASSERT(!m_page);
77 }
78
79 void ScrollingCoordinator::pageDestroyed()
80 {
81     ASSERT(m_page);
82     m_page = nullptr;
83 }
84
85 bool ScrollingCoordinator::coordinatesScrollingForFrameView(const FrameView& frameView) const
86 {
87     ASSERT(isMainThread());
88     ASSERT(m_page);
89
90     if (!frameView.frame().isMainFrame() && !m_page->settings().scrollingTreeIncludesFrames())
91         return false;
92
93     RenderView* renderView = m_page->mainFrame().contentRenderer();
94     if (!renderView)
95         return false;
96     return renderView->usesCompositing();
97 }
98
99 Region ScrollingCoordinator::computeNonFastScrollableRegion(const Frame& frame, const IntPoint& frameLocation) const
100 {
101 #if ENABLE(IOS_TOUCH_EVENTS)
102     // On iOS, we use nonFastScrollableRegion to represent the region covered by elements with touch event handlers.
103     ASSERT(frame.isMainFrame());
104     UNUSED_PARAM(frameLocation);
105
106     Document* document = frame.document();
107     if (!document)
108         return Region();
109
110     Vector<IntRect> touchRects;
111     document->getTouchRects(touchRects);
112     
113     Region touchRegion;
114     for (const auto& rect : touchRects)
115         touchRegion.unite(rect);
116
117     return touchRegion;
118 #else
119     Region nonFastScrollableRegion;
120     FrameView* frameView = frame.view();
121     if (!frameView)
122         return nonFastScrollableRegion;
123
124     IntPoint offset = frameLocation;
125     offset.moveBy(frameView->frameRect().location());
126     offset.move(0, frameView->topContentInset());
127
128     if (const FrameView::ScrollableAreaSet* scrollableAreas = frameView->scrollableAreas()) {
129         for (FrameView::ScrollableAreaSet::const_iterator it = scrollableAreas->begin(), end = scrollableAreas->end(); it != end; ++it) {
130             ScrollableArea* scrollableArea = *it;
131             // Composited scrollable areas can be scrolled off the main thread.
132             if (scrollableArea->usesCompositedScrolling())
133                 continue;
134             IntRect box = scrollableArea->scrollableAreaBoundingBox();
135             box.moveBy(offset);
136             nonFastScrollableRegion.unite(box);
137         }
138     }
139
140     for (const auto& child : frameView->children()) {
141         if (!is<PluginViewBase>(*child))
142             continue;
143         PluginViewBase& pluginViewBase = downcast<PluginViewBase>(*child);
144         if (pluginViewBase.wantsWheelEvents())
145             nonFastScrollableRegion.unite(pluginViewBase.frameRect());
146     }
147
148     for (Frame* subframe = frame.tree().firstChild(); subframe; subframe = subframe->tree().nextSibling())
149         nonFastScrollableRegion.unite(computeNonFastScrollableRegion(*subframe, offset));
150
151     return nonFastScrollableRegion;
152 #endif
153 }
154
155 unsigned ScrollingCoordinator::computeCurrentWheelEventHandlerCount()
156 {
157     unsigned wheelEventHandlerCount = 0;
158
159     for (Frame* frame = &m_page->mainFrame(); frame; frame = frame->tree().traverseNext()) {
160         if (frame->document())
161             wheelEventHandlerCount += frame->document()->wheelEventHandlerCount();
162     }
163
164     return wheelEventHandlerCount;
165 }
166
167 void ScrollingCoordinator::frameViewWheelEventHandlerCountChanged(FrameView& frameView)
168 {
169     ASSERT(isMainThread());
170     ASSERT(m_page);
171
172     recomputeWheelEventHandlerCountForFrameView(frameView);
173 }
174
175 void ScrollingCoordinator::frameViewHasSlowRepaintObjectsDidChange(FrameView& frameView)
176 {
177     ASSERT(isMainThread());
178     ASSERT(m_page);
179
180     if (!coordinatesScrollingForFrameView(frameView))
181         return;
182
183     updateSynchronousScrollingReasons(frameView);
184 }
185
186 void ScrollingCoordinator::frameViewFixedObjectsDidChange(FrameView& frameView)
187 {
188     ASSERT(isMainThread());
189     ASSERT(m_page);
190
191     if (!coordinatesScrollingForFrameView(frameView))
192         return;
193
194     updateSynchronousScrollingReasons(frameView);
195 }
196
197 GraphicsLayer* ScrollingCoordinator::scrollLayerForScrollableArea(ScrollableArea& scrollableArea)
198 {
199     return scrollableArea.layerForScrolling();
200 }
201
202 GraphicsLayer* ScrollingCoordinator::scrollLayerForFrameView(FrameView& frameView)
203 {
204     if (RenderView* renderView = frameView.frame().contentRenderer())
205         return renderView->compositor().scrollLayer();
206     return nullptr;
207 }
208
209 GraphicsLayer* ScrollingCoordinator::headerLayerForFrameView(FrameView& frameView)
210 {
211 #if ENABLE(RUBBER_BANDING)
212     if (RenderView* renderView = frameView.frame().contentRenderer())
213         return renderView->compositor().headerLayer();
214     return nullptr;
215 #else
216     UNUSED_PARAM(frameView);
217     return nullptr;
218 #endif
219 }
220
221 GraphicsLayer* ScrollingCoordinator::footerLayerForFrameView(FrameView& frameView)
222 {
223 #if ENABLE(RUBBER_BANDING)
224     if (RenderView* renderView = frameView.frame().contentRenderer())
225         return renderView->compositor().footerLayer();
226     return nullptr;
227 #else
228     UNUSED_PARAM(frameView);
229     return nullptr;
230 #endif
231 }
232
233 GraphicsLayer* ScrollingCoordinator::counterScrollingLayerForFrameView(FrameView& frameView)
234 {
235     if (RenderView* renderView = frameView.frame().contentRenderer())
236         return renderView->compositor().fixedRootBackgroundLayer();
237     return nullptr;
238 }
239
240 GraphicsLayer* ScrollingCoordinator::insetClipLayerForFrameView(FrameView& frameView)
241 {
242     if (RenderView* renderView = frameView.frame().contentRenderer())
243         return renderView->compositor().clipLayer();
244     return nullptr;
245 }
246
247 GraphicsLayer* ScrollingCoordinator::contentShadowLayerForFrameView(FrameView& frameView)
248 {
249 #if ENABLE(RUBBER_BANDING)
250     if (RenderView* renderView = frameView.frame().contentRenderer())
251         return renderView->compositor().layerForContentShadow();
252     
253     return nullptr;
254 #else
255     UNUSED_PARAM(frameView);
256     return nullptr;
257 #endif
258 }
259
260 GraphicsLayer* ScrollingCoordinator::rootContentLayerForFrameView(FrameView& frameView)
261 {
262     if (RenderView* renderView = frameView.frame().contentRenderer())
263         return renderView->compositor().rootContentLayer();
264     return nullptr;
265 }
266
267 void ScrollingCoordinator::frameViewRootLayerDidChange(FrameView& frameView)
268 {
269     ASSERT(isMainThread());
270     ASSERT(m_page);
271
272     if (!coordinatesScrollingForFrameView(frameView))
273         return;
274
275     frameViewLayoutUpdated(frameView);
276     recomputeWheelEventHandlerCountForFrameView(frameView);
277     updateSynchronousScrollingReasons(frameView);
278 }
279
280 #if PLATFORM(COCOA)
281 void ScrollingCoordinator::handleWheelEventPhase(PlatformWheelEventPhase phase)
282 {
283     ASSERT(isMainThread());
284
285     if (!m_page)
286         return;
287
288     FrameView* frameView = m_page->mainFrame().view();
289     if (!frameView)
290         return;
291
292     frameView->scrollAnimator().handleWheelEventPhase(phase);
293 }
294 #endif
295
296 bool ScrollingCoordinator::hasVisibleSlowRepaintViewportConstrainedObjects(const FrameView& frameView) const
297 {
298     const FrameView::ViewportConstrainedObjectSet* viewportConstrainedObjects = frameView.viewportConstrainedObjects();
299     if (!viewportConstrainedObjects)
300         return false;
301
302     for (FrameView::ViewportConstrainedObjectSet::const_iterator it = viewportConstrainedObjects->begin(), end = viewportConstrainedObjects->end(); it != end; ++it) {
303         RenderObject& viewportConstrainedObject = **it;
304         if (!is<RenderBoxModelObject>(viewportConstrainedObject) || !viewportConstrainedObject.hasLayer())
305             return true;
306         RenderLayer& layer = *downcast<RenderBoxModelObject>(viewportConstrainedObject).layer();
307         // Any explicit reason that a fixed position element is not composited shouldn't cause slow scrolling.
308         if (!layer.isComposited() && layer.viewportConstrainedNotCompositedReason() == RenderLayer::NoNotCompositedReason)
309             return true;
310     }
311     return false;
312 }
313
314 SynchronousScrollingReasons ScrollingCoordinator::synchronousScrollingReasons(const FrameView& frameView) const
315 {
316     SynchronousScrollingReasons synchronousScrollingReasons = (SynchronousScrollingReasons)0;
317
318     if (m_forceSynchronousScrollLayerPositionUpdates)
319         synchronousScrollingReasons |= ForcedOnMainThread;
320 #if ENABLE(WEB_REPLAY)
321     InputCursor& cursor = m_page->replayController().activeInputCursor();
322     if (cursor.isCapturing() || cursor.isReplaying())
323         synchronousScrollingReasons |= ForcedOnMainThread;
324 #endif
325     if (frameView.hasSlowRepaintObjects())
326         synchronousScrollingReasons |= HasSlowRepaintObjects;
327     if (!supportsFixedPositionLayers() && frameView.hasViewportConstrainedObjects())
328         synchronousScrollingReasons |= HasViewportConstrainedObjectsWithoutSupportingFixedLayers;
329     if (supportsFixedPositionLayers() && hasVisibleSlowRepaintViewportConstrainedObjects(frameView))
330         synchronousScrollingReasons |= HasNonLayerViewportConstrainedObjects;
331     if (frameView.frame().mainFrame().document() && frameView.frame().document()->isImageDocument())
332         synchronousScrollingReasons |= IsImageDocument;
333
334     return synchronousScrollingReasons;
335 }
336
337 void ScrollingCoordinator::updateSynchronousScrollingReasons(FrameView& frameView)
338 {
339     // FIXME: Once we support async scrolling of iframes, we'll have to track the synchronous scrolling
340     // reasons per frame (maybe on scrolling tree nodes).
341     if (!frameView.frame().isMainFrame())
342         return;
343
344     setSynchronousScrollingReasons(synchronousScrollingReasons(frameView));
345 }
346
347 void ScrollingCoordinator::setForceSynchronousScrollLayerPositionUpdates(bool forceSynchronousScrollLayerPositionUpdates)
348 {
349     if (m_forceSynchronousScrollLayerPositionUpdates == forceSynchronousScrollLayerPositionUpdates)
350         return;
351
352     m_forceSynchronousScrollLayerPositionUpdates = forceSynchronousScrollLayerPositionUpdates;
353     if (FrameView* frameView = m_page->mainFrame().view())
354         updateSynchronousScrollingReasons(*frameView);
355 }
356
357 bool ScrollingCoordinator::shouldUpdateScrollLayerPositionSynchronously() const
358 {
359     if (FrameView* frameView = m_page->mainFrame().view())
360         return synchronousScrollingReasons(*frameView);
361     return true;
362 }
363
364 #if ENABLE(WEB_REPLAY)
365 void ScrollingCoordinator::replaySessionStateDidChange()
366 {
367     // FIXME: Once we support async scrolling of iframes, this should go through all subframes.
368     if (FrameView* frameView = m_page->mainFrame().view())
369         updateSynchronousScrollingReasons(*frameView);
370 }
371 #endif
372
373 ScrollingNodeID ScrollingCoordinator::uniqueScrollLayerID()
374 {
375     static ScrollingNodeID uniqueScrollLayerID = 1;
376     return uniqueScrollLayerID++;
377 }
378
379 String ScrollingCoordinator::scrollingStateTreeAsText() const
380 {
381     return String();
382 }
383
384 String ScrollingCoordinator::synchronousScrollingReasonsAsText(SynchronousScrollingReasons reasons)
385 {
386     StringBuilder stringBuilder;
387
388     if (reasons & ScrollingCoordinator::ForcedOnMainThread)
389         stringBuilder.appendLiteral("Forced on main thread, ");
390     if (reasons & ScrollingCoordinator::HasSlowRepaintObjects)
391         stringBuilder.appendLiteral("Has slow repaint objects, ");
392     if (reasons & ScrollingCoordinator::HasViewportConstrainedObjectsWithoutSupportingFixedLayers)
393         stringBuilder.appendLiteral("Has viewport constrained objects without supporting fixed layers, ");
394     if (reasons & ScrollingCoordinator::HasNonLayerViewportConstrainedObjects)
395         stringBuilder.appendLiteral("Has non-layer viewport-constrained objects, ");
396     if (reasons & ScrollingCoordinator::IsImageDocument)
397         stringBuilder.appendLiteral("Is image document, ");
398
399     if (stringBuilder.length())
400         stringBuilder.resize(stringBuilder.length() - 2);
401     return stringBuilder.toString();
402 }
403
404 String ScrollingCoordinator::synchronousScrollingReasonsAsText() const
405 {
406     if (FrameView* frameView = m_page->mainFrame().view())
407         return synchronousScrollingReasonsAsText(synchronousScrollingReasons(*frameView));
408
409     return String();
410 }
411
412 } // namespace WebCore