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