22f9fc2dbe986a4e67b0b6b083a9aa3b7a6f52b1
[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 "EventNames.h"
32 #include "Frame.h"
33 #include "FrameView.h"
34 #include "GraphicsLayer.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 "RuntimeEnabledFeatures.h"
42 #include "ScrollAnimator.h"
43 #include "Settings.h"
44 #include <wtf/MainThread.h>
45 #include <wtf/text/StringBuilder.h>
46 #include <wtf/text/TextStream.h>
47
48 namespace WebCore {
49
50 #if !PLATFORM(COCOA) && !USE(COORDINATED_GRAPHICS)
51 Ref<ScrollingCoordinator> ScrollingCoordinator::create(Page* page)
52 {
53     return adoptRef(*new ScrollingCoordinator(page));
54 }
55 #endif
56
57 ScrollingCoordinator::ScrollingCoordinator(Page* page)
58     : m_page(page)
59 {
60 }
61
62 ScrollingCoordinator::~ScrollingCoordinator()
63 {
64     ASSERT(!m_page);
65 }
66
67 void ScrollingCoordinator::pageDestroyed()
68 {
69     ASSERT(m_page);
70     m_page = nullptr;
71 }
72
73 bool ScrollingCoordinator::coordinatesScrollingForFrameView(const FrameView& frameView) const
74 {
75     ASSERT(isMainThread());
76     ASSERT(m_page);
77
78     if (!frameView.frame().isMainFrame() && !m_page->settings().scrollingTreeIncludesFrames()
79 #if PLATFORM(MAC)
80         && !m_page->settings().asyncFrameScrollingEnabled()
81 #endif
82     )
83         return false;
84
85     auto* renderView = frameView.frame().contentRenderer();
86     if (!renderView)
87         return false;
88     return renderView->usesCompositing();
89 }
90
91 bool ScrollingCoordinator::coordinatesScrollingForOverflowLayer(const RenderLayer& layer) const
92 {
93     ASSERT(isMainThread());
94     ASSERT(m_page);
95
96     return layer.hasCompositedScrollableOverflow();
97 }
98
99 EventTrackingRegions ScrollingCoordinator::absoluteEventTrackingRegionsForFrame(const Frame& frame) const
100 {
101     auto* renderView = frame.contentRenderer();
102     if (!renderView || renderView->renderTreeBeingDestroyed())
103         return EventTrackingRegions();
104
105 #if ENABLE(IOS_TOUCH_EVENTS)
106     // On iOS, we use nonFastScrollableRegion to represent the region covered by elements with touch event handlers.
107     ASSERT(frame.isMainFrame());
108     auto* document = frame.document();
109     if (!document)
110         return EventTrackingRegions();
111     auto eventTrackingRegions = document->eventTrackingRegions();
112
113 #if ENABLE(POINTER_EVENTS)
114     if (RuntimeEnabledFeatures::sharedFeatures().pointerEventsEnabled()) {
115         if (auto* touchActionElements = frame.document()->touchActionElements()) {
116             auto& touchActionData = eventTrackingRegions.touchActionData;
117             for (const auto& element : *touchActionElements) {
118                 ASSERT(element);
119                 touchActionData.append({
120                     element->computedTouchActions(),
121                     element->nearestScrollingNodeIDUsingTouchOverflowScrolling(),
122                     element->document().absoluteEventRegionForNode(*element).first
123                 });
124             }
125         }
126     }
127 #endif
128
129     return eventTrackingRegions;
130 #else
131     auto* frameView = frame.view();
132     if (!frameView)
133         return EventTrackingRegions();
134
135     Region nonFastScrollableRegion;
136
137     // FIXME: should ASSERT(!frameView->needsLayout()) here, but need to fix DebugPageOverlays
138     // to not ask for regions at bad times.
139
140     if (auto* scrollableAreas = frameView->scrollableAreas()) {
141         for (auto& scrollableArea : *scrollableAreas) {
142             // Composited scrollable areas can be scrolled off the main thread.
143             if (scrollableArea->usesAsyncScrolling())
144                 continue;
145
146             bool isInsideFixed;
147             IntRect box = scrollableArea->scrollableAreaBoundingBox(&isInsideFixed);
148             if (isInsideFixed)
149                 box = IntRect(frameView->fixedScrollableAreaBoundsInflatedForScrolling(LayoutRect(box)));
150
151             nonFastScrollableRegion.unite(box);
152         }
153     }
154
155     for (auto& widget : frameView->widgetsInRenderTree()) {
156         if (!is<PluginViewBase>(*widget))
157             continue;
158         if (!downcast<PluginViewBase>(*widget).wantsWheelEvents())
159             continue;
160         auto* renderWidget = RenderWidget::find(*widget);
161         if (!renderWidget)
162             continue;
163         nonFastScrollableRegion.unite(renderWidget->absoluteBoundingBoxRect());
164     }
165     
166     EventTrackingRegions eventTrackingRegions;
167
168     // FIXME: if we've already accounted for this subframe as a scrollable area, we can avoid recursing into it here.
169     for (auto* subframe = frame.tree().firstChild(); subframe; subframe = subframe->tree().nextSibling()) {
170         auto* subframeView = subframe->view();
171         if (!subframeView)
172             continue;
173
174         EventTrackingRegions subframeRegion = absoluteEventTrackingRegionsForFrame(*subframe);
175         // Map from the frame document to our document.
176         IntPoint offset = subframeView->contentsToContainingViewContents(IntPoint());
177
178         // FIXME: this translation ignores non-trival transforms on the frame.
179         subframeRegion.translate(toIntSize(offset));
180         eventTrackingRegions.unite(subframeRegion);
181     }
182
183     auto wheelHandlerRegion = frame.document()->absoluteRegionForEventTargets(frame.document()->wheelEventTargets());
184     bool wheelHandlerInFixedContent = wheelHandlerRegion.second;
185     if (wheelHandlerInFixedContent) {
186         // FIXME: need to handle position:sticky here too.
187         LayoutRect inflatedWheelHandlerBounds = frameView->fixedScrollableAreaBoundsInflatedForScrolling(LayoutRect(wheelHandlerRegion.first.bounds()));
188         wheelHandlerRegion.first.unite(enclosingIntRect(inflatedWheelHandlerBounds));
189     }
190     
191     nonFastScrollableRegion.unite(wheelHandlerRegion.first);
192
193     // FIXME: If this is not the main frame, we could clip the region to the frame's bounds.
194     eventTrackingRegions.uniteSynchronousRegion(eventNames().wheelEvent, nonFastScrollableRegion);
195
196     return eventTrackingRegions;
197 #endif
198 }
199
200 EventTrackingRegions ScrollingCoordinator::absoluteEventTrackingRegions() const
201 {
202     return absoluteEventTrackingRegionsForFrame(m_page->mainFrame());
203 }
204
205 void ScrollingCoordinator::frameViewHasSlowRepaintObjectsDidChange(FrameView& frameView)
206 {
207     ASSERT(isMainThread());
208     ASSERT(m_page);
209
210     if (!coordinatesScrollingForFrameView(frameView))
211         return;
212
213     updateSynchronousScrollingReasons(frameView);
214 }
215
216 void ScrollingCoordinator::frameViewFixedObjectsDidChange(FrameView& frameView)
217 {
218     ASSERT(isMainThread());
219     ASSERT(m_page);
220
221     if (!coordinatesScrollingForFrameView(frameView))
222         return;
223
224     updateSynchronousScrollingReasons(frameView);
225 }
226
227 GraphicsLayer* ScrollingCoordinator::scrollContainerLayerForFrameView(FrameView& frameView)
228 {
229     if (auto* renderView = frameView.frame().contentRenderer())
230         return renderView->compositor().scrollContainerLayer();
231     return nullptr;
232 }
233
234 GraphicsLayer* ScrollingCoordinator::scrolledContentsLayerForFrameView(FrameView& frameView)
235 {
236     if (auto* renderView = frameView.frame().contentRenderer())
237         return renderView->compositor().scrolledContentsLayer();
238     return nullptr;
239 }
240
241 GraphicsLayer* ScrollingCoordinator::headerLayerForFrameView(FrameView& frameView)
242 {
243 #if ENABLE(RUBBER_BANDING)
244     if (auto* renderView = frameView.frame().contentRenderer())
245         return renderView->compositor().headerLayer();
246     return nullptr;
247 #else
248     UNUSED_PARAM(frameView);
249     return nullptr;
250 #endif
251 }
252
253 GraphicsLayer* ScrollingCoordinator::footerLayerForFrameView(FrameView& frameView)
254 {
255 #if ENABLE(RUBBER_BANDING)
256     if (auto* renderView = frameView.frame().contentRenderer())
257         return renderView->compositor().footerLayer();
258     return nullptr;
259 #else
260     UNUSED_PARAM(frameView);
261     return nullptr;
262 #endif
263 }
264
265 GraphicsLayer* ScrollingCoordinator::counterScrollingLayerForFrameView(FrameView& frameView)
266 {
267     if (auto* renderView = frameView.frame().contentRenderer())
268         return renderView->compositor().fixedRootBackgroundLayer();
269     return nullptr;
270 }
271
272 GraphicsLayer* ScrollingCoordinator::insetClipLayerForFrameView(FrameView& frameView)
273 {
274     if (auto* renderView = frameView.frame().contentRenderer())
275         return renderView->compositor().clipLayer();
276     return nullptr;
277 }
278
279 GraphicsLayer* ScrollingCoordinator::contentShadowLayerForFrameView(FrameView& frameView)
280 {
281 #if ENABLE(RUBBER_BANDING)
282     if (auto* renderView = frameView.frame().contentRenderer())
283         return renderView->compositor().layerForContentShadow();
284     
285     return nullptr;
286 #else
287     UNUSED_PARAM(frameView);
288     return nullptr;
289 #endif
290 }
291
292 GraphicsLayer* ScrollingCoordinator::rootContentsLayerForFrameView(FrameView& frameView)
293 {
294     if (auto* renderView = frameView.frame().contentRenderer())
295         return renderView->compositor().rootContentsLayer();
296     return nullptr;
297 }
298
299 void ScrollingCoordinator::frameViewRootLayerDidChange(FrameView& frameView)
300 {
301     ASSERT(isMainThread());
302     ASSERT(m_page);
303
304     if (!coordinatesScrollingForFrameView(frameView))
305         return;
306
307     frameViewLayoutUpdated(frameView);
308     updateSynchronousScrollingReasons(frameView);
309 }
310
311 #if PLATFORM(COCOA)
312 void ScrollingCoordinator::handleWheelEventPhase(PlatformWheelEventPhase phase)
313 {
314     ASSERT(isMainThread());
315
316     if (!m_page)
317         return;
318
319     auto* frameView = m_page->mainFrame().view();
320     if (!frameView)
321         return;
322
323     frameView->scrollAnimator().handleWheelEventPhase(phase);
324 }
325 #endif
326
327 bool ScrollingCoordinator::hasVisibleSlowRepaintViewportConstrainedObjects(const FrameView& frameView) const
328 {
329     const FrameView::ViewportConstrainedObjectSet* viewportConstrainedObjects = frameView.viewportConstrainedObjects();
330     if (!viewportConstrainedObjects)
331         return false;
332
333     for (auto& viewportConstrainedObject : *viewportConstrainedObjects) {
334         if (!is<RenderBoxModelObject>(*viewportConstrainedObject) || !viewportConstrainedObject->hasLayer())
335             return true;
336         auto& layer = *downcast<RenderBoxModelObject>(*viewportConstrainedObject).layer();
337         // Any explicit reason that a fixed position element is not composited shouldn't cause slow scrolling.
338         if (!layer.isComposited() && layer.viewportConstrainedNotCompositedReason() == RenderLayer::NoNotCompositedReason)
339             return true;
340     }
341     return false;
342 }
343
344 SynchronousScrollingReasons ScrollingCoordinator::synchronousScrollingReasons(const FrameView& frameView) const
345 {
346     SynchronousScrollingReasons synchronousScrollingReasons = (SynchronousScrollingReasons)0;
347
348     if (m_forceSynchronousScrollLayerPositionUpdates)
349         synchronousScrollingReasons |= ForcedOnMainThread;
350     if (frameView.hasSlowRepaintObjects())
351         synchronousScrollingReasons |= HasSlowRepaintObjects;
352     if (hasVisibleSlowRepaintViewportConstrainedObjects(frameView))
353         synchronousScrollingReasons |= HasNonLayerViewportConstrainedObjects;
354     if (frameView.frame().mainFrame().document() && frameView.frame().document()->isImageDocument())
355         synchronousScrollingReasons |= IsImageDocument;
356
357     return synchronousScrollingReasons;
358 }
359
360 void ScrollingCoordinator::updateSynchronousScrollingReasons(FrameView& frameView)
361 {
362     ASSERT(coordinatesScrollingForFrameView(frameView));
363     setSynchronousScrollingReasons(frameView, synchronousScrollingReasons(frameView));
364 }
365
366 void ScrollingCoordinator::updateSynchronousScrollingReasonsForAllFrames()
367 {
368     for (Frame* frame = &m_page->mainFrame(); frame; frame = frame->tree().traverseNext()) {
369         if (auto* frameView = frame->view()) {
370             if (coordinatesScrollingForFrameView(*frameView))
371                 updateSynchronousScrollingReasons(*frameView);
372         }
373     }
374 }
375
376 void ScrollingCoordinator::setForceSynchronousScrollLayerPositionUpdates(bool forceSynchronousScrollLayerPositionUpdates)
377 {
378     if (m_forceSynchronousScrollLayerPositionUpdates == forceSynchronousScrollLayerPositionUpdates)
379         return;
380
381     m_forceSynchronousScrollLayerPositionUpdates = forceSynchronousScrollLayerPositionUpdates;
382     updateSynchronousScrollingReasonsForAllFrames();
383 }
384
385 bool ScrollingCoordinator::shouldUpdateScrollLayerPositionSynchronously(const FrameView& frameView) const
386 {
387     if (&frameView == m_page->mainFrame().view())
388         return synchronousScrollingReasons(frameView);
389     
390     return true;
391 }
392
393 ScrollingNodeID ScrollingCoordinator::uniqueScrollingNodeID()
394 {
395     static ScrollingNodeID uniqueScrollingNodeID = 1;
396     return uniqueScrollingNodeID++;
397 }
398
399 String ScrollingCoordinator::scrollingStateTreeAsText(ScrollingStateTreeAsTextBehavior) const
400 {
401     return String();
402 }
403
404 String ScrollingCoordinator::synchronousScrollingReasonsAsText(SynchronousScrollingReasons reasons)
405 {
406     StringBuilder stringBuilder;
407
408     if (reasons & ScrollingCoordinator::ForcedOnMainThread)
409         stringBuilder.appendLiteral("Forced on main thread, ");
410     if (reasons & ScrollingCoordinator::HasSlowRepaintObjects)
411         stringBuilder.appendLiteral("Has slow repaint objects, ");
412     if (reasons & ScrollingCoordinator::HasViewportConstrainedObjectsWithoutSupportingFixedLayers)
413         stringBuilder.appendLiteral("Has viewport constrained objects without supporting fixed layers, ");
414     if (reasons & ScrollingCoordinator::HasNonLayerViewportConstrainedObjects)
415         stringBuilder.appendLiteral("Has non-layer viewport-constrained objects, ");
416     if (reasons & ScrollingCoordinator::IsImageDocument)
417         stringBuilder.appendLiteral("Is image document, ");
418
419     if (stringBuilder.length())
420         stringBuilder.resize(stringBuilder.length() - 2);
421     return stringBuilder.toString();
422 }
423
424 String ScrollingCoordinator::synchronousScrollingReasonsAsText() const
425 {
426     if (auto* frameView = m_page->mainFrame().view())
427         return synchronousScrollingReasonsAsText(synchronousScrollingReasons(*frameView));
428
429     return String();
430 }
431
432 TextStream& operator<<(TextStream& ts, ScrollableAreaParameters scrollableAreaParameters)
433 {
434     ts.dumpProperty("horizontal scroll elasticity", scrollableAreaParameters.horizontalScrollElasticity);
435     ts.dumpProperty("vertical scroll elasticity", scrollableAreaParameters.verticalScrollElasticity);
436     ts.dumpProperty("horizontal scrollbar mode", scrollableAreaParameters.horizontalScrollbarMode);
437     ts.dumpProperty("vertical scrollbar mode", scrollableAreaParameters.verticalScrollbarMode);
438     if (scrollableAreaParameters.hasEnabledHorizontalScrollbar)
439         ts.dumpProperty("has enabled horizontal scrollbar", scrollableAreaParameters.hasEnabledHorizontalScrollbar);
440     if (scrollableAreaParameters.hasEnabledVerticalScrollbar)
441         ts.dumpProperty("has enabled vertical scrollbar", scrollableAreaParameters.hasEnabledVerticalScrollbar);
442
443     return ts;
444 }
445
446 TextStream& operator<<(TextStream& ts, ScrollingNodeType nodeType)
447 {
448     switch (nodeType) {
449     case ScrollingNodeType::MainFrame:
450         ts << "main-frame-scrolling";
451         break;
452     case ScrollingNodeType::Subframe:
453         ts << "subframe-scrolling";
454         break;
455     case ScrollingNodeType::FrameHosting:
456         ts << "frame-hosting";
457         break;
458     case ScrollingNodeType::Overflow:
459         ts << "overflow-scrolling";
460         break;
461     case ScrollingNodeType::Fixed:
462         ts << "fixed";
463         break;
464     case ScrollingNodeType::Sticky:
465         ts << "sticky";
466         break;
467     }
468     return ts;
469 }
470
471 TextStream& operator<<(TextStream& ts, ScrollingLayerPositionAction action)
472 {
473     switch (action) {
474     case ScrollingLayerPositionAction::Set:
475         ts << "set";
476         break;
477     case ScrollingLayerPositionAction::SetApproximate:
478         ts << "set approximate";
479         break;
480     case ScrollingLayerPositionAction::Sync:
481         ts << "sync";
482         break;
483     }
484     return ts;
485 }
486
487 TextStream& operator<<(TextStream& ts, ViewportRectStability stability)
488 {
489     switch (stability) {
490     case ViewportRectStability::Stable:
491         ts << "stable";
492         break;
493     case ViewportRectStability::Unstable:
494         ts << "unstable";
495         break;
496     case ViewportRectStability::ChangingObscuredInsetsInteractively:
497         ts << "changing obscured insets interactively";
498         break;
499     }
500     return ts;
501 }
502
503 } // namespace WebCore