Work towards having frames in the scrolling tree
[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 = 0;
83 }
84
85 bool ScrollingCoordinator::coordinatesScrollingForFrameView(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 PLATFORM(IOS)
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 (!child->isPluginViewBase())
142             continue;
143         PluginViewBase* pluginViewBase = toPluginViewBase(child.get());
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::horizontalScrollbarLayerForScrollableArea(ScrollableArea* scrollableArea)
203 {
204     return scrollableArea->layerForHorizontalScrollbar();
205 }
206
207 GraphicsLayer* ScrollingCoordinator::verticalScrollbarLayerForScrollableArea(ScrollableArea* scrollableArea)
208 {
209     return scrollableArea->layerForVerticalScrollbar();
210 }
211
212 GraphicsLayer* ScrollingCoordinator::scrollLayerForFrameView(FrameView* frameView)
213 {
214     if (RenderView* renderView = frameView->frame().contentRenderer())
215         return renderView->compositor().scrollLayer();
216     return nullptr;
217 }
218
219 GraphicsLayer* ScrollingCoordinator::headerLayerForFrameView(FrameView* frameView)
220 {
221 #if ENABLE(RUBBER_BANDING)
222     if (RenderView* renderView = frameView->frame().contentRenderer())
223         return renderView->compositor().headerLayer();
224     return nullptr;
225 #else
226     UNUSED_PARAM(frameView);
227     return nullptr;
228 #endif
229 }
230
231 GraphicsLayer* ScrollingCoordinator::footerLayerForFrameView(FrameView* frameView)
232 {
233 #if ENABLE(RUBBER_BANDING)
234     if (RenderView* renderView = frameView->frame().contentRenderer())
235         return renderView->compositor().footerLayer();
236     return nullptr;
237 #else
238     UNUSED_PARAM(frameView);
239     return nullptr;
240 #endif
241 }
242
243 GraphicsLayer* ScrollingCoordinator::counterScrollingLayerForFrameView(FrameView* frameView)
244 {
245     if (RenderView* renderView = frameView->frame().contentRenderer())
246         return renderView->compositor().fixedRootBackgroundLayer();
247     return nullptr;
248 }
249
250 GraphicsLayer* ScrollingCoordinator::insetClipLayerForFrameView(FrameView* frameView)
251 {
252     if (RenderView* renderView = frameView->frame().contentRenderer())
253         return renderView->compositor().clipLayer();
254     return nullptr;
255 }
256
257 GraphicsLayer* ScrollingCoordinator::contentShadowLayerForFrameView(FrameView* frameView)
258 {
259 #if ENABLE(RUBBER_BANDING)
260     if (RenderView* renderView = frameView->frame().contentRenderer())
261         return renderView->compositor().layerForContentShadow();
262     
263     return nullptr;
264 #else
265     UNUSED_PARAM(frameView);
266     return nullptr;
267 #endif
268 }
269
270 GraphicsLayer* ScrollingCoordinator::rootContentLayerForFrameView(FrameView* frameView)
271 {
272     if (RenderView* renderView = frameView->frame().contentRenderer())
273         return renderView->compositor().rootContentLayer();
274     return nullptr;
275 }
276
277 void ScrollingCoordinator::frameViewRootLayerDidChange(FrameView* frameView)
278 {
279     ASSERT(isMainThread());
280     ASSERT(m_page);
281
282     if (!coordinatesScrollingForFrameView(frameView))
283         return;
284
285     frameViewLayoutUpdated(frameView);
286     recomputeWheelEventHandlerCountForFrameView(frameView);
287     updateSynchronousScrollingReasons(frameView);
288 }
289
290 #if PLATFORM(COCOA)
291 void ScrollingCoordinator::handleWheelEventPhase(PlatformWheelEventPhase phase)
292 {
293     ASSERT(isMainThread());
294
295     if (!m_page)
296         return;
297
298     FrameView* frameView = m_page->mainFrame().view();
299     if (!frameView)
300         return;
301
302     frameView->scrollAnimator()->handleWheelEventPhase(phase);
303 }
304 #endif
305
306 bool ScrollingCoordinator::hasVisibleSlowRepaintViewportConstrainedObjects(FrameView* frameView) const
307 {
308     const FrameView::ViewportConstrainedObjectSet* viewportConstrainedObjects = frameView->viewportConstrainedObjects();
309     if (!viewportConstrainedObjects)
310         return false;
311
312     for (FrameView::ViewportConstrainedObjectSet::const_iterator it = viewportConstrainedObjects->begin(), end = viewportConstrainedObjects->end(); it != end; ++it) {
313         RenderObject* viewportConstrainedObject = *it;
314         if (!viewportConstrainedObject->isBoxModelObject() || !viewportConstrainedObject->hasLayer())
315             return true;
316         RenderLayer* layer = toRenderBoxModelObject(viewportConstrainedObject)->layer();
317         // Any explicit reason that a fixed position element is not composited shouldn't cause slow scrolling.
318         if (!layer->isComposited() && layer->viewportConstrainedNotCompositedReason() == RenderLayer::NoNotCompositedReason)
319             return true;
320     }
321     return false;
322 }
323
324 SynchronousScrollingReasons ScrollingCoordinator::synchronousScrollingReasons(FrameView* frameView) const
325 {
326     if (!frameView)
327         return static_cast<SynchronousScrollingReasons>(0);
328
329     SynchronousScrollingReasons synchronousScrollingReasons = (SynchronousScrollingReasons)0;
330
331     if (m_forceSynchronousScrollLayerPositionUpdates)
332         synchronousScrollingReasons |= ForcedOnMainThread;
333 #if ENABLE(WEB_REPLAY)
334     InputCursor& cursor = m_page->replayController().activeInputCursor();
335     if (cursor.isCapturing() || cursor.isReplaying())
336         synchronousScrollingReasons |= ForcedOnMainThread;
337 #endif
338     if (frameView->hasSlowRepaintObjects())
339         synchronousScrollingReasons |= HasSlowRepaintObjects;
340     if (!supportsFixedPositionLayers() && frameView->hasViewportConstrainedObjects())
341         synchronousScrollingReasons |= HasViewportConstrainedObjectsWithoutSupportingFixedLayers;
342     if (supportsFixedPositionLayers() && hasVisibleSlowRepaintViewportConstrainedObjects(frameView))
343         synchronousScrollingReasons |= HasNonLayerViewportConstrainedObjects;
344     if (frameView->frame().mainFrame().document() && frameView->frame().document()->isImageDocument())
345         synchronousScrollingReasons |= IsImageDocument;
346
347     return synchronousScrollingReasons;
348 }
349
350 void ScrollingCoordinator::updateSynchronousScrollingReasons(FrameView* frameView)
351 {
352     // FIXME: Once we support async scrolling of iframes, we'll have to track the synchronous scrolling
353     // reasons per frame (maybe on scrolling tree nodes).
354     if (!frameView->frame().isMainFrame())
355         return;
356
357     setSynchronousScrollingReasons(synchronousScrollingReasons(frameView));
358 }
359
360 void ScrollingCoordinator::setForceSynchronousScrollLayerPositionUpdates(bool forceSynchronousScrollLayerPositionUpdates)
361 {
362     if (m_forceSynchronousScrollLayerPositionUpdates == forceSynchronousScrollLayerPositionUpdates)
363         return;
364
365     m_forceSynchronousScrollLayerPositionUpdates = forceSynchronousScrollLayerPositionUpdates;
366     updateSynchronousScrollingReasons(m_page->mainFrame().view());
367 }
368
369 bool ScrollingCoordinator::shouldUpdateScrollLayerPositionSynchronously() const
370 {
371     return synchronousScrollingReasons(m_page->mainFrame().view());
372 }
373
374 #if ENABLE(WEB_REPLAY)
375 void ScrollingCoordinator::replaySessionStateDidChange()
376 {
377     // FIXME: Once we support async scrolling of iframes, this should go through all subframes.
378     updateSynchronousScrollingReasons(m_page->mainFrame().view());
379 }
380 #endif
381
382 ScrollingNodeID ScrollingCoordinator::uniqueScrollLayerID()
383 {
384     static ScrollingNodeID uniqueScrollLayerID = 1;
385     return uniqueScrollLayerID++;
386 }
387
388 String ScrollingCoordinator::scrollingStateTreeAsText() const
389 {
390     return String();
391 }
392
393 String ScrollingCoordinator::synchronousScrollingReasonsAsText(SynchronousScrollingReasons reasons)
394 {
395     StringBuilder stringBuilder;
396
397     if (reasons & ScrollingCoordinator::ForcedOnMainThread)
398         stringBuilder.append("Forced on main thread, ");
399     if (reasons & ScrollingCoordinator::HasSlowRepaintObjects)
400         stringBuilder.append("Has slow repaint objects, ");
401     if (reasons & ScrollingCoordinator::HasViewportConstrainedObjectsWithoutSupportingFixedLayers)
402         stringBuilder.append("Has viewport constrained objects without supporting fixed layers, ");
403     if (reasons & ScrollingCoordinator::HasNonLayerViewportConstrainedObjects)
404         stringBuilder.append("Has non-layer viewport-constrained objects, ");
405     if (reasons & ScrollingCoordinator::IsImageDocument)
406         stringBuilder.append("Is image document, ");
407
408     if (stringBuilder.length())
409         stringBuilder.resize(stringBuilder.length() - 2);
410     return stringBuilder.toString();
411 }
412
413 String ScrollingCoordinator::synchronousScrollingReasonsAsText() const
414 {
415     return synchronousScrollingReasonsAsText(synchronousScrollingReasons(m_page->mainFrame().view()));
416 }
417
418 } // namespace WebCore