diff options
Diffstat (limited to 'third_party/WebKit')
23 files changed, 444 insertions, 70 deletions
diff --git a/third_party/WebKit/LayoutTests/fast/scroll-behavior/smooth-scroll/keyboard-scroll-expected.txt b/third_party/WebKit/LayoutTests/fast/scroll-behavior/smooth-scroll/keyboard-scroll-expected.txt new file mode 100644 index 0000000..9c6d0e3 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/scroll-behavior/smooth-scroll/keyboard-scroll-expected.txt @@ -0,0 +1,18 @@ +Test keyboard smooth scroll. The main purpose of this test is to ensure that smooth scrolling on the compositor works as intended (tested via virtual suite virtual/threaded/). + +On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". + + +PASS downArrow reached target +PASS upArrow reached target +PASS rightArrow reached target +PASS leftArrow reached target +PASS end reached target +PASS home reached target +PASS pageDown reached target +PASS pageUp reached target +PASS reached target +PASS successfullyParsed is true + +TEST COMPLETE +Top of pageBottom of pageLeft of pageRight of pageMiddle of page diff --git a/third_party/WebKit/LayoutTests/fast/scroll-behavior/smooth-scroll/keyboard-scroll.html b/third_party/WebKit/LayoutTests/fast/scroll-behavior/smooth-scroll/keyboard-scroll.html new file mode 100644 index 0000000..310b4e2 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/scroll-behavior/smooth-scroll/keyboard-scroll.html @@ -0,0 +1,114 @@ +<!DOCTYPE html> +<script src="../../../resources/js-test.js"></script> +<script> + window.jsTestIsAsync = true; + var pageHeight = 1200; + var pageWidth = 1000; + + var testScrolls = [ + {key: 'downArrow', expectedX: 0, expectedY: pageHeight - window.innerHeight}, + {key: 'upArrow', expectedX: 0, expectedY: 0}, + {key: 'rightArrow', expectedX: pageWidth - window.innerWidth, expectedY: 0}, + {key: 'leftArrow', expectedX: 0, expectedY: 0}, + {key: 'end', expectedX: 0, expectedY: pageHeight - window.innerHeight}, + {key: 'home', expectedX: 0, expectedY: 0}, + {key: 'pageDown', expectedX: 0, expectedY: pageHeight - window.innerHeight}, + {key: 'pageUp', expectedX: 0, expectedY: 0}, + {key: ' ', expectedX: 0, expectedY: pageHeight - window.innerHeight}, + ]; + var currentTest = -1; + + description("Test keyboard smooth scroll. The main purpose of this\ + test is to ensure that smooth scrolling on the compositor\ + works as intended (tested via virtual suite virtual/threaded/)."); + + function runTestCase(testCase) { + window.eventSender.keyDown(testCase.key); + if (window.scrollX == testCase.expectedX && window.scrollY == testCase.expectedY) { + testPassed(testCase.key + ' reached target'); + startNextTestCase(); + } else { + requestAnimationFrame(function() { + runTestCase(testCase); + }); + } + } + + function startNextTestCase() { + currentTest++; + if (currentTest >= testScrolls.length) { + finishJSTest(); + return; + } + runTestCase(testScrolls[currentTest]); + } + + function runTest() { + if (!window.eventSender || !window.internals) { + finishJSTest(); + return; + } + // Turn on smooth scrolling. + internals.settings.setScrollAnimatorEnabled(true); + + startNextTestCase(); + } + addEventListener('load', runTest); +</script> + +<style> + ::-webkit-scrollbar { + width: 0px; + height: 0px; + } + + div { + width: 200px; + height: 20px; + background-color: red; + } + + html{ + padding: 0px; + margin: 0px; + width: 1000px; + height: 1200px; + } + + .top { + position: absolute; + top: 0px; + left: 300px; + } + + .middle{ + position: absolute; + top: 575px; + left: 300px; + } + + .bottom { + position: absolute; + top: 1180px; + left: 300px; + } + + .left { + position: absolute; + top: 275px; + left: 0px; + } + + .right { + position: absolute; + top: 275px; + left: 800px; + } +</style> +<p id="description" style="width: 800px"></p> +<p id="console" style="width: 800px"></p> +<div class="top">Top of page</div> +<div class="bottom">Bottom of page</div> +<div class="left">Left of page</div> +<div class="right">Right of page</div> +<div class="middle">Middle of page</div> diff --git a/third_party/WebKit/LayoutTests/fast/scroll-behavior/smooth-scroll/mousewheel-scroll-expected.txt b/third_party/WebKit/LayoutTests/fast/scroll-behavior/smooth-scroll/mousewheel-scroll-expected.txt new file mode 100644 index 0000000..c7cb861 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/scroll-behavior/smooth-scroll/mousewheel-scroll-expected.txt @@ -0,0 +1,10 @@ +This test ensures that consecutive mouse wheel ticks scroll to the right offset. The main purpose of this test is to ensure that smooth scrolling on the compositor works as intended (tested via virtual suite virtual/threaded/). + +On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". + + +PASS document.scrollingElement.scrollTop == 80 && document.scrollingElement.scrollLeft == 80 became true +PASS successfullyParsed is true + +TEST COMPLETE + diff --git a/third_party/WebKit/LayoutTests/fast/scroll-behavior/smooth-scroll/mousewheel-scroll.html b/third_party/WebKit/LayoutTests/fast/scroll-behavior/smooth-scroll/mousewheel-scroll.html new file mode 100644 index 0000000..702dbf1 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/scroll-behavior/smooth-scroll/mousewheel-scroll.html @@ -0,0 +1,46 @@ +<!DOCTYPE html> +<script src="../../../resources/js-test.js"></script> +<style> + body { + height: 2000px; + width: 2000px; + } +</style> + +<script> + window.jsTestIsAsync = true; + + description("This test ensures that consecutive mouse wheel ticks scroll\ + to the right offset. The main purpose of this test is to ensure that\ + smooth scrolling on the compositor works as intended (tested via\ + virtual suite virtual/threaded/)."); + + function runTest() { + if (!window.eventSender || !window.internals) { + finishJSTest(); + return; + } + + // Turn on smooth scrolling. + internals.settings.setScrollAnimatorEnabled(true); + + eventSender.mouseMoveTo(20, 20); + // Scroll down 3 ticks. + eventSender.mouseScrollBy(0, -1); + eventSender.mouseScrollBy(0, -1); + eventSender.mouseScrollBy(0, -1); + // Scroll right 3 ticks. + eventSender.mouseScrollBy(-1, 0); + eventSender.mouseScrollBy(-1, 0); + eventSender.mouseScrollBy(-1, 0); + // Undo 1 tick in each direction. + eventSender.mouseScrollBy(0, 1); + eventSender.mouseScrollBy(1, 0); + + // 40px per tick. + shouldBecomeEqual("document.scrollingElement.scrollTop == 80 && " + + "document.scrollingElement.scrollLeft == 80", "true", finishJSTest); + } +</script> + +<body onload="runTest()"></body> diff --git a/third_party/WebKit/Source/core/frame/FrameView.cpp b/third_party/WebKit/Source/core/frame/FrameView.cpp index 2b39cef..de49f4b 100644 --- a/third_party/WebKit/Source/core/frame/FrameView.cpp +++ b/third_party/WebKit/Source/core/frame/FrameView.cpp @@ -264,7 +264,7 @@ void FrameView::dispose() RELEASE_ASSERT(!isInPerformLayout()); if (ScrollAnimatorBase* scrollAnimator = existingScrollAnimator()) - scrollAnimator->cancelAnimations(); + scrollAnimator->cancelAnimation(); cancelProgrammaticScrollAnimation(); detachScrollbars(); diff --git a/third_party/WebKit/Source/core/input/EventHandler.cpp b/third_party/WebKit/Source/core/input/EventHandler.cpp index 515e550..47861ee 100644 --- a/third_party/WebKit/Source/core/input/EventHandler.cpp +++ b/third_party/WebKit/Source/core/input/EventHandler.cpp @@ -2036,14 +2036,14 @@ WebInputEventResult EventHandler::handleGestureShowPress() if (!view) return WebInputEventResult::NotHandled; if (ScrollAnimatorBase* scrollAnimator = view->existingScrollAnimator()) - scrollAnimator->cancelAnimations(); + scrollAnimator->cancelAnimation(); const FrameView::ScrollableAreaSet* areas = view->scrollableAreas(); if (!areas) return WebInputEventResult::NotHandled; for (const ScrollableArea* scrollableArea : *areas) { ScrollAnimatorBase* animator = scrollableArea->existingScrollAnimator(); if (animator) - animator->cancelAnimations(); + animator->cancelAnimation(); } return WebInputEventResult::NotHandled; } diff --git a/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp b/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp index eefb444..bbb2640 100644 --- a/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp +++ b/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp @@ -1128,6 +1128,11 @@ void GraphicsLayer::removeAnimation(int animationId) platformLayer()->removeAnimation(animationId); } +void GraphicsLayer::abortAnimation(int animationId) +{ + platformLayer()->abortAnimation(animationId); +} + WebLayer* GraphicsLayer::platformLayer() const { return m_layer->layer(); diff --git a/third_party/WebKit/Source/platform/graphics/GraphicsLayer.h b/third_party/WebKit/Source/platform/graphics/GraphicsLayer.h index 8f52c48..caa5158 100644 --- a/third_party/WebKit/Source/platform/graphics/GraphicsLayer.h +++ b/third_party/WebKit/Source/platform/graphics/GraphicsLayer.h @@ -203,6 +203,7 @@ public: bool addAnimation(PassOwnPtr<WebCompositorAnimation>); void pauseAnimation(int animationId, double /*timeOffset*/); void removeAnimation(int animationId); + void abortAnimation(int animationId); // Layer contents void setContentsToImage(Image*, RespectImageOrientationEnum = DoNotRespectImageOrientation); diff --git a/third_party/WebKit/Source/platform/mac/ScrollAnimatorMac.h b/third_party/WebKit/Source/platform/mac/ScrollAnimatorMac.h index b5805bc..35c19f4e 100644 --- a/third_party/WebKit/Source/platform/mac/ScrollAnimatorMac.h +++ b/third_party/WebKit/Source/platform/mac/ScrollAnimatorMac.h @@ -93,7 +93,7 @@ private: void handleWheelEventPhase(PlatformWheelEventPhase) override; - void cancelAnimations() override; + void cancelAnimation() override; void setIsActive() override; void contentAreaWillPaint() const override; diff --git a/third_party/WebKit/Source/platform/mac/ScrollAnimatorMac.mm b/third_party/WebKit/Source/platform/mac/ScrollAnimatorMac.mm index c99941a..a731a46 100644 --- a/third_party/WebKit/Source/platform/mac/ScrollAnimatorMac.mm +++ b/third_party/WebKit/Source/platform/mac/ScrollAnimatorMac.mm @@ -1041,7 +1041,7 @@ bool ScrollAnimatorMac::setScrollbarsVisibleForTesting(bool show) return false; } -void ScrollAnimatorMac::cancelAnimations() +void ScrollAnimatorMac::cancelAnimation() { m_haveScrolledSincePageLoad = false; diff --git a/third_party/WebKit/Source/platform/scroll/ProgrammaticScrollAnimator.cpp b/third_party/WebKit/Source/platform/scroll/ProgrammaticScrollAnimator.cpp index 6910c4f..3e29f04 100644 --- a/third_party/WebKit/Source/platform/scroll/ProgrammaticScrollAnimator.cpp +++ b/third_party/WebKit/Source/platform/scroll/ProgrammaticScrollAnimator.cpp @@ -64,6 +64,12 @@ void ProgrammaticScrollAnimator::animateToOffset(FloatPoint offset) m_runState = RunState::WaitingToSendToCompositor; } +void ProgrammaticScrollAnimator::cancelAnimation() +{ + ASSERT(m_runState != RunState::RunningOnCompositorButNeedsUpdate); + ScrollAnimatorCompositorCoordinator::cancelAnimation(); +} + void ProgrammaticScrollAnimator::tickAnimation(double monotonicTime) { if (m_runState != RunState::RunningOnMainThread) @@ -154,6 +160,7 @@ void ProgrammaticScrollAnimator::layerForCompositedScrollingDidChange(WebComposi void ProgrammaticScrollAnimator::notifyCompositorAnimationFinished(int groupId) { + ASSERT(m_runState != RunState::RunningOnCompositorButNeedsUpdate); ScrollAnimatorCompositorCoordinator::compositorAnimationFinished(groupId); } diff --git a/third_party/WebKit/Source/platform/scroll/ProgrammaticScrollAnimator.h b/third_party/WebKit/Source/platform/scroll/ProgrammaticScrollAnimator.h index c700414..fa05677 100644 --- a/third_party/WebKit/Source/platform/scroll/ProgrammaticScrollAnimator.h +++ b/third_party/WebKit/Source/platform/scroll/ProgrammaticScrollAnimator.h @@ -34,6 +34,7 @@ public: // ScrollAnimatorCompositorCoordinator implementation. void resetAnimationState() override; + void cancelAnimation() override; ScrollableArea* scrollableArea() const override { return m_scrollableArea; } void tickAnimation(double monotonicTime) override; void updateCompositorAnimations() override; diff --git a/third_party/WebKit/Source/platform/scroll/ScrollAnimator.cpp b/third_party/WebKit/Source/platform/scroll/ScrollAnimator.cpp index e9610b0..fa45f0f 100644 --- a/third_party/WebKit/Source/platform/scroll/ScrollAnimator.cpp +++ b/third_party/WebKit/Source/platform/scroll/ScrollAnimator.cpp @@ -31,12 +31,13 @@ #include "platform/scroll/ScrollAnimator.h" #include "platform/TraceEvent.h" +#include "platform/graphics/GraphicsLayer.h" #include "platform/scroll/ScrollableArea.h" #include "public/platform/Platform.h" +#include "public/platform/WebCompositorAnimation.h" #include "public/platform/WebCompositorSupport.h" #include "wtf/CurrentTime.h" #include "wtf/PassRefPtr.h" -#include <algorithm> namespace blink { @@ -49,21 +50,22 @@ PassOwnPtrWillBeRawPtr<ScrollAnimatorBase> ScrollAnimatorBase::create(Scrollable ScrollAnimator::ScrollAnimator(ScrollableArea* scrollableArea, WTF::TimeFunction timeFunction) : ScrollAnimatorBase(scrollableArea) + , m_lastTickTime(0.0) , m_timeFunction(timeFunction) { } ScrollAnimator::~ScrollAnimator() { - cancelAnimations(); } FloatPoint ScrollAnimator::desiredTargetPosition() const { - return m_animationCurve ? FloatPoint(m_animationCurve->targetValue()) : currentPosition(); + return m_animationCurve ? m_targetOffset : currentPosition(); } -float ScrollAnimator::computeDeltaToConsume(ScrollbarOrientation orientation, float pixelDelta) const +float ScrollAnimator::computeDeltaToConsume( + ScrollbarOrientation orientation, float pixelDelta) const { FloatPoint pos = desiredTargetPosition(); float currentPos = (orientation == HorizontalScrollbar) ? pos.x() : pos.y(); @@ -71,7 +73,16 @@ float ScrollAnimator::computeDeltaToConsume(ScrollbarOrientation orientation, fl return (currentPos == newPos) ? 0.0f : (newPos - currentPos); } -ScrollResultOneDimensional ScrollAnimator::userScroll(ScrollbarOrientation orientation, ScrollGranularity granularity, float step, float delta) +void ScrollAnimator::resetAnimationState() +{ + ScrollAnimatorCompositorCoordinator::resetAnimationState(); + if (m_animationCurve) + m_animationCurve.clear(); + m_startTime = 0.0; +} + +ScrollResultOneDimensional ScrollAnimator::userScroll( + ScrollbarOrientation orientation, ScrollGranularity granularity, float step, float delta) { if (!m_scrollableArea->scrollAnimatorEnabled()) return ScrollAnimatorBase::userScroll(orientation, granularity, step, delta); @@ -82,14 +93,33 @@ ScrollResultOneDimensional ScrollAnimator::userScroll(ScrollbarOrientation orien return ScrollAnimatorBase::userScroll(orientation, granularity, step, delta); float usedPixelDelta = computeDeltaToConsume(orientation, step * delta); - FloatPoint pixelDelta = (orientation == VerticalScrollbar ? FloatPoint(0, usedPixelDelta) : FloatPoint(usedPixelDelta, 0)); + FloatPoint pixelDelta = (orientation == VerticalScrollbar + ? FloatPoint(0, usedPixelDelta) : FloatPoint(usedPixelDelta, 0)); FloatPoint targetPos = desiredTargetPosition(); targetPos.moveBy(pixelDelta); if (m_animationCurve) { - if (!(targetPos - m_animationCurve->targetValue()).isZero()) - m_animationCurve->updateTarget(m_timeFunction() - m_startTime, targetPos); + if ((targetPos - m_targetOffset).isZero()) { + // Report unused delta only if there is no animation running. See + // comment below regarding scroll latching. + return ScrollResultOneDimensional(/* didScroll */ true, /* unusedScrollDelta */ 0); + } + + m_targetOffset = targetPos; + ASSERT(m_runState == RunState::RunningOnMainThread + || m_runState == RunState::RunningOnCompositor + || m_runState == RunState::RunningOnCompositorButNeedsUpdate); + + if (m_runState == RunState::RunningOnCompositor + || m_runState == RunState::RunningOnCompositorButNeedsUpdate) { + m_runState = RunState::RunningOnCompositorButNeedsUpdate; + return ScrollResultOneDimensional(/* didScroll */ true, /* unusedScrollDelta */ 0); + } + + // Running on the main thread, simply update the target offset instead + // of sending to the compositor. + m_animationCurve->updateTarget(m_timeFunction() - m_startTime, targetPos); return ScrollResultOneDimensional(/* didScroll */ true, /* unusedScrollDelta */ 0); } @@ -100,16 +130,17 @@ ScrollResultOneDimensional ScrollAnimator::userScroll(ScrollbarOrientation orien return ScrollResultOneDimensional(/* didScroll */ false, delta); } - m_animationCurve = adoptPtr(Platform::current()->compositorSupport()->createScrollOffsetAnimationCurve( - targetPos, - WebCompositorAnimationCurve::TimingFunctionTypeEaseInOut, - WebScrollOffsetAnimationCurve::ScrollDurationConstant)); - - m_animationCurve->setInitialValue(currentPosition()); + m_targetOffset = targetPos; m_startTime = m_timeFunction(); scrollableArea()->registerForAnimation(); - animationTimerFired(); + if (!m_scrollableArea->scheduleAnimation()) { + scrollToOffsetWithoutAnimation(targetPos); + resetAnimationState(); + return ScrollResultOneDimensional(/* didScroll */ true, /* unusedScrollDelta */ 0); + } + + m_runState = RunState::WaitingToSendToCompositor; return ScrollResultOneDimensional(/* didScroll */ true, /* unusedScrollDelta */ 0); } @@ -118,34 +149,23 @@ void ScrollAnimator::scrollToOffsetWithoutAnimation(const FloatPoint& offset) m_currentPosX = offset.x(); m_currentPosY = offset.y(); - cancelAnimations(); + resetAnimationState(); notifyPositionChanged(); } -void ScrollAnimator::cancelAnimations() +void ScrollAnimator::tickAnimation(double monotonicTime) { - if (m_animationCurve) - m_animationCurve.clear(); -} + m_lastTickTime = monotonicTime; -void ScrollAnimator::serviceScrollAnimations() -{ - if (hasRunningAnimation()) - animationTimerFired(); -} + if (m_runState != RunState::RunningOnMainThread) + return; -bool ScrollAnimator::hasRunningAnimation() const -{ - return m_animationCurve; -} - -void ScrollAnimator::animationTimerFired() -{ - TRACE_EVENT0("blink", "ScrollAnimator::animationTimerFired"); - double elapsedTime = m_timeFunction() - m_startTime; + TRACE_EVENT0("blink", "ScrollAnimator::tickAnimation"); + double elapsedTime = monotonicTime - m_startTime; bool isFinished = (elapsedTime > m_animationCurve->duration()); - FloatPoint offset = isFinished ? m_animationCurve->targetValue() : m_animationCurve->getValue(elapsedTime); + FloatPoint offset = isFinished ? m_animationCurve->targetValue() + : m_animationCurve->getValue(elapsedTime); offset = FloatPoint(m_scrollableArea->clampScrollPosition(offset)); @@ -153,7 +173,7 @@ void ScrollAnimator::animationTimerFired() m_currentPosY = offset.y(); if (isFinished) - m_animationCurve.clear(); + resetAnimationState(); else scrollableArea()->scheduleAnimation(); @@ -161,6 +181,105 @@ void ScrollAnimator::animationTimerFired() notifyPositionChanged(); } +void ScrollAnimator::updateCompositorAnimations() +{ + if (m_compositorAnimationId && m_runState != RunState::RunningOnCompositor + && m_runState != RunState::RunningOnCompositorButNeedsUpdate) { + // If the current run state is WaitingToSendToCompositor but we have a + // non-zero compositor animation id, there's a currently running + // compositor animation that needs to be removed here before the new + // animation is added below. + ASSERT(m_runState == RunState::WaitingToCancelOnCompositor + || m_runState == RunState::WaitingToSendToCompositor); + + abortAnimation(); + + m_compositorAnimationId = 0; + m_compositorAnimationGroupId = 0; + if (m_runState == RunState::WaitingToCancelOnCompositor) { + resetAnimationState(); + return; + } + } + + if (m_runState == RunState::WaitingToSendToCompositor + || m_runState == RunState::RunningOnCompositorButNeedsUpdate) { + if (m_runState == RunState::RunningOnCompositorButNeedsUpdate) { + // Abort the running animation before a new one with an updated + // target is added. + abortAnimation(); + + m_compositorAnimationId = 0; + m_compositorAnimationGroupId = 0; + + m_animationCurve->updateTarget(m_lastTickTime - m_startTime, + m_targetOffset); + m_runState = RunState::WaitingToSendToCompositor; + } + + if (!m_animationCurve) { + m_animationCurve = adoptPtr(Platform::current()->compositorSupport() + ->createScrollOffsetAnimationCurve( + m_targetOffset, + WebCompositorAnimationCurve::TimingFunctionTypeEaseInOut, + WebScrollOffsetAnimationCurve::ScrollDurationConstant)); + m_animationCurve->setInitialValue(currentPosition()); + } + + bool sentToCompositor = false; + if (GraphicsLayer* layer = m_scrollableArea->layerForScrolling()) { + ASSERT(layer->scrollableArea() == m_scrollableArea); + if (!layer->platformLayer()->shouldScrollOnMainThread()) { + OwnPtr<WebCompositorAnimation> animation = adoptPtr( + Platform::current()->compositorSupport()->createAnimation( + *m_animationCurve, + WebCompositorAnimation::TargetPropertyScrollOffset)); + // Being here means that either there is an animation that needs + // to be sent to the compositor, or an animation that needs to + // be updated (a new scroll event before the previous animation + // is finished). In either case, the start time is when the + // first animation was initiated. This re-targets the animation + // using the current time on main thread. + animation->setStartTime(m_startTime); + + int animationId = animation->id(); + int animationGroupId = animation->group(); + + sentToCompositor = addAnimation(animation.release()); + if (sentToCompositor) { + m_runState = RunState::RunningOnCompositor; + m_compositorAnimationId = animationId; + m_compositorAnimationGroupId = animationGroupId; + } + } + } + + if (!sentToCompositor) { + m_runState = RunState::RunningOnMainThread; + if (!m_scrollableArea->scheduleAnimation()) { + scrollToOffsetWithoutAnimation(m_targetOffset); + resetAnimationState(); + } + } + } +} + +void ScrollAnimator::notifyCompositorAnimationFinished(int groupId) +{ + ScrollAnimatorCompositorCoordinator::compositorAnimationFinished(groupId); +} + +void ScrollAnimator::cancelAnimation() +{ + ScrollAnimatorCompositorCoordinator::cancelAnimation(); +} + +void ScrollAnimator::layerForCompositedScrollingDidChange( + WebCompositorAnimationTimeline* timeline) +{ + reattachCompositorPlayerIfNeeded(timeline); +} + DEFINE_TRACE(ScrollAnimator) { ScrollAnimatorBase::trace(visitor); diff --git a/third_party/WebKit/Source/platform/scroll/ScrollAnimator.h b/third_party/WebKit/Source/platform/scroll/ScrollAnimator.h index 01746e68..5d8f20a 100644 --- a/third_party/WebKit/Source/platform/scroll/ScrollAnimator.h +++ b/third_party/WebKit/Source/platform/scroll/ScrollAnimator.h @@ -34,11 +34,14 @@ #include "platform/Timer.h" #include "platform/geometry/FloatPoint.h" #include "platform/scroll/ScrollAnimatorBase.h" +#include "public/platform/WebCompositorAnimationDelegate.h" +#include "public/platform/WebCompositorAnimationPlayerClient.h" #include "public/platform/WebScrollOffsetAnimationCurve.h" namespace blink { class ScrollAnimatorTest; +class WebCompositorAnimationTimeline; class PLATFORM_EXPORT ScrollAnimator final : public ScrollAnimatorBase { public: @@ -50,20 +53,26 @@ public: ScrollResultOneDimensional userScroll(ScrollbarOrientation, ScrollGranularity, float step, float delta) override; void scrollToOffsetWithoutAnimation(const FloatPoint&) override; - void cancelAnimations() override; - void serviceScrollAnimations() override; - bool hasRunningAnimation() const override; + // ScrollAnimatorCompositorCoordinator implementation. + void tickAnimation(double monotonicTime) override; + void cancelAnimation() override; + void resetAnimationState() override; + void updateCompositorAnimations() override; + void notifyCompositorAnimationFinished(int groupId) override; + void layerForCompositedScrollingDidChange(WebCompositorAnimationTimeline*) override; DECLARE_VIRTUAL_TRACE(); protected: - void animationTimerFired(); - OwnPtr<WebScrollOffsetAnimationCurve> m_animationCurve; + double m_lastTickTime; double m_startTime; WTF::TimeFunction m_timeFunction; + private: FloatPoint desiredTargetPosition() const; + + FloatPoint m_targetOffset; }; } // namespace blink diff --git a/third_party/WebKit/Source/platform/scroll/ScrollAnimatorBase.cpp b/third_party/WebKit/Source/platform/scroll/ScrollAnimatorBase.cpp index ce86e06..75306cc 100644 --- a/third_party/WebKit/Source/platform/scroll/ScrollAnimatorBase.cpp +++ b/third_party/WebKit/Source/platform/scroll/ScrollAnimatorBase.cpp @@ -104,6 +104,7 @@ float ScrollAnimatorBase::clampScrollPosition(ScrollbarOrientation orientation, DEFINE_TRACE(ScrollAnimatorBase) { visitor->trace(m_scrollableArea); + ScrollAnimatorCompositorCoordinator::trace(visitor); } } // namespace blink diff --git a/third_party/WebKit/Source/platform/scroll/ScrollAnimatorBase.h b/third_party/WebKit/Source/platform/scroll/ScrollAnimatorBase.h index 3503b7f..5926f86 100644 --- a/third_party/WebKit/Source/platform/scroll/ScrollAnimatorBase.h +++ b/third_party/WebKit/Source/platform/scroll/ScrollAnimatorBase.h @@ -35,6 +35,7 @@ #include "platform/PlatformWheelEvent.h" #include "platform/geometry/FloatSize.h" #include "platform/heap/Handle.h" +#include "platform/scroll/ScrollAnimatorCompositorCoordinator.h" #include "platform/scroll/ScrollTypes.h" #include "wtf/Forward.h" @@ -43,8 +44,9 @@ namespace blink { class FloatPoint; class ScrollableArea; class Scrollbar; +class WebCompositorAnimationTimeline; -class PLATFORM_EXPORT ScrollAnimatorBase : public NoBaseWillBeGarbageCollectedFinalized<ScrollAnimatorBase> { +class PLATFORM_EXPORT ScrollAnimatorBase : public ScrollAnimatorCompositorCoordinator { public: static PassOwnPtrWillBeRawPtr<ScrollAnimatorBase> create(ScrollableArea*); @@ -61,8 +63,6 @@ public: virtual void scrollToOffsetWithoutAnimation(const FloatPoint&); - ScrollableArea* scrollableArea() const { return m_scrollableArea; } - virtual void setIsActive() { } #if OS(MACOSX) @@ -76,9 +76,14 @@ public: // area. virtual float computeDeltaToConsume(ScrollbarOrientation, float pixelDelta) const; - virtual void cancelAnimations() { } - virtual void serviceScrollAnimations() { } - virtual bool hasRunningAnimation() const { return false; } + + // ScrollAnimatorCompositorCoordinator implementation. + ScrollableArea* scrollableArea() const override { return m_scrollableArea; } + void tickAnimation(double monotonicTime) override { }; + void cancelAnimation() override { } + void updateCompositorAnimations() override { }; + void notifyCompositorAnimationFinished(int groupId) override { }; + void layerForCompositedScrollingDidChange(WebCompositorAnimationTimeline*) override { }; virtual void contentAreaWillPaint() const { } virtual void mouseEnteredContentArea() const { } diff --git a/third_party/WebKit/Source/platform/scroll/ScrollAnimatorCompositorCoordinator.cpp b/third_party/WebKit/Source/platform/scroll/ScrollAnimatorCompositorCoordinator.cpp index 9245749..4f0528f 100644 --- a/third_party/WebKit/Source/platform/scroll/ScrollAnimatorCompositorCoordinator.cpp +++ b/third_party/WebKit/Source/platform/scroll/ScrollAnimatorCompositorCoordinator.cpp @@ -51,6 +51,7 @@ bool ScrollAnimatorCompositorCoordinator::hasAnimationThatRequiresService() cons return false; case RunState::WaitingToSendToCompositor: case RunState::RunningOnMainThread: + case RunState::RunningOnCompositorButNeedsUpdate: case RunState::WaitingToCancelOnCompositor: return true; } @@ -83,6 +84,17 @@ void ScrollAnimatorCompositorCoordinator::removeAnimation() } } +void ScrollAnimatorCompositorCoordinator::abortAnimation() +{ + if (m_compositorPlayer) { + if (m_compositorPlayer->isLayerAttached()) + m_compositorPlayer->abortAnimation(m_compositorAnimationId); + } else { + if (GraphicsLayer* layer = scrollableArea()->layerForScrolling()) + layer->abortAnimation(m_compositorAnimationId); + } +} + void ScrollAnimatorCompositorCoordinator::cancelAnimation() { switch (m_runState) { @@ -100,6 +112,7 @@ void ScrollAnimatorCompositorCoordinator::cancelAnimation() case RunState::RunningOnMainThread: resetAnimationState(); break; + case RunState::RunningOnCompositorButNeedsUpdate: case RunState::RunningOnCompositor: m_runState = RunState::WaitingToCancelOnCompositor; @@ -125,6 +138,7 @@ void ScrollAnimatorCompositorCoordinator::compositorAnimationFinished( case RunState::WaitingToSendToCompositor: break; case RunState::RunningOnCompositor: + case RunState::RunningOnCompositorButNeedsUpdate: case RunState::WaitingToCancelOnCompositor: resetAnimationState(); } diff --git a/third_party/WebKit/Source/platform/scroll/ScrollAnimatorCompositorCoordinator.h b/third_party/WebKit/Source/platform/scroll/ScrollAnimatorCompositorCoordinator.h index f10acb3..440aa7e 100644 --- a/third_party/WebKit/Source/platform/scroll/ScrollAnimatorCompositorCoordinator.h +++ b/third_party/WebKit/Source/platform/scroll/ScrollAnimatorCompositorCoordinator.h @@ -22,9 +22,9 @@ public: virtual ~ScrollAnimatorCompositorCoordinator(); bool hasAnimationThatRequiresService() const; - void cancelAnimation(); virtual void resetAnimationState(); + virtual void cancelAnimation(); virtual ScrollableArea* scrollableArea() const = 0; virtual void tickAnimation(double monotonicTime) = 0; @@ -39,6 +39,7 @@ protected: bool addAnimation(PassOwnPtr<WebCompositorAnimation>); void removeAnimation(); + void abortAnimation(); void compositorAnimationFinished(int groupId); void reattachCompositorPlayerIfNeeded(WebCompositorAnimationTimeline*); @@ -62,6 +63,9 @@ protected: // Running an animation on the compositor. RunningOnCompositor, + // Running an animation on the compositor but needs update. + RunningOnCompositorButNeedsUpdate, + // Running an animation on the main thread. RunningOnMainThread, diff --git a/third_party/WebKit/Source/platform/scroll/ScrollAnimatorTest.cpp b/third_party/WebKit/Source/platform/scroll/ScrollAnimatorTest.cpp index 2a398a0..cbb5be1 100644 --- a/third_party/WebKit/Source/platform/scroll/ScrollAnimatorTest.cpp +++ b/third_party/WebKit/Source/platform/scroll/ScrollAnimatorTest.cpp @@ -72,6 +72,7 @@ public: MOCK_CONST_METHOD0(scrollbarsCanBeActive, bool()); MOCK_CONST_METHOD0(scrollableAreaBoundingBox, IntRect()); MOCK_METHOD0(registerForAnimation, void()); + MOCK_METHOD0(scheduleAnimation, bool()); bool userInputScrollable(ScrollbarOrientation) const override { return true; } bool shouldPlaceVerticalScrollbarOnLeft() const override { return false; } @@ -100,30 +101,32 @@ static void reset(ScrollAnimator& scrollAnimator) scrollAnimator.scrollToOffsetWithoutAnimation(FloatPoint()); } -TEST(ScrollAnimatorTest, Enabled) +TEST(ScrollAnimatorTest, MainThreadEnabled) { OwnPtrWillBeRawPtr<MockScrollableArea> scrollableArea = MockScrollableArea::create(true); OwnPtrWillBeRawPtr<ScrollAnimator> scrollAnimator = adoptPtrWillBeNoop(new ScrollAnimator(scrollableArea.get(), getMockedTime)); EXPECT_CALL(*scrollableArea, minimumScrollPosition()).Times(AtLeast(1)).WillRepeatedly(Return(IntPoint())); EXPECT_CALL(*scrollableArea, maximumScrollPosition()).Times(AtLeast(1)).WillRepeatedly(Return(IntPoint(1000, 1000))); - EXPECT_CALL(*scrollableArea, setScrollOffset(_, _)).Times(12); + EXPECT_CALL(*scrollableArea, setScrollOffset(_, _)).Times(9); EXPECT_CALL(*scrollableArea, registerForAnimation()).Times(3); + EXPECT_CALL(*scrollableArea, scheduleAnimation()).Times(AtLeast(1)).WillRepeatedly(Return(true)); - EXPECT_FALSE(scrollAnimator->hasRunningAnimation()); + EXPECT_FALSE(scrollAnimator->hasAnimationThatRequiresService()); ScrollResultOneDimensional result = scrollAnimator->userScroll(HorizontalScrollbar, ScrollByLine, 100, -1); - EXPECT_FALSE(scrollAnimator->hasRunningAnimation()); + EXPECT_FALSE(scrollAnimator->hasAnimationThatRequiresService()); EXPECT_FALSE(result.didScroll); EXPECT_FLOAT_EQ(-1.0f, result.unusedScrollDelta); result = scrollAnimator->userScroll(HorizontalScrollbar, ScrollByLine, 100, 1); - EXPECT_TRUE(scrollAnimator->hasRunningAnimation()); + EXPECT_TRUE(scrollAnimator->hasAnimationThatRequiresService()); EXPECT_TRUE(result.didScroll); EXPECT_FLOAT_EQ(0.0, result.unusedScrollDelta); gMockedTime += 0.05; - scrollAnimator->serviceScrollAnimations(); + scrollAnimator->updateCompositorAnimations(); + scrollAnimator->tickAnimation(getMockedTime()); EXPECT_NE(100, scrollAnimator->currentPosition().x()); EXPECT_NE(0, scrollAnimator->currentPosition().x()); @@ -131,10 +134,11 @@ TEST(ScrollAnimatorTest, Enabled) reset(*scrollAnimator); scrollAnimator->userScroll(HorizontalScrollbar, ScrollByPage, 100, 1); - EXPECT_TRUE(scrollAnimator->hasRunningAnimation()); + EXPECT_TRUE(scrollAnimator->hasAnimationThatRequiresService()); gMockedTime += 0.05; - scrollAnimator->serviceScrollAnimations(); + scrollAnimator->updateCompositorAnimations(); + scrollAnimator->tickAnimation(getMockedTime()); EXPECT_NE(100, scrollAnimator->currentPosition().x()); EXPECT_NE(0, scrollAnimator->currentPosition().x()); @@ -142,25 +146,27 @@ TEST(ScrollAnimatorTest, Enabled) reset(*scrollAnimator); scrollAnimator->userScroll(HorizontalScrollbar, ScrollByPixel, 4, 25); - EXPECT_TRUE(scrollAnimator->hasRunningAnimation()); + EXPECT_TRUE(scrollAnimator->hasAnimationThatRequiresService()); gMockedTime += 0.05; - scrollAnimator->serviceScrollAnimations(); + scrollAnimator->updateCompositorAnimations(); + scrollAnimator->tickAnimation(getMockedTime()); EXPECT_NE(100, scrollAnimator->currentPosition().x()); EXPECT_NE(0, scrollAnimator->currentPosition().x()); EXPECT_EQ(0, scrollAnimator->currentPosition().y()); gMockedTime += 1.0; - scrollAnimator->serviceScrollAnimations(); + scrollAnimator->updateCompositorAnimations(); + scrollAnimator->tickAnimation(getMockedTime()); - EXPECT_FALSE(scrollAnimator->hasRunningAnimation()); + EXPECT_FALSE(scrollAnimator->hasAnimationThatRequiresService()); EXPECT_EQ(100, scrollAnimator->currentPosition().x()); reset(*scrollAnimator); scrollAnimator->userScroll(HorizontalScrollbar, ScrollByPrecisePixel, 4, 25); - EXPECT_FALSE(scrollAnimator->hasRunningAnimation()); + EXPECT_FALSE(scrollAnimator->hasAnimationThatRequiresService()); EXPECT_EQ(100, scrollAnimator->currentPosition().x()); EXPECT_NE(0, scrollAnimator->currentPosition().x()); diff --git a/third_party/WebKit/Source/platform/scroll/ScrollableArea.cpp b/third_party/WebKit/Source/platform/scroll/ScrollableArea.cpp index fb93af9..365aa95 100644 --- a/third_party/WebKit/Source/platform/scroll/ScrollableArea.cpp +++ b/third_party/WebKit/Source/platform/scroll/ScrollableArea.cpp @@ -453,6 +453,8 @@ void ScrollableArea::layerForScrollingDidChange(WebCompositorAnimationTimeline* { if (ProgrammaticScrollAnimator* programmaticScrollAnimator = existingProgrammaticScrollAnimator()) programmaticScrollAnimator->layerForCompositedScrollingDidChange(timeline); + if (ScrollAnimatorBase* scrollAnimator = existingScrollAnimator()) + scrollAnimator->layerForCompositedScrollingDidChange(timeline); } bool ScrollableArea::scheduleAnimation() @@ -468,8 +470,8 @@ void ScrollableArea::serviceScrollAnimations(double monotonicTime) { bool requiresAnimationService = false; if (ScrollAnimatorBase* scrollAnimator = existingScrollAnimator()) { - scrollAnimator->serviceScrollAnimations(); - if (scrollAnimator->hasRunningAnimation()) + scrollAnimator->tickAnimation(monotonicTime); + if (scrollAnimator->hasAnimationThatRequiresService()) requiresAnimationService = true; } if (ProgrammaticScrollAnimator* programmaticScrollAnimator = existingProgrammaticScrollAnimator()) { @@ -485,18 +487,24 @@ void ScrollableArea::updateCompositorScrollAnimations() { if (ProgrammaticScrollAnimator* programmaticScrollAnimator = existingProgrammaticScrollAnimator()) programmaticScrollAnimator->updateCompositorAnimations(); + + if (ScrollAnimatorBase* scrollAnimator = existingScrollAnimator()) + scrollAnimator->updateCompositorAnimations(); } void ScrollableArea::notifyCompositorAnimationFinished(int groupId) { if (ProgrammaticScrollAnimator* programmaticScrollAnimator = existingProgrammaticScrollAnimator()) programmaticScrollAnimator->notifyCompositorAnimationFinished(groupId); + + if (ScrollAnimatorBase* scrollAnimator = existingScrollAnimator()) + scrollAnimator->notifyCompositorAnimationFinished(groupId); } void ScrollableArea::cancelScrollAnimation() { if (ScrollAnimatorBase* scrollAnimator = existingScrollAnimator()) - scrollAnimator->cancelAnimations(); + scrollAnimator->cancelAnimation(); } void ScrollableArea::cancelProgrammaticScrollAnimation() diff --git a/third_party/WebKit/Source/platform/scroll/ScrollableArea.h b/third_party/WebKit/Source/platform/scroll/ScrollableArea.h index 71e221b..50d99bf 100644 --- a/third_party/WebKit/Source/platform/scroll/ScrollableArea.h +++ b/third_party/WebKit/Source/platform/scroll/ScrollableArea.h @@ -212,7 +212,7 @@ public: // Let subclasses provide a way of asking for and servicing scroll // animations. - bool scheduleAnimation(); + virtual bool scheduleAnimation(); virtual void serviceScrollAnimations(double monotonicTime); virtual void updateCompositorScrollAnimations(); virtual void registerForAnimation() { } diff --git a/third_party/WebKit/public/platform/WebCompositorAnimationPlayer.h b/third_party/WebKit/public/platform/WebCompositorAnimationPlayer.h index 9df4e55..92abb1e 100644 --- a/third_party/WebKit/public/platform/WebCompositorAnimationPlayer.h +++ b/third_party/WebKit/public/platform/WebCompositorAnimationPlayer.h @@ -29,6 +29,7 @@ public: virtual void addAnimation(WebCompositorAnimation*) = 0; virtual void removeAnimation(int animationId) = 0; virtual void pauseAnimation(int animationId, double timeOffset) = 0; + virtual void abortAnimation(int animationId) = 0; }; } // namespace blink diff --git a/third_party/WebKit/public/platform/WebLayer.h b/third_party/WebKit/public/platform/WebLayer.h index a0e21b2..6ef2535 100644 --- a/third_party/WebKit/public/platform/WebLayer.h +++ b/third_party/WebKit/public/platform/WebLayer.h @@ -160,6 +160,11 @@ public: // Pauses all animations with the given id. virtual void pauseAnimation(int animationId, double timeOffset) = 0; + // Aborts all animations with the given id. Different from removeAnimation + // in that aborting an animation stops it from affecting both the pending + // and active tree. + virtual void abortAnimation(int animationId) = 0; + // Returns true if this layer has any active animations - useful for tests. virtual bool hasActiveAnimation() = 0; |