diff --git a/third_party/WebKit/LayoutTests/http/tests/misc/resources/cross-origin-subframe-for-scrolling.html b/third_party/WebKit/LayoutTests/http/tests/misc/resources/cross-origin-subframe-for-scrolling.html new file mode 100644 index 0000000000000..75414848f7d74 --- /dev/null +++ b/third_party/WebKit/LayoutTests/http/tests/misc/resources/cross-origin-subframe-for-scrolling.html @@ -0,0 +1,28 @@ + + +
+ + \ No newline at end of file diff --git a/third_party/WebKit/LayoutTests/http/tests/misc/scroll-cross-origin-iframes-expected.txt b/third_party/WebKit/LayoutTests/http/tests/misc/scroll-cross-origin-iframes-expected.txt new file mode 100644 index 0000000000000..c97dacb6e8a5b --- /dev/null +++ b/third_party/WebKit/LayoutTests/http/tests/misc/scroll-cross-origin-iframes-expected.txt @@ -0,0 +1,11 @@ +Verify that two sibling cross-origin iframes both correctly scroll on MouseWheel events, as per https://crbug.com/675695. + +On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". + + +PASS event.data.scrollTop is 40 +PASS event.data.scrollTop is 40 +PASS successfullyParsed is true + +TEST COMPLETE + diff --git a/third_party/WebKit/LayoutTests/http/tests/misc/scroll-cross-origin-iframes.html b/third_party/WebKit/LayoutTests/http/tests/misc/scroll-cross-origin-iframes.html new file mode 100644 index 0000000000000..acd8309160120 --- /dev/null +++ b/third_party/WebKit/LayoutTests/http/tests/misc/scroll-cross-origin-iframes.html @@ -0,0 +1,44 @@ + + + + + + \ No newline at end of file diff --git a/third_party/WebKit/Source/core/frame/FrameView.cpp b/third_party/WebKit/Source/core/frame/FrameView.cpp index d76f103605d5c..20f073c65f284 100644 --- a/third_party/WebKit/Source/core/frame/FrameView.cpp +++ b/third_party/WebKit/Source/core/frame/FrameView.cpp @@ -566,11 +566,30 @@ ScrollingCoordinator* FrameView::scrollingCoordinator() const { } CompositorAnimationHost* FrameView::compositorAnimationHost() const { + // When m_animationHost is not nullptr, this is the FrameView for an OOPIF. + if (m_animationHost) + return m_animationHost.get(); + + if (m_frame->localFrameRoot() != m_frame) + return m_frame->localFrameRoot()->view()->compositorAnimationHost(); + + if (!m_frame->isMainFrame()) + return nullptr; + ScrollingCoordinator* c = scrollingCoordinator(); return c ? c->compositorAnimationHost() : nullptr; } CompositorAnimationTimeline* FrameView::compositorAnimationTimeline() const { + if (m_animationTimeline) + return m_animationTimeline.get(); + + if (m_frame->localFrameRoot() != m_frame) + return m_frame->localFrameRoot()->view()->compositorAnimationTimeline(); + + if (!m_frame->isMainFrame()) + return nullptr; + ScrollingCoordinator* c = scrollingCoordinator(); return c ? c->compositorAnimationTimeline() : nullptr; } @@ -4999,4 +5018,14 @@ void FrameView::applyTransformForTopFrameSpace(TransformState& transformState) { LayoutSize(-viewportIntersectionRect.x(), -viewportIntersectionRect.y())); } +void FrameView::setAnimationTimeline( + std::unique_ptr timeline) { + m_animationTimeline = std::move(timeline); +} + +void FrameView::setAnimationHost( + std::unique_ptr host) { + m_animationHost = std::move(host); +} + } // namespace blink diff --git a/third_party/WebKit/Source/core/frame/FrameView.h b/third_party/WebKit/Source/core/frame/FrameView.h index 0dcff6e507e6c..4568af5b52f42 100644 --- a/third_party/WebKit/Source/core/frame/FrameView.h +++ b/third_party/WebKit/Source/core/frame/FrameView.h @@ -40,6 +40,8 @@ #include "core/paint/ScrollbarManager.h" #include "platform/RuntimeEnabledFeatures.h" #include "platform/Widget.h" +#include "platform/animation/CompositorAnimationHost.h" +#include "platform/animation/CompositorAnimationTimeline.h" #include "platform/geometry/IntRect.h" #include "platform/geometry/LayoutRect.h" #include "platform/graphics/Color.h" @@ -819,6 +821,14 @@ class CORE_EXPORT FrameView final void applyTransformForTopFrameSpace(TransformState&); + // TODO(kenrb): These are temporary methods pending resolution of + // https://crbug.com/680606. Animation timelines and hosts for scrolling + // are normally owned by ScrollingCoordinator, but there is only one + // of those objects per page. To get around this, we temporarily stash a + // unique timeline and host on each OOPIF FrameView. + void setAnimationTimeline(std::unique_ptr); + void setAnimationHost(std::unique_ptr); + protected: // Scroll the content via the compositor. bool scrollContentsFastPath(const IntSize& scrollDelta); @@ -1190,6 +1200,10 @@ class CORE_EXPORT FrameView final // The size of the vector depends on the number of // main thread scrolling reasons. Vector m_mainThreadScrollingReasonsCounter; + + // TODO(kenrb): Remove these when https://crbug.com/680606 is resolved. + std::unique_ptr m_animationTimeline; + std::unique_ptr m_animationHost; }; inline void FrameView::incrementVisuallyNonEmptyCharacterCount(unsigned count) { diff --git a/third_party/WebKit/Source/core/frame/VisualViewport.cpp b/third_party/WebKit/Source/core/frame/VisualViewport.cpp index 7899bfb739fa6..38b97c84f41a2 100644 --- a/third_party/WebKit/Source/core/frame/VisualViewport.cpp +++ b/third_party/WebKit/Source/core/frame/VisualViewport.cpp @@ -801,12 +801,14 @@ bool VisualViewport::shouldDisableDesktopWorkarounds() const { } CompositorAnimationHost* VisualViewport::compositorAnimationHost() const { + DCHECK(frameHost().page().mainFrame()->isLocalFrame()); ScrollingCoordinator* c = frameHost().page().scrollingCoordinator(); return c ? c->compositorAnimationHost() : nullptr; } CompositorAnimationTimeline* VisualViewport::compositorAnimationTimeline() const { + DCHECK(frameHost().page().mainFrame()->isLocalFrame()); ScrollingCoordinator* c = frameHost().page().scrollingCoordinator(); return c ? c->compositorAnimationTimeline() : nullptr; } diff --git a/third_party/WebKit/Source/core/page/Page.cpp b/third_party/WebKit/Source/core/page/Page.cpp index 671df370fac83..a48697de757aa 100644 --- a/third_party/WebKit/Source/core/page/Page.cpp +++ b/third_party/WebKit/Source/core/page/Page.cpp @@ -507,14 +507,16 @@ DEFINE_TRACE(Page) { PageVisibilityNotifier::trace(visitor); } -void Page::layerTreeViewInitialized(WebLayerTreeView& layerTreeView) { +void Page::layerTreeViewInitialized(WebLayerTreeView& layerTreeView, + FrameView* view) { if (scrollingCoordinator()) - scrollingCoordinator()->layerTreeViewInitialized(layerTreeView); + scrollingCoordinator()->layerTreeViewInitialized(layerTreeView, view); } -void Page::willCloseLayerTreeView(WebLayerTreeView& layerTreeView) { +void Page::willCloseLayerTreeView(WebLayerTreeView& layerTreeView, + FrameView* view) { if (m_scrollingCoordinator) - m_scrollingCoordinator->willCloseLayerTreeView(layerTreeView); + m_scrollingCoordinator->willCloseLayerTreeView(layerTreeView, view); } void Page::willBeDestroyed() { diff --git a/third_party/WebKit/Source/core/page/Page.h b/third_party/WebKit/Source/core/page/Page.h index 133260a54178c..c23e07a75a28e 100644 --- a/third_party/WebKit/Source/core/page/Page.h +++ b/third_party/WebKit/Source/core/page/Page.h @@ -226,8 +226,8 @@ class CORE_EXPORT Page final : public GarbageCollectedFinalized, DECLARE_TRACE(); - void layerTreeViewInitialized(WebLayerTreeView&); - void willCloseLayerTreeView(WebLayerTreeView&); + void layerTreeViewInitialized(WebLayerTreeView&, FrameView*); + void willCloseLayerTreeView(WebLayerTreeView&, FrameView*); void willBeDestroyed(); diff --git a/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.cpp b/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.cpp index aef4256f37f49..feeddc1a5f29d 100644 --- a/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.cpp +++ b/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.cpp @@ -508,8 +508,19 @@ bool ScrollingCoordinator::scrollableAreaScrollLayerDidChange( isForRootLayer(scrollableArea)) m_page->chromeClient().registerViewportLayers(); - scrollableArea->layerForScrollingDidChange( - m_programmaticScrollAnimatorTimeline.get()); + CompositorAnimationTimeline* timeline; + // FrameView::compositorAnimationTimeline() can indirectly return + // m_programmaticScrollAnimatorTimeline if it does not have its own + // timeline. + if (scrollableArea->isFrameView()) { + timeline = toFrameView(scrollableArea)->compositorAnimationTimeline(); + } else if (scrollableArea->isPaintLayerScrollableArea()) { + timeline = toPaintLayerScrollableArea(scrollableArea) + ->compositorAnimationTimeline(); + } else { + timeline = m_programmaticScrollAnimatorTimeline.get(); + } + scrollableArea->layerForScrollingDidChange(timeline); return !!webLayer; } @@ -852,20 +863,37 @@ void ScrollingCoordinator::setShouldUpdateScrollLayerPositionOnMainThread( } void ScrollingCoordinator::layerTreeViewInitialized( - WebLayerTreeView& layerTreeView) { + WebLayerTreeView& layerTreeView, + FrameView* view) { if (Platform::current()->isThreadedAnimationEnabled() && layerTreeView.compositorAnimationHost()) { - m_animationHost = WTF::makeUnique( - layerTreeView.compositorAnimationHost()); - m_programmaticScrollAnimatorTimeline = + std::unique_ptr timeline = CompositorAnimationTimeline::create(); - m_animationHost->addTimeline(*m_programmaticScrollAnimatorTimeline.get()); + std::unique_ptr host = + WTF::makeUnique( + layerTreeView.compositorAnimationHost()); + if (view && view->frame().localFrameRoot() != m_page->mainFrame()) { + view->setAnimationHost(std::move(host)); + view->setAnimationTimeline(std::move(timeline)); + view->compositorAnimationHost()->addTimeline( + *view->compositorAnimationTimeline()); + } else { + m_animationHost = std::move(host); + m_programmaticScrollAnimatorTimeline = std::move(timeline); + m_animationHost->addTimeline(*m_programmaticScrollAnimatorTimeline.get()); + } } } void ScrollingCoordinator::willCloseLayerTreeView( - WebLayerTreeView& layerTreeView) { - if (m_programmaticScrollAnimatorTimeline) { + WebLayerTreeView& layerTreeView, + FrameView* view) { + if (view && view->frame().localFrameRoot() != m_page->mainFrame()) { + view->compositorAnimationHost()->removeTimeline( + *view->compositorAnimationTimeline()); + view->setAnimationTimeline(nullptr); + view->setAnimationHost(nullptr); + } else if (m_programmaticScrollAnimatorTimeline) { m_animationHost->removeTimeline( *m_programmaticScrollAnimatorTimeline.get()); m_programmaticScrollAnimatorTimeline = nullptr; diff --git a/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.h b/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.h index 9f681cdb3fa09..161f9786cb93e 100644 --- a/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.h +++ b/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.h @@ -62,8 +62,12 @@ class CORE_EXPORT ScrollingCoordinator final ~ScrollingCoordinator(); DECLARE_TRACE(); - void layerTreeViewInitialized(WebLayerTreeView&); - void willCloseLayerTreeView(WebLayerTreeView&); + // The FrameView argument is optional, nullptr causes the the scrolling + // animation host and timeline to be owned by the ScrollingCoordinator. When + // not null, the host and timeline are attached to the specified FrameView. + // A FrameView only needs to own them when it is the view for an OOPIF. + void layerTreeViewInitialized(WebLayerTreeView&, FrameView*); + void willCloseLayerTreeView(WebLayerTreeView&, FrameView*); void willBeDestroyed(); diff --git a/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp b/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp index f7aeadb1036ab..017c2ed163cc6 100644 --- a/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp +++ b/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp @@ -1882,18 +1882,12 @@ void PaintLayerScrollableArea::resetRebuildScrollbarLayerFlags() { CompositorAnimationHost* PaintLayerScrollableArea::compositorAnimationHost() const { - if (ScrollingCoordinator* coordinator = getScrollingCoordinator()) - return coordinator->compositorAnimationHost(); - - return nullptr; + return m_layer.layoutObject()->frameView()->compositorAnimationHost(); } CompositorAnimationTimeline* PaintLayerScrollableArea::compositorAnimationTimeline() const { - if (ScrollingCoordinator* coordinator = getScrollingCoordinator()) - return coordinator->compositorAnimationTimeline(); - - return nullptr; + return m_layer.layoutObject()->frameView()->compositorAnimationTimeline(); } PaintLayerScrollableArea* diff --git a/third_party/WebKit/Source/web/WebFrameWidgetImpl.cpp b/third_party/WebKit/Source/web/WebFrameWidgetImpl.cpp index 4f686427e736d..c0e69a2d0a716 100644 --- a/third_party/WebKit/Source/web/WebFrameWidgetImpl.cpp +++ b/third_party/WebKit/Source/web/WebFrameWidgetImpl.cpp @@ -651,8 +651,10 @@ bool WebFrameWidgetImpl::isAcceleratedCompositingActive() const { } void WebFrameWidgetImpl::willCloseLayerTreeView() { - if (m_layerTreeView) - page()->willCloseLayerTreeView(*m_layerTreeView); + if (m_layerTreeView) { + page()->willCloseLayerTreeView(*m_layerTreeView, + m_localRoot->frame()->view()); + } setIsAcceleratedCompositingActive(false); m_mutator = nullptr; @@ -996,8 +998,10 @@ void WebFrameWidgetImpl::initializeLayerTreeView() { devTools->layerTreeViewChanged(m_layerTreeView); page()->settings().setAcceleratedCompositingEnabled(m_layerTreeView); - if (m_layerTreeView) - page()->layerTreeViewInitialized(*m_layerTreeView); + if (m_layerTreeView) { + page()->layerTreeViewInitialized(*m_layerTreeView, + m_localRoot->frame()->view()); + } // FIXME: only unittests, click to play, Android priting, and printing (for // headers and footers) make this assert necessary. We should make them not diff --git a/third_party/WebKit/Source/web/WebPagePopupImpl.cpp b/third_party/WebKit/Source/web/WebPagePopupImpl.cpp index 7e1d2c3d94fe1..ef30de3ab41f0 100644 --- a/third_party/WebKit/Source/web/WebPagePopupImpl.cpp +++ b/third_party/WebKit/Source/web/WebPagePopupImpl.cpp @@ -395,7 +395,12 @@ void WebPagePopupImpl::setIsAcceleratedCompositingActive(bool enter) { m_isAcceleratedCompositingActive = true; m_animationHost = WTF::makeUnique( m_layerTreeView->compositorAnimationHost()); - m_page->layerTreeViewInitialized(*m_layerTreeView); + m_page->layerTreeViewInitialized(*m_layerTreeView, + m_popupClient->ownerElement() + .document() + .frame() + ->localFrameRoot() + ->view()); } else { m_isAcceleratedCompositingActive = false; m_animationHost = nullptr; @@ -412,8 +417,14 @@ void WebPagePopupImpl::beginFrame(double lastFrameTimeMonotonic) { } void WebPagePopupImpl::willCloseLayerTreeView() { - if (m_page && m_layerTreeView) - m_page->willCloseLayerTreeView(*m_layerTreeView); + if (m_page && m_layerTreeView) { + m_page->willCloseLayerTreeView(*m_layerTreeView, + m_popupClient->ownerElement() + .document() + .frame() + ->localFrameRoot() + ->view()); + } setIsAcceleratedCompositingActive(false); m_layerTreeView = nullptr; diff --git a/third_party/WebKit/Source/web/WebViewImpl.cpp b/third_party/WebKit/Source/web/WebViewImpl.cpp index 6a7688b481756..24a1fbf205c19 100644 --- a/third_party/WebKit/Source/web/WebViewImpl.cpp +++ b/third_party/WebKit/Source/web/WebViewImpl.cpp @@ -2515,7 +2515,7 @@ void WebViewImpl::willCloseLayerTreeView() { } if (m_layerTreeView) - page()->willCloseLayerTreeView(*m_layerTreeView); + page()->willCloseLayerTreeView(*m_layerTreeView, nullptr); setRootLayer(nullptr); m_animationHost = nullptr; @@ -3956,7 +3956,7 @@ void WebViewImpl::initializeLayerTreeView() { m_page->settings().setAcceleratedCompositingEnabled(m_layerTreeView); if (m_layerTreeView) - m_page->layerTreeViewInitialized(*m_layerTreeView); + m_page->layerTreeViewInitialized(*m_layerTreeView, nullptr); // FIXME: only unittests, click to play, Android printing, and printing (for // headers and footers) make this assert necessary. We should make them not