summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorymalik <ymalik@chromium.org>2015-12-22 15:17:10 -0800
committerCommit bot <commit-bot@chromium.org>2015-12-22 23:18:23 +0000
commit5534a2b2972534b523014c803e1e0e0541855cc7 (patch)
tree59ad1c2863849ef5bacf96f4eaf5446f5742ece2
parent5a080f017c68b6230a6acea6cca89414d12db661 (diff)
downloadchromium_src-5534a2b2972534b523014c803e1e0e0541855cc7.zip
chromium_src-5534a2b2972534b523014c803e1e0e0541855cc7.tar.gz
chromium_src-5534a2b2972534b523014c803e1e0e0541855cc7.tar.bz2
Run smooth scroll animations on the compositor when possible
This CL implements "immediate retargeting" shown in the following diagram: https://docs.google.com/drawings/d/1z76m-GMDgLI-clkfroLJ-5yhsHkmriZr_swP0kn5iw4 This CL does the following - Add a new state to ScrollAnimatorCompositorCoordinator to update the target offset on the compositor - Use the ScrollAnimatorCompositorCoordinator to schedule anim - Add plumbing from the animators to the animation controller to abort animations Sample test pages: yashmalik.com/nested_scroll_mousewheel_listener.html yashmalik.com/nested_scroll_mousewheel_listener_15ms_janky.html (tight loop in RAF) BUG=552556 CQ_INCLUDE_TRYBOTS=tryserver.blink:linux_blink_rel Review URL: https://codereview.chromium.org/1534813004 Cr-Commit-Position: refs/heads/master@{#366685}
-rw-r--r--cc/animation/animation_player.cc7
-rw-r--r--cc/animation/animation_player.h1
-rw-r--r--cc/blink/web_compositor_animation_player_impl.cc4
-rw-r--r--cc/blink/web_compositor_animation_player_impl.h1
-rw-r--r--cc/blink/web_layer_impl.cc4
-rw-r--r--cc/blink/web_layer_impl.h1
-rw-r--r--cc/layers/layer.cc6
-rw-r--r--cc/layers/layer.h1
-rw-r--r--third_party/WebKit/LayoutTests/fast/scroll-behavior/smooth-scroll/keyboard-scroll-expected.txt18
-rw-r--r--third_party/WebKit/LayoutTests/fast/scroll-behavior/smooth-scroll/keyboard-scroll.html114
-rw-r--r--third_party/WebKit/LayoutTests/fast/scroll-behavior/smooth-scroll/mousewheel-scroll-expected.txt10
-rw-r--r--third_party/WebKit/LayoutTests/fast/scroll-behavior/smooth-scroll/mousewheel-scroll.html46
-rw-r--r--third_party/WebKit/Source/core/frame/FrameView.cpp2
-rw-r--r--third_party/WebKit/Source/core/input/EventHandler.cpp4
-rw-r--r--third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp5
-rw-r--r--third_party/WebKit/Source/platform/graphics/GraphicsLayer.h1
-rw-r--r--third_party/WebKit/Source/platform/mac/ScrollAnimatorMac.h2
-rw-r--r--third_party/WebKit/Source/platform/mac/ScrollAnimatorMac.mm2
-rw-r--r--third_party/WebKit/Source/platform/scroll/ProgrammaticScrollAnimator.cpp7
-rw-r--r--third_party/WebKit/Source/platform/scroll/ProgrammaticScrollAnimator.h1
-rw-r--r--third_party/WebKit/Source/platform/scroll/ScrollAnimator.cpp191
-rw-r--r--third_party/WebKit/Source/platform/scroll/ScrollAnimator.h19
-rw-r--r--third_party/WebKit/Source/platform/scroll/ScrollAnimatorBase.cpp1
-rw-r--r--third_party/WebKit/Source/platform/scroll/ScrollAnimatorBase.h17
-rw-r--r--third_party/WebKit/Source/platform/scroll/ScrollAnimatorCompositorCoordinator.cpp14
-rw-r--r--third_party/WebKit/Source/platform/scroll/ScrollAnimatorCompositorCoordinator.h6
-rw-r--r--third_party/WebKit/Source/platform/scroll/ScrollAnimatorTest.cpp32
-rw-r--r--third_party/WebKit/Source/platform/scroll/ScrollableArea.cpp14
-rw-r--r--third_party/WebKit/Source/platform/scroll/ScrollableArea.h2
-rw-r--r--third_party/WebKit/public/platform/WebCompositorAnimationPlayer.h1
-rw-r--r--third_party/WebKit/public/platform/WebLayer.h5
31 files changed, 469 insertions, 70 deletions
diff --git a/cc/animation/animation_player.cc b/cc/animation/animation_player.cc
index dee19ea..68a6294 100644
--- a/cc/animation/animation_player.cc
+++ b/cc/animation/animation_player.cc
@@ -153,6 +153,13 @@ void AnimationPlayer::RemoveAnimation(int animation_id) {
}
}
+void AnimationPlayer::AbortAnimation(int animation_id) {
+ DCHECK(element_animations_);
+ element_animations_->layer_animation_controller()->AbortAnimation(
+ animation_id);
+ SetNeedsCommit();
+}
+
void AnimationPlayer::PushPropertiesTo(AnimationPlayer* player_impl) {
if (layer_id_ != player_impl->layer_id()) {
if (player_impl->layer_id())
diff --git a/cc/animation/animation_player.h b/cc/animation/animation_player.h
index d028930..f53c9b6 100644
--- a/cc/animation/animation_player.h
+++ b/cc/animation/animation_player.h
@@ -68,6 +68,7 @@ class CC_EXPORT AnimationPlayer : public base::RefCounted<AnimationPlayer>,
void AddAnimation(scoped_ptr<Animation> animation);
void PauseAnimation(int animation_id, double time_offset);
void RemoveAnimation(int animation_id);
+ void AbortAnimation(int animation_id);
void PushPropertiesTo(AnimationPlayer* player_impl);
diff --git a/cc/blink/web_compositor_animation_player_impl.cc b/cc/blink/web_compositor_animation_player_impl.cc
index b73d8d8..150ec93 100644
--- a/cc/blink/web_compositor_animation_player_impl.cc
+++ b/cc/blink/web_compositor_animation_player_impl.cc
@@ -68,4 +68,8 @@ void WebCompositorAnimationPlayerImpl::pauseAnimation(int animation_id,
animation_player_->PauseAnimation(animation_id, time_offset);
}
+void WebCompositorAnimationPlayerImpl::abortAnimation(int animation_id) {
+ animation_player_->AbortAnimation(animation_id);
+}
+
} // namespace cc_blink
diff --git a/cc/blink/web_compositor_animation_player_impl.h b/cc/blink/web_compositor_animation_player_impl.h
index 0cc6975..429438f 100644
--- a/cc/blink/web_compositor_animation_player_impl.h
+++ b/cc/blink/web_compositor_animation_player_impl.h
@@ -36,6 +36,7 @@ class WebCompositorAnimationPlayerImpl
void addAnimation(blink::WebCompositorAnimation* animation) override;
void removeAnimation(int animation_id) override;
void pauseAnimation(int animation_id, double time_offset) override;
+ void abortAnimation(int animation_id) override;
private:
scoped_refptr<cc::AnimationPlayer> animation_player_;
diff --git a/cc/blink/web_layer_impl.cc b/cc/blink/web_layer_impl.cc
index 2210a9e..88601b5 100644
--- a/cc/blink/web_layer_impl.cc
+++ b/cc/blink/web_layer_impl.cc
@@ -278,6 +278,10 @@ void WebLayerImpl::pauseAnimation(int animation_id, double time_offset) {
layer_->PauseAnimation(animation_id, time_offset);
}
+void WebLayerImpl::abortAnimation(int animation_id) {
+ layer_->AbortAnimation(animation_id);
+}
+
bool WebLayerImpl::hasActiveAnimation() {
return layer_->HasActiveAnimation();
}
diff --git a/cc/blink/web_layer_impl.h b/cc/blink/web_layer_impl.h
index a1b762b..3fd0bcc 100644
--- a/cc/blink/web_layer_impl.h
+++ b/cc/blink/web_layer_impl.h
@@ -113,6 +113,7 @@ class WebLayerImpl : public blink::WebLayer {
void removeAnimation(int animation_id,
blink::WebCompositorAnimation::TargetProperty) override;
void pauseAnimation(int animation_id, double time_offset) override;
+ void abortAnimation(int animation_id) override;
bool hasActiveAnimation() override;
void setForceRenderSurface(bool force) override;
void setScrollPositionDouble(blink::WebDoublePoint position) override;
diff --git a/cc/layers/layer.cc b/cc/layers/layer.cc
index c085f16..c933aa9 100644
--- a/cc/layers/layer.cc
+++ b/cc/layers/layer.cc
@@ -1880,6 +1880,12 @@ void Layer::RemoveAnimation(int animation_id,
SetNeedsCommit();
}
+void Layer::AbortAnimation(int animation_id) {
+ DCHECK(layer_animation_controller_);
+ layer_animation_controller_->AbortAnimation(animation_id);
+ SetNeedsCommit();
+}
+
void Layer::SetLayerAnimationControllerForTest(
scoped_refptr<LayerAnimationController> controller) {
DCHECK(layer_animation_controller_);
diff --git a/cc/layers/layer.h b/cc/layers/layer.h
index 6c9036c..7dfe6d0 100644
--- a/cc/layers/layer.h
+++ b/cc/layers/layer.h
@@ -417,6 +417,7 @@ class CC_EXPORT Layer : public base::RefCounted<Layer>,
void PauseAnimation(int animation_id, double time_offset);
void RemoveAnimation(int animation_id);
void RemoveAnimation(int animation_id, Animation::TargetProperty property);
+ void AbortAnimation(int animation_id);
LayerAnimationController* layer_animation_controller() const {
return layer_animation_controller_.get();
}
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;