Limit user-agent interactions based on the touch-action property on iOS
[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::scrollLayerForScrollableArea(ScrollableArea& scrollableArea)
228 {
229     return scrollableArea.layerForScrolling();
230 }
231
232 GraphicsLayer* ScrollingCoordinator::scrollLayerForFrameView(FrameView& frameView)
233 {
234     if (auto* renderView = frameView.frame().contentRenderer())
235         return renderView->compositor().scrollLayer();
236     return nullptr;
237 }
238
239 GraphicsLayer* ScrollingCoordinator::headerLayerForFrameView(FrameView& frameView)
240 {
241 #if ENABLE(RUBBER_BANDING)
242     if (auto* renderView = frameView.frame().contentRenderer())
243         return renderView->compositor().headerLayer();
244     return nullptr;
245 #else
246     UNUSED_PARAM(frameView);
247     return nullptr;
248 #endif
249 }
250
251 GraphicsLayer* ScrollingCoordinator::footerLayerForFrameView(FrameView& frameView)
252 {
253 #if ENABLE(RUBBER_BANDING)
254     if (auto* renderView = frameView.frame().contentRenderer())
255         return renderView->compositor().footerLayer();
256     return nullptr;
257 #else
258     UNUSED_PARAM(frameView);
259     return nullptr;
260 #endif
261 }
262
263 GraphicsLayer* ScrollingCoordinator::counterScrollingLayerForFrameView(FrameView& frameView)
264 {
265     if (auto* renderView = frameView.frame().contentRenderer())
266         return renderView->compositor().fixedRootBackgroundLayer();
267     return nullptr;
268 }
269
270 GraphicsLayer* ScrollingCoordinator::insetClipLayerForFrameView(FrameView& frameView)
271 {
272     if (auto* renderView = frameView.frame().contentRenderer())
273         return renderView->compositor().clipLayer();
274     return nullptr;
275 }
276
277 GraphicsLayer* ScrollingCoordinator::contentShadowLayerForFrameView(FrameView& frameView)
278 {
279 #if ENABLE(RUBBER_BANDING)
280     if (auto* renderView = frameView.frame().contentRenderer())
281         return renderView->compositor().layerForContentShadow();
282     
283     return nullptr;
284 #else
285     UNUSED_PARAM(frameView);
286     return nullptr;
287 #endif
288 }
289
290 GraphicsLayer* ScrollingCoordinator::rootContentLayerForFrameView(FrameView& frameView)
291 {
292     if (auto* renderView = frameView.frame().contentRenderer())
293         return renderView->compositor().rootContentLayer();
294     return nullptr;
295 }
296
297 void ScrollingCoordinator::frameViewRootLayerDidChange(FrameView& frameView)
298 {
299     ASSERT(isMainThread());
300     ASSERT(m_page);
301
302     if (!coordinatesScrollingForFrameView(frameView))
303         return;
304
305     frameViewLayoutUpdated(frameView);
306     updateSynchronousScrollingReasons(frameView);
307 }
308
309 #if PLATFORM(COCOA)
310 void ScrollingCoordinator::handleWheelEventPhase(PlatformWheelEventPhase phase)
311 {
312     ASSERT(isMainThread());
313
314     if (!m_page)
315         return;
316
317     auto* frameView = m_page->mainFrame().view();
318     if (!frameView)
319         return;
320
321     frameView->scrollAnimator().handleWheelEventPhase(phase);
322 }
323 #endif
324
325 bool ScrollingCoordinator::hasVisibleSlowRepaintViewportConstrainedObjects(const FrameView& frameView) const
326 {
327     const FrameView::ViewportConstrainedObjectSet* viewportConstrainedObjects = frameView.viewportConstrainedObjects();
328     if (!viewportConstrainedObjects)
329         return false;
330
331     for (auto& viewportConstrainedObject : *viewportConstrainedObjects) {
332         if (!is<RenderBoxModelObject>(*viewportConstrainedObject) || !viewportConstrainedObject->hasLayer())
333             return true;
334         auto& layer = *downcast<RenderBoxModelObject>(*viewportConstrainedObject).layer();
335         // Any explicit reason that a fixed position element is not composited shouldn't cause slow scrolling.
336         if (!layer.isComposited() && layer.viewportConstrainedNotCompositedReason() == RenderLayer::NoNotCompositedReason)
337             return true;
338     }
339     return false;
340 }
341
342 SynchronousScrollingReasons ScrollingCoordinator::synchronousScrollingReasons(const FrameView& frameView) const
343 {
344     SynchronousScrollingReasons synchronousScrollingReasons = (SynchronousScrollingReasons)0;
345
346     if (m_forceSynchronousScrollLayerPositionUpdates)
347         synchronousScrollingReasons |= ForcedOnMainThread;
348     if (frameView.hasSlowRepaintObjects())
349         synchronousScrollingReasons |= HasSlowRepaintObjects;
350     if (hasVisibleSlowRepaintViewportConstrainedObjects(frameView))
351         synchronousScrollingReasons |= HasNonLayerViewportConstrainedObjects;
352     if (frameView.frame().mainFrame().document() && frameView.frame().document()->isImageDocument())
353         synchronousScrollingReasons |= IsImageDocument;
354
355     return synchronousScrollingReasons;
356 }
357
358 void ScrollingCoordinator::updateSynchronousScrollingReasons(FrameView& frameView)
359 {
360     ASSERT(coordinatesScrollingForFrameView(frameView));
361     setSynchronousScrollingReasons(frameView, synchronousScrollingReasons(frameView));
362 }
363
364 void ScrollingCoordinator::updateSynchronousScrollingReasonsForAllFrames()
365 {
366     for (Frame* frame = &m_page->mainFrame(); frame; frame = frame->tree().traverseNext()) {
367         if (auto* frameView = frame->view()) {
368             if (coordinatesScrollingForFrameView(*frameView))
369                 updateSynchronousScrollingReasons(*frameView);
370         }
371     }
372 }
373
374 void ScrollingCoordinator::setForceSynchronousScrollLayerPositionUpdates(bool forceSynchronousScrollLayerPositionUpdates)
375 {
376     if (m_forceSynchronousScrollLayerPositionUpdates == forceSynchronousScrollLayerPositionUpdates)
377         return;
378
379     m_forceSynchronousScrollLayerPositionUpdates = forceSynchronousScrollLayerPositionUpdates;
380     updateSynchronousScrollingReasonsForAllFrames();
381 }
382
383 bool ScrollingCoordinator::shouldUpdateScrollLayerPositionSynchronously(const FrameView& frameView) const
384 {
385     if (&frameView == m_page->mainFrame().view())
386         return synchronousScrollingReasons(frameView);
387     
388     return true;
389 }
390
391 ScrollingNodeID ScrollingCoordinator::uniqueScrollingNodeID()
392 {
393     static ScrollingNodeID uniqueScrollingNodeID = 1;
394     return uniqueScrollingNodeID++;
395 }
396
397 String ScrollingCoordinator::scrollingStateTreeAsText(ScrollingStateTreeAsTextBehavior) const
398 {
399     return String();
400 }
401
402 String ScrollingCoordinator::synchronousScrollingReasonsAsText(SynchronousScrollingReasons reasons)
403 {
404     StringBuilder stringBuilder;
405
406     if (reasons & ScrollingCoordinator::ForcedOnMainThread)
407         stringBuilder.appendLiteral("Forced on main thread, ");
408     if (reasons & ScrollingCoordinator::HasSlowRepaintObjects)
409         stringBuilder.appendLiteral("Has slow repaint objects, ");
410     if (reasons & ScrollingCoordinator::HasViewportConstrainedObjectsWithoutSupportingFixedLayers)
411         stringBuilder.appendLiteral("Has viewport constrained objects without supporting fixed layers, ");
412     if (reasons & ScrollingCoordinator::HasNonLayerViewportConstrainedObjects)
413         stringBuilder.appendLiteral("Has non-layer viewport-constrained objects, ");
414     if (reasons & ScrollingCoordinator::IsImageDocument)
415         stringBuilder.appendLiteral("Is image document, ");
416
417     if (stringBuilder.length())
418         stringBuilder.resize(stringBuilder.length() - 2);
419     return stringBuilder.toString();
420 }
421
422 String ScrollingCoordinator::synchronousScrollingReasonsAsText() const
423 {
424     if (auto* frameView = m_page->mainFrame().view())
425         return synchronousScrollingReasonsAsText(synchronousScrollingReasons(*frameView));
426
427     return String();
428 }
429
430 TextStream& operator<<(TextStream& ts, ScrollableAreaParameters scrollableAreaParameters)
431 {
432     ts.dumpProperty("horizontal scroll elasticity", scrollableAreaParameters.horizontalScrollElasticity);
433     ts.dumpProperty("vertical scroll elasticity", scrollableAreaParameters.verticalScrollElasticity);
434     ts.dumpProperty("horizontal scrollbar mode", scrollableAreaParameters.horizontalScrollbarMode);
435     ts.dumpProperty("vertical scrollbar mode", scrollableAreaParameters.verticalScrollbarMode);
436     if (scrollableAreaParameters.hasEnabledHorizontalScrollbar)
437         ts.dumpProperty("has enabled horizontal scrollbar", scrollableAreaParameters.hasEnabledHorizontalScrollbar);
438     if (scrollableAreaParameters.hasEnabledVerticalScrollbar)
439         ts.dumpProperty("has enabled vertical scrollbar", scrollableAreaParameters.hasEnabledVerticalScrollbar);
440
441     return ts;
442 }
443
444 TextStream& operator<<(TextStream& ts, ScrollingNodeType nodeType)
445 {
446     switch (nodeType) {
447     case ScrollingNodeType::MainFrame:
448         ts << "main-frame-scrolling";
449         break;
450     case ScrollingNodeType::Subframe:
451         ts << "subframe-scrolling";
452         break;
453     case ScrollingNodeType::FrameHosting:
454         ts << "frame-hosting";
455         break;
456     case ScrollingNodeType::Overflow:
457         ts << "overflow-scrolling";
458         break;
459     case ScrollingNodeType::Fixed:
460         ts << "fixed";
461         break;
462     case ScrollingNodeType::Sticky:
463         ts << "sticky";
464         break;
465     }
466     return ts;
467 }
468
469 TextStream& operator<<(TextStream& ts, ScrollingLayerPositionAction action)
470 {
471     switch (action) {
472     case ScrollingLayerPositionAction::Set:
473         ts << "set";
474         break;
475     case ScrollingLayerPositionAction::SetApproximate:
476         ts << "set approximate";
477         break;
478     case ScrollingLayerPositionAction::Sync:
479         ts << "sync";
480         break;
481     }
482     return ts;
483 }
484
485 TextStream& operator<<(TextStream& ts, ViewportRectStability stability)
486 {
487     switch (stability) {
488     case ViewportRectStability::Stable:
489         ts << "stable";
490         break;
491     case ViewportRectStability::Unstable:
492         ts << "unstable";
493         break;
494     case ViewportRectStability::ChangingObscuredInsetsInteractively:
495         ts << "changing obscured insets interactively";
496         break;
497     }
498     return ts;
499 }
500
501 } // namespace WebCore