diff options
Diffstat (limited to 'Source/WebCore/page/scrolling/ScrollingCoordinator.cpp')
-rw-r--r-- | Source/WebCore/page/scrolling/ScrollingCoordinator.cpp | 345 |
1 files changed, 217 insertions, 128 deletions
diff --git a/Source/WebCore/page/scrolling/ScrollingCoordinator.cpp b/Source/WebCore/page/scrolling/ScrollingCoordinator.cpp index 93dfb0cec..ff34266a7 100644 --- a/Source/WebCore/page/scrolling/ScrollingCoordinator.cpp +++ b/Source/WebCore/page/scrolling/ScrollingCoordinator.cpp @@ -28,6 +28,7 @@ #include "ScrollingCoordinator.h" #include "Document.h" +#include "EventNames.h" #include "FrameView.h" #include "GraphicsLayer.h" #include "IntRect.h" @@ -36,35 +37,38 @@ #include "PlatformWheelEvent.h" #include "PluginViewBase.h" #include "Region.h" +#include "RenderLayerCompositor.h" #include "RenderView.h" #include "ScrollAnimator.h" +#include "Settings.h" +#include "TextStream.h" #include <wtf/MainThread.h> #include <wtf/text/StringBuilder.h> -#if USE(ACCELERATED_COMPOSITING) -#include "RenderLayerCompositor.h" -#endif - #if USE(COORDINATED_GRAPHICS) #include "ScrollingCoordinatorCoordinatedGraphics.h" #endif +#if ENABLE(WEB_REPLAY) +#include "ReplayController.h" +#include <replay/InputCursor.h> +#endif + namespace WebCore { -#if !PLATFORM(MAC) -PassRefPtr<ScrollingCoordinator> ScrollingCoordinator::create(Page* page) +#if !PLATFORM(COCOA) +Ref<ScrollingCoordinator> ScrollingCoordinator::create(Page* page) { #if USE(COORDINATED_GRAPHICS) - return adoptRef(new ScrollingCoordinatorCoordinatedGraphics(page)); + return adoptRef(*new ScrollingCoordinatorCoordinatedGraphics(page)); #endif - return adoptRef(new ScrollingCoordinator(page)); + return adoptRef(*new ScrollingCoordinator(page)); } #endif ScrollingCoordinator::ScrollingCoordinator(Page* page) : m_page(page) - , m_forceSynchronousScrollLayerPositionUpdates(false) { } @@ -76,88 +80,112 @@ ScrollingCoordinator::~ScrollingCoordinator() void ScrollingCoordinator::pageDestroyed() { ASSERT(m_page); - m_page = 0; + m_page = nullptr; } -bool ScrollingCoordinator::coordinatesScrollingForFrameView(FrameView* frameView) const +bool ScrollingCoordinator::coordinatesScrollingForFrameView(const FrameView& frameView) const { ASSERT(isMainThread()); ASSERT(m_page); - // We currently only handle the main frame. - if (!frameView->frame().isMainFrame()) + if (!frameView.frame().isMainFrame() && !m_page->settings().scrollingTreeIncludesFrames()) return false; - // We currently only support composited mode. -#if USE(ACCELERATED_COMPOSITING) RenderView* renderView = m_page->mainFrame().contentRenderer(); if (!renderView) return false; return renderView->usesCompositing(); -#else - return false; -#endif } -Region ScrollingCoordinator::computeNonFastScrollableRegion(const Frame* frame, const IntPoint& frameLocation) const +EventTrackingRegions ScrollingCoordinator::absoluteEventTrackingRegionsForFrame(const Frame& frame) const { - Region nonFastScrollableRegion; - FrameView* frameView = frame->view(); + auto* renderView = frame.contentRenderer(); + if (!renderView || renderView->renderTreeBeingDestroyed()) + return EventTrackingRegions(); + +#if ENABLE(IOS_TOUCH_EVENTS) + // On iOS, we use nonFastScrollableRegion to represent the region covered by elements with touch event handlers. + ASSERT(frame.isMainFrame()); + auto* document = frame.document(); + if (!document) + return EventTrackingRegions(); + return document->eventTrackingRegions(); +#else + auto* frameView = frame.view(); if (!frameView) - return nonFastScrollableRegion; + return EventTrackingRegions(); - IntPoint offset = frameLocation; - offset.moveBy(frameView->frameRect().location()); + Region nonFastScrollableRegion; - if (const FrameView::ScrollableAreaSet* scrollableAreas = frameView->scrollableAreas()) { - for (FrameView::ScrollableAreaSet::const_iterator it = scrollableAreas->begin(), end = scrollableAreas->end(); it != end; ++it) { - ScrollableArea* scrollableArea = *it; -#if USE(ACCELERATED_COMPOSITING) + // FIXME: should ASSERT(!frameView->needsLayout()) here, but need to fix DebugPageOverlays + // to not ask for regions at bad times. + + if (auto* scrollableAreas = frameView->scrollableAreas()) { + for (auto& scrollableArea : *scrollableAreas) { // Composited scrollable areas can be scrolled off the main thread. - if (scrollableArea->usesCompositedScrolling()) + if (scrollableArea->usesAsyncScrolling()) continue; -#endif - IntRect box = scrollableArea->scrollableAreaBoundingBox(); - box.moveBy(offset); + + bool isInsideFixed; + IntRect box = scrollableArea->scrollableAreaBoundingBox(&isInsideFixed); + if (isInsideFixed) + box = IntRect(frameView->fixedScrollableAreaBoundsInflatedForScrolling(LayoutRect(box))); + nonFastScrollableRegion.unite(box); } } - for (auto it = frameView->children().begin(), end = frameView->children().end(); it != end; ++it) { - if (!(*it)->isPluginViewBase()) + for (auto& widget : frameView->widgetsInRenderTree()) { + if (!is<PluginViewBase>(*widget)) + continue; + if (!downcast<PluginViewBase>(*widget).wantsWheelEvents()) + continue; + auto* renderWidget = RenderWidget::find(*widget); + if (!renderWidget) continue; - PluginViewBase* pluginViewBase = toPluginViewBase((*it).get()); - if (pluginViewBase->wantsWheelEvents()) - nonFastScrollableRegion.unite(pluginViewBase->frameRect()); + nonFastScrollableRegion.unite(renderWidget->absoluteBoundingBoxRect()); } + + EventTrackingRegions eventTrackingRegions; - for (Frame* subframe = frame->tree().firstChild(); subframe; subframe = subframe->tree().nextSibling()) - nonFastScrollableRegion.unite(computeNonFastScrollableRegion(subframe, offset)); + // FIXME: if we've already accounted for this subframe as a scrollable area, we can avoid recursing into it here. + for (Frame* subframe = frame.tree().firstChild(); subframe; subframe = subframe->tree().nextSibling()) { + auto* subframeView = subframe->view(); + if (!subframeView) + continue; - return nonFastScrollableRegion; -} + EventTrackingRegions subframeRegion = absoluteEventTrackingRegionsForFrame(*subframe); + // Map from the frame document to our document. + IntPoint offset = subframeView->contentsToContainingViewContents(IntPoint()); -unsigned ScrollingCoordinator::computeCurrentWheelEventHandlerCount() -{ - unsigned wheelEventHandlerCount = 0; + // FIXME: this translation ignores non-trival transforms on the frame. + subframeRegion.translate(toIntSize(offset)); + eventTrackingRegions.unite(subframeRegion); + } - for (Frame* frame = &m_page->mainFrame(); frame; frame = frame->tree().traverseNext()) { - if (frame->document()) - wheelEventHandlerCount += frame->document()->wheelEventHandlerCount(); + auto wheelHandlerRegion = frame.document()->absoluteRegionForEventTargets(frame.document()->wheelEventTargets()); + bool wheelHandlerInFixedContent = wheelHandlerRegion.second; + if (wheelHandlerInFixedContent) { + // FIXME: need to handle position:sticky here too. + LayoutRect inflatedWheelHandlerBounds = frameView->fixedScrollableAreaBoundsInflatedForScrolling(LayoutRect(wheelHandlerRegion.first.bounds())); + wheelHandlerRegion.first.unite(enclosingIntRect(inflatedWheelHandlerBounds)); } + + nonFastScrollableRegion.unite(wheelHandlerRegion.first); + + // FIXME: If this is not the main frame, we could clip the region to the frame's bounds. + eventTrackingRegions.uniteSynchronousRegion(eventNames().wheelEvent, nonFastScrollableRegion); - return wheelEventHandlerCount; + return eventTrackingRegions; +#endif } -void ScrollingCoordinator::frameViewWheelEventHandlerCountChanged(FrameView* frameView) +EventTrackingRegions ScrollingCoordinator::absoluteEventTrackingRegions() const { - ASSERT(isMainThread()); - ASSERT(m_page); - - recomputeWheelEventHandlerCountForFrameView(frameView); + return absoluteEventTrackingRegionsForFrame(m_page->mainFrame()); } -void ScrollingCoordinator::frameViewHasSlowRepaintObjectsDidChange(FrameView* frameView) +void ScrollingCoordinator::frameViewHasSlowRepaintObjectsDidChange(FrameView& frameView) { ASSERT(isMainThread()); ASSERT(m_page); @@ -165,10 +193,10 @@ void ScrollingCoordinator::frameViewHasSlowRepaintObjectsDidChange(FrameView* fr if (!coordinatesScrollingForFrameView(frameView)) return; - updateSynchronousScrollingReasons(); + updateSynchronousScrollingReasons(frameView); } -void ScrollingCoordinator::frameViewFixedObjectsDidChange(FrameView* frameView) +void ScrollingCoordinator::frameViewFixedObjectsDidChange(FrameView& frameView) { ASSERT(isMainThread()); ASSERT(m_page); @@ -176,75 +204,80 @@ void ScrollingCoordinator::frameViewFixedObjectsDidChange(FrameView* frameView) if (!coordinatesScrollingForFrameView(frameView)) return; - updateSynchronousScrollingReasons(); + updateSynchronousScrollingReasons(frameView); } -#if USE(ACCELERATED_COMPOSITING) -GraphicsLayer* ScrollingCoordinator::scrollLayerForScrollableArea(ScrollableArea* scrollableArea) +GraphicsLayer* ScrollingCoordinator::scrollLayerForScrollableArea(ScrollableArea& scrollableArea) { - return scrollableArea->layerForScrolling(); + return scrollableArea.layerForScrolling(); } -GraphicsLayer* ScrollingCoordinator::horizontalScrollbarLayerForScrollableArea(ScrollableArea* scrollableArea) +GraphicsLayer* ScrollingCoordinator::scrollLayerForFrameView(FrameView& frameView) { - return scrollableArea->layerForHorizontalScrollbar(); -} - -GraphicsLayer* ScrollingCoordinator::verticalScrollbarLayerForScrollableArea(ScrollableArea* scrollableArea) -{ - return scrollableArea->layerForVerticalScrollbar(); -} -#endif - -GraphicsLayer* ScrollingCoordinator::scrollLayerForFrameView(FrameView* frameView) -{ -#if USE(ACCELERATED_COMPOSITING) - if (RenderView* renderView = frameView->frame().contentRenderer()) + if (RenderView* renderView = frameView.frame().contentRenderer()) return renderView->compositor().scrollLayer(); - return 0; -#else - UNUSED_PARAM(frameView); - return 0; -#endif + return nullptr; } -GraphicsLayer* ScrollingCoordinator::headerLayerForFrameView(FrameView* frameView) +GraphicsLayer* ScrollingCoordinator::headerLayerForFrameView(FrameView& frameView) { -#if USE(ACCELERATED_COMPOSITING) && ENABLE(RUBBER_BANDING) - if (RenderView* renderView = frameView->frame().contentRenderer()) - renderView->compositor().headerLayer(); - return 0; +#if ENABLE(RUBBER_BANDING) + if (RenderView* renderView = frameView.frame().contentRenderer()) + return renderView->compositor().headerLayer(); + return nullptr; #else UNUSED_PARAM(frameView); - return 0; + return nullptr; #endif } -GraphicsLayer* ScrollingCoordinator::footerLayerForFrameView(FrameView* frameView) +GraphicsLayer* ScrollingCoordinator::footerLayerForFrameView(FrameView& frameView) { -#if USE(ACCELERATED_COMPOSITING) && ENABLE(RUBBER_BANDING) - if (RenderView* renderView = frameView->frame().contentRenderer()) +#if ENABLE(RUBBER_BANDING) + if (RenderView* renderView = frameView.frame().contentRenderer()) return renderView->compositor().footerLayer(); - return 0; + return nullptr; #else UNUSED_PARAM(frameView); - return 0; + return nullptr; #endif } -GraphicsLayer* ScrollingCoordinator::counterScrollingLayerForFrameView(FrameView* frameView) +GraphicsLayer* ScrollingCoordinator::counterScrollingLayerForFrameView(FrameView& frameView) { -#if USE(ACCELERATED_COMPOSITING) - if (RenderView* renderView = frameView->frame().contentRenderer()) + if (RenderView* renderView = frameView.frame().contentRenderer()) return renderView->compositor().fixedRootBackgroundLayer(); - return 0; + return nullptr; +} + +GraphicsLayer* ScrollingCoordinator::insetClipLayerForFrameView(FrameView& frameView) +{ + if (RenderView* renderView = frameView.frame().contentRenderer()) + return renderView->compositor().clipLayer(); + return nullptr; +} + +GraphicsLayer* ScrollingCoordinator::contentShadowLayerForFrameView(FrameView& frameView) +{ +#if ENABLE(RUBBER_BANDING) + if (RenderView* renderView = frameView.frame().contentRenderer()) + return renderView->compositor().layerForContentShadow(); + + return nullptr; #else UNUSED_PARAM(frameView); - return 0; + return nullptr; #endif } -void ScrollingCoordinator::frameViewRootLayerDidChange(FrameView* frameView) +GraphicsLayer* ScrollingCoordinator::rootContentLayerForFrameView(FrameView& frameView) +{ + if (RenderView* renderView = frameView.frame().contentRenderer()) + return renderView->compositor().rootContentLayer(); + return nullptr; +} + +void ScrollingCoordinator::frameViewRootLayerDidChange(FrameView& frameView) { ASSERT(isMainThread()); ASSERT(m_page); @@ -253,11 +286,10 @@ void ScrollingCoordinator::frameViewRootLayerDidChange(FrameView* frameView) return; frameViewLayoutUpdated(frameView); - recomputeWheelEventHandlerCountForFrameView(frameView); - updateSynchronousScrollingReasons(); + updateSynchronousScrollingReasons(frameView); } -#if PLATFORM(MAC) +#if PLATFORM(COCOA) void ScrollingCoordinator::handleWheelEventPhase(PlatformWheelEventPhase phase) { ASSERT(isMainThread()); @@ -269,57 +301,58 @@ void ScrollingCoordinator::handleWheelEventPhase(PlatformWheelEventPhase phase) if (!frameView) return; - frameView->scrollAnimator()->handleWheelEventPhase(phase); + frameView->scrollAnimator().handleWheelEventPhase(phase); } #endif -bool ScrollingCoordinator::hasVisibleSlowRepaintViewportConstrainedObjects(FrameView* frameView) const +bool ScrollingCoordinator::hasVisibleSlowRepaintViewportConstrainedObjects(const FrameView& frameView) const { - const FrameView::ViewportConstrainedObjectSet* viewportConstrainedObjects = frameView->viewportConstrainedObjects(); + const FrameView::ViewportConstrainedObjectSet* viewportConstrainedObjects = frameView.viewportConstrainedObjects(); if (!viewportConstrainedObjects) return false; -#if USE(ACCELERATED_COMPOSITING) - for (FrameView::ViewportConstrainedObjectSet::const_iterator it = viewportConstrainedObjects->begin(), end = viewportConstrainedObjects->end(); it != end; ++it) { - RenderObject* viewportConstrainedObject = *it; - if (!viewportConstrainedObject->isBoxModelObject() || !viewportConstrainedObject->hasLayer()) + for (auto& viewportConstrainedObject : *viewportConstrainedObjects) { + if (!is<RenderBoxModelObject>(*viewportConstrainedObject) || !viewportConstrainedObject->hasLayer()) return true; - RenderLayer* layer = toRenderBoxModelObject(viewportConstrainedObject)->layer(); + RenderLayer& layer = *downcast<RenderBoxModelObject>(*viewportConstrainedObject).layer(); // Any explicit reason that a fixed position element is not composited shouldn't cause slow scrolling. - if (!layer->isComposited() && layer->viewportConstrainedNotCompositedReason() == RenderLayer::NoNotCompositedReason) + if (!layer.isComposited() && layer.viewportConstrainedNotCompositedReason() == RenderLayer::NoNotCompositedReason) return true; } return false; -#else - return viewportConstrainedObjects->size(); -#endif } -SynchronousScrollingReasons ScrollingCoordinator::synchronousScrollingReasons() const +SynchronousScrollingReasons ScrollingCoordinator::synchronousScrollingReasons(const FrameView& frameView) const { - FrameView* frameView = m_page->mainFrame().view(); - if (!frameView) - return static_cast<SynchronousScrollingReasons>(0); - SynchronousScrollingReasons synchronousScrollingReasons = (SynchronousScrollingReasons)0; if (m_forceSynchronousScrollLayerPositionUpdates) synchronousScrollingReasons |= ForcedOnMainThread; - if (frameView->hasSlowRepaintObjects()) +#if ENABLE(WEB_REPLAY) + InputCursor& cursor = m_page->replayController().activeInputCursor(); + if (cursor.isCapturing() || cursor.isReplaying()) + synchronousScrollingReasons |= ForcedOnMainThread; +#endif + if (frameView.hasSlowRepaintObjects()) synchronousScrollingReasons |= HasSlowRepaintObjects; - if (!supportsFixedPositionLayers() && frameView->hasViewportConstrainedObjects()) + if (!supportsFixedPositionLayers() && frameView.hasViewportConstrainedObjects()) synchronousScrollingReasons |= HasViewportConstrainedObjectsWithoutSupportingFixedLayers; if (supportsFixedPositionLayers() && hasVisibleSlowRepaintViewportConstrainedObjects(frameView)) synchronousScrollingReasons |= HasNonLayerViewportConstrainedObjects; - if (m_page->mainFrame().document() && m_page->mainFrame().document()->isImageDocument()) + if (frameView.frame().mainFrame().document() && frameView.frame().document()->isImageDocument()) synchronousScrollingReasons |= IsImageDocument; return synchronousScrollingReasons; } -void ScrollingCoordinator::updateSynchronousScrollingReasons() +void ScrollingCoordinator::updateSynchronousScrollingReasons(const FrameView& frameView) { - setSynchronousScrollingReasons(synchronousScrollingReasons()); + // FIXME: Once we support async scrolling of iframes, we'll have to track the synchronous scrolling + // reasons per frame (maybe on scrolling tree nodes). + if (!frameView.frame().isMainFrame()) + return; + + setSynchronousScrollingReasons(synchronousScrollingReasons(frameView)); } void ScrollingCoordinator::setForceSynchronousScrollLayerPositionUpdates(bool forceSynchronousScrollLayerPositionUpdates) @@ -328,9 +361,27 @@ void ScrollingCoordinator::setForceSynchronousScrollLayerPositionUpdates(bool fo return; m_forceSynchronousScrollLayerPositionUpdates = forceSynchronousScrollLayerPositionUpdates; - updateSynchronousScrollingReasons(); + if (FrameView* frameView = m_page->mainFrame().view()) + updateSynchronousScrollingReasons(*frameView); } +bool ScrollingCoordinator::shouldUpdateScrollLayerPositionSynchronously(const FrameView& frameView) const +{ + if (&frameView == m_page->mainFrame().view()) + return synchronousScrollingReasons(frameView); + + return true; +} + +#if ENABLE(WEB_REPLAY) +void ScrollingCoordinator::replaySessionStateDidChange() +{ + // FIXME: Once we support async scrolling of iframes, this should go through all subframes. + if (FrameView* frameView = m_page->mainFrame().view()) + updateSynchronousScrollingReasons(*frameView); +} +#endif + ScrollingNodeID ScrollingCoordinator::uniqueScrollLayerID() { static ScrollingNodeID uniqueScrollLayerID = 1; @@ -347,15 +398,15 @@ String ScrollingCoordinator::synchronousScrollingReasonsAsText(SynchronousScroll StringBuilder stringBuilder; if (reasons & ScrollingCoordinator::ForcedOnMainThread) - stringBuilder.append("Forced on main thread, "); + stringBuilder.appendLiteral("Forced on main thread, "); if (reasons & ScrollingCoordinator::HasSlowRepaintObjects) - stringBuilder.append("Has slow repaint objects, "); + stringBuilder.appendLiteral("Has slow repaint objects, "); if (reasons & ScrollingCoordinator::HasViewportConstrainedObjectsWithoutSupportingFixedLayers) - stringBuilder.append("Has viewport constrained objects without supporting fixed layers, "); + stringBuilder.appendLiteral("Has viewport constrained objects without supporting fixed layers, "); if (reasons & ScrollingCoordinator::HasNonLayerViewportConstrainedObjects) - stringBuilder.append("Has non-layer viewport-constrained objects, "); + stringBuilder.appendLiteral("Has non-layer viewport-constrained objects, "); if (reasons & ScrollingCoordinator::IsImageDocument) - stringBuilder.append("Is image document, "); + stringBuilder.appendLiteral("Is image document, "); if (stringBuilder.length()) stringBuilder.resize(stringBuilder.length() - 2); @@ -364,7 +415,45 @@ String ScrollingCoordinator::synchronousScrollingReasonsAsText(SynchronousScroll String ScrollingCoordinator::synchronousScrollingReasonsAsText() const { - return synchronousScrollingReasonsAsText(synchronousScrollingReasons()); + if (FrameView* frameView = m_page->mainFrame().view()) + return synchronousScrollingReasonsAsText(synchronousScrollingReasons(*frameView)); + + return String(); +} + +TextStream& operator<<(TextStream& ts, ScrollingNodeType nodeType) +{ + switch (nodeType) { + case FrameScrollingNode: + ts << "frame-scrolling"; + break; + case OverflowScrollingNode: + ts << "overflow-scrolling"; + break; + case FixedNode: + ts << "fixed"; + break; + case StickyNode: + ts << "sticky"; + break; + } + return ts; +} + +TextStream& operator<<(TextStream& ts, ScrollingLayerPositionAction action) +{ + switch (action) { + case ScrollingLayerPositionAction::Set: + ts << "set"; + break; + case ScrollingLayerPositionAction::SetApproximate: + ts << "set approximate"; + break; + case ScrollingLayerPositionAction::Sync: + ts << "sync"; + break; + } + return ts; } } // namespace WebCore |