Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(226)

Side by Side Diff: third_party/WebKit/Source/platform/scroll/ScrollAnimator.cpp

Issue 1534813004: Run smooth scroll animations on the compositor when possible (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: nit Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (c) 2011, Google Inc. All rights reserved. 2 * Copyright (c) 2011, Google Inc. All rights reserved.
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are 5 * modification, are permitted provided that the following conditions are
6 * met: 6 * met:
7 * 7 *
8 * * Redistributions of source code must retain the above copyright 8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer. 9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above 10 * * Redistributions in binary form must reproduce the above
(...skipping 14 matching lines...) Expand all
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */ 29 */
30 30
31 #include "config.h" 31 #include "config.h"
32 #include "platform/scroll/ScrollAnimator.h" 32 #include "platform/scroll/ScrollAnimator.h"
33 33
34 #include "platform/TraceEvent.h" 34 #include "platform/TraceEvent.h"
35 #include "platform/graphics/GraphicsLayer.h"
35 #include "platform/scroll/ScrollableArea.h" 36 #include "platform/scroll/ScrollableArea.h"
36 #include "public/platform/Platform.h" 37 #include "public/platform/Platform.h"
38 #include "public/platform/WebCompositorAnimation.h"
37 #include "public/platform/WebCompositorSupport.h" 39 #include "public/platform/WebCompositorSupport.h"
38 #include "wtf/CurrentTime.h" 40 #include "wtf/CurrentTime.h"
39 #include "wtf/PassRefPtr.h" 41 #include "wtf/PassRefPtr.h"
40 #include <algorithm>
41 42
42 namespace blink { 43 namespace blink {
43 44
44 PassOwnPtrWillBeRawPtr<ScrollAnimatorBase> ScrollAnimatorBase::create(Scrollable Area* scrollableArea) 45 PassOwnPtrWillBeRawPtr<ScrollAnimatorBase> ScrollAnimatorBase::create(Scrollable Area* scrollableArea)
45 { 46 {
46 if (scrollableArea && scrollableArea->scrollAnimatorEnabled()) 47 if (scrollableArea && scrollableArea->scrollAnimatorEnabled())
47 return adoptPtrWillBeNoop(new ScrollAnimator(scrollableArea)); 48 return adoptPtrWillBeNoop(new ScrollAnimator(scrollableArea));
48 return adoptPtrWillBeNoop(new ScrollAnimatorBase(scrollableArea)); 49 return adoptPtrWillBeNoop(new ScrollAnimatorBase(scrollableArea));
49 } 50 }
50 51
51 ScrollAnimator::ScrollAnimator(ScrollableArea* scrollableArea, WTF::TimeFunction timeFunction) 52 ScrollAnimator::ScrollAnimator(ScrollableArea* scrollableArea, WTF::TimeFunction timeFunction)
52 : ScrollAnimatorBase(scrollableArea) 53 : ScrollAnimatorBase(scrollableArea)
54 , m_lastTickTime(0.0)
53 , m_timeFunction(timeFunction) 55 , m_timeFunction(timeFunction)
54 { 56 {
55 } 57 }
56 58
57 ScrollAnimator::~ScrollAnimator() 59 ScrollAnimator::~ScrollAnimator()
58 { 60 {
59 cancelAnimations();
60 } 61 }
61 62
62 FloatPoint ScrollAnimator::desiredTargetPosition() const 63 FloatPoint ScrollAnimator::desiredTargetPosition() const
63 { 64 {
64 return m_animationCurve ? FloatPoint(m_animationCurve->targetValue()) : curr entPosition(); 65 return m_animationCurve ? m_targetOffset : currentPosition();
65 } 66 }
66 67
67 float ScrollAnimator::computeDeltaToConsume(ScrollbarOrientation orientation, fl oat pixelDelta) const 68 float ScrollAnimator::computeDeltaToConsume(
69 ScrollbarOrientation orientation, float pixelDelta) const
68 { 70 {
69 FloatPoint pos = desiredTargetPosition(); 71 FloatPoint pos = desiredTargetPosition();
70 float currentPos = (orientation == HorizontalScrollbar) ? pos.x() : pos.y(); 72 float currentPos = (orientation == HorizontalScrollbar) ? pos.x() : pos.y();
71 float newPos = clampScrollPosition(orientation, currentPos + pixelDelta); 73 float newPos = clampScrollPosition(orientation, currentPos + pixelDelta);
72 return (currentPos == newPos) ? 0.0f : (newPos - currentPos); 74 return (currentPos == newPos) ? 0.0f : (newPos - currentPos);
73 } 75 }
74 76
75 ScrollResultOneDimensional ScrollAnimator::userScroll(ScrollbarOrientation orien tation, ScrollGranularity granularity, float step, float delta) 77 void ScrollAnimator::resetAnimationState()
78 {
79 ScrollAnimatorCompositorCoordinator::resetAnimationState();
80 if (m_animationCurve)
81 m_animationCurve.clear();
82 m_startTime = 0.0;
83 }
84
85 ScrollResultOneDimensional ScrollAnimator::userScroll(
86 ScrollbarOrientation orientation, ScrollGranularity granularity, float step, float delta)
76 { 87 {
77 if (!m_scrollableArea->scrollAnimatorEnabled()) 88 if (!m_scrollableArea->scrollAnimatorEnabled())
78 return ScrollAnimatorBase::userScroll(orientation, granularity, step, de lta); 89 return ScrollAnimatorBase::userScroll(orientation, granularity, step, de lta);
79 90
80 TRACE_EVENT0("blink", "ScrollAnimator::scroll"); 91 TRACE_EVENT0("blink", "ScrollAnimator::scroll");
81 92
82 if (granularity == ScrollByPrecisePixel) 93 if (granularity == ScrollByPrecisePixel)
83 return ScrollAnimatorBase::userScroll(orientation, granularity, step, de lta); 94 return ScrollAnimatorBase::userScroll(orientation, granularity, step, de lta);
84 95
85 float usedPixelDelta = computeDeltaToConsume(orientation, step * delta); 96 float usedPixelDelta = computeDeltaToConsume(orientation, step * delta);
86 FloatPoint pixelDelta = (orientation == VerticalScrollbar ? FloatPoint(0, us edPixelDelta) : FloatPoint(usedPixelDelta, 0)); 97 FloatPoint pixelDelta = (orientation == VerticalScrollbar
98 ? FloatPoint(0, usedPixelDelta) : FloatPoint(usedPixelDelta, 0));
87 99
88 FloatPoint targetPos = desiredTargetPosition(); 100 FloatPoint targetPos = desiredTargetPosition();
89 targetPos.moveBy(pixelDelta); 101 targetPos.moveBy(pixelDelta);
90 102
91 if (m_animationCurve) { 103 if (m_animationCurve) {
92 if (!(targetPos - m_animationCurve->targetValue()).isZero()) 104 if ((targetPos - m_targetOffset).isZero()) {
93 m_animationCurve->updateTarget(m_timeFunction() - m_startTime, targe tPos); 105 // Report unused delta only if there is no animation running. See
106 // comment below regarding scroll latching.
107 return ScrollResultOneDimensional(/* didScroll */ true, /* unusedScr ollDelta */ 0);
108 }
109
110 m_targetOffset = targetPos;
111 ASSERT(m_runState == RunState::RunningOnMainThread
112 || m_runState == RunState::RunningOnCompositor
113 || m_runState == RunState::RunningOnCompositorButNeedsUpdate);
114
115 if (m_runState == RunState::RunningOnCompositor
116 || m_runState == RunState::RunningOnCompositorButNeedsUpdate) {
117 m_runState = RunState::RunningOnCompositorButNeedsUpdate;
118 return ScrollResultOneDimensional(/* didScroll */ true, /* unusedScr ollDelta */ 0);
119 }
120
121 // Running on the main thread, simply update the target offset instead
122 // of sending to the compositor.
123 m_animationCurve->updateTarget(m_timeFunction() - m_startTime, targetPos );
94 return ScrollResultOneDimensional(/* didScroll */ true, /* unusedScrollD elta */ 0); 124 return ScrollResultOneDimensional(/* didScroll */ true, /* unusedScrollD elta */ 0);
95 } 125 }
96 126
97 if ((targetPos - currentPosition()).isZero()) { 127 if ((targetPos - currentPosition()).isZero()) {
98 // Report unused delta only if there is no animation and we are not 128 // Report unused delta only if there is no animation and we are not
99 // starting one. This ensures we latch for the duration of the 129 // starting one. This ensures we latch for the duration of the
100 // animation rather than animating multiple scrollers at the same time. 130 // animation rather than animating multiple scrollers at the same time.
101 return ScrollResultOneDimensional(/* didScroll */ false, delta); 131 return ScrollResultOneDimensional(/* didScroll */ false, delta);
102 } 132 }
103 133
104 m_animationCurve = adoptPtr(Platform::current()->compositorSupport()->create ScrollOffsetAnimationCurve( 134 m_targetOffset = targetPos;
105 targetPos,
106 WebCompositorAnimationCurve::TimingFunctionTypeEaseInOut,
107 WebScrollOffsetAnimationCurve::ScrollDurationConstant));
108
109 m_animationCurve->setInitialValue(currentPosition());
110 m_startTime = m_timeFunction(); 135 m_startTime = m_timeFunction();
111 136
112 scrollableArea()->registerForAnimation(); 137 scrollableArea()->registerForAnimation();
113 animationTimerFired(); 138 if (!m_scrollableArea->scheduleAnimation()) {
139 scrollToOffsetWithoutAnimation(targetPos);
140 resetAnimationState();
141 return ScrollResultOneDimensional(/* didScroll */ true, /* unusedScrollD elta */ 0);
142 }
143
144 m_runState = RunState::WaitingToSendToCompositor;
114 return ScrollResultOneDimensional(/* didScroll */ true, /* unusedScrollDelta */ 0); 145 return ScrollResultOneDimensional(/* didScroll */ true, /* unusedScrollDelta */ 0);
115 } 146 }
116 147
117 void ScrollAnimator::scrollToOffsetWithoutAnimation(const FloatPoint& offset) 148 void ScrollAnimator::scrollToOffsetWithoutAnimation(const FloatPoint& offset)
118 { 149 {
119 m_currentPosX = offset.x(); 150 m_currentPosX = offset.x();
120 m_currentPosY = offset.y(); 151 m_currentPosY = offset.y();
121 152
122 cancelAnimations(); 153 resetAnimationState();
123 notifyPositionChanged(); 154 notifyPositionChanged();
124 } 155 }
125 156
126 void ScrollAnimator::cancelAnimations() 157 void ScrollAnimator::tickAnimation(double monotonicTime)
127 { 158 {
128 if (m_animationCurve) 159 m_lastTickTime = monotonicTime;
129 m_animationCurve.clear();
130 }
131 160
132 void ScrollAnimator::serviceScrollAnimations() 161 if (m_runState != RunState::RunningOnMainThread)
133 { 162 return;
134 if (hasRunningAnimation())
135 animationTimerFired();
136 }
137 163
138 bool ScrollAnimator::hasRunningAnimation() const 164 TRACE_EVENT0("blink", "ScrollAnimator::tickAnimation");
139 { 165 double elapsedTime = monotonicTime - m_startTime;
140 return m_animationCurve;
141 }
142
143 void ScrollAnimator::animationTimerFired()
144 {
145 TRACE_EVENT0("blink", "ScrollAnimator::animationTimerFired");
146 double elapsedTime = m_timeFunction() - m_startTime;
147 166
148 bool isFinished = (elapsedTime > m_animationCurve->duration()); 167 bool isFinished = (elapsedTime > m_animationCurve->duration());
149 FloatPoint offset = isFinished ? m_animationCurve->targetValue() : m_animati onCurve->getValue(elapsedTime); 168 FloatPoint offset = isFinished ? m_animationCurve->targetValue()
169 : m_animationCurve->getValue(elapsedTime);
150 170
151 offset = FloatPoint(m_scrollableArea->clampScrollPosition(offset)); 171 offset = FloatPoint(m_scrollableArea->clampScrollPosition(offset));
152 172
153 m_currentPosX = offset.x(); 173 m_currentPosX = offset.x();
154 m_currentPosY = offset.y(); 174 m_currentPosY = offset.y();
155 175
156 if (isFinished) 176 if (isFinished)
157 m_animationCurve.clear(); 177 resetAnimationState();
158 else 178 else
159 scrollableArea()->scheduleAnimation(); 179 scrollableArea()->scheduleAnimation();
160 180
161 TRACE_EVENT0("blink", "ScrollAnimator::notifyPositionChanged"); 181 TRACE_EVENT0("blink", "ScrollAnimator::notifyPositionChanged");
162 notifyPositionChanged(); 182 notifyPositionChanged();
163 } 183 }
164 184
185 void ScrollAnimator::updateCompositorAnimations()
186 {
187 if (m_compositorAnimationId && m_runState != RunState::RunningOnCompositor
188 && m_runState != RunState::RunningOnCompositorButNeedsUpdate) {
189 // If the current run state is WaitingToSendToCompositor but we have a
190 // non-zero compositor animation id, there's a currently running
191 // compositor animation that needs to be removed here before the new
192 // animation is added below.
193 ASSERT(m_runState == RunState::WaitingToCancelOnCompositor
194 || m_runState == RunState::WaitingToSendToCompositor);
195
196 abortAnimation();
197
198 m_compositorAnimationId = 0;
199 m_compositorAnimationGroupId = 0;
200 if (m_runState == RunState::WaitingToCancelOnCompositor) {
201 resetAnimationState();
202 return;
203 }
204 }
205
206 if (m_runState == RunState::WaitingToSendToCompositor
207 || m_runState == RunState::RunningOnCompositorButNeedsUpdate) {
208 if (m_runState == RunState::RunningOnCompositorButNeedsUpdate) {
209 // Abort the running animation before a new one with an updated
210 // target is added.
211 abortAnimation();
212
213 m_compositorAnimationId = 0;
214 m_compositorAnimationGroupId = 0;
215
216 m_animationCurve->updateTarget(m_lastTickTime - m_startTime,
217 m_targetOffset);
218 m_runState = RunState::WaitingToSendToCompositor;
219 }
220
221 if (!m_animationCurve) {
222 m_animationCurve = adoptPtr(Platform::current()->compositorSupport()
223 ->createScrollOffsetAnimationCurve(
224 m_targetOffset,
225 WebCompositorAnimationCurve::TimingFunctionTypeEaseInOut,
226 WebScrollOffsetAnimationCurve::ScrollDurationConstant));
227 m_animationCurve->setInitialValue(currentPosition());
228 }
229
230 bool sentToCompositor = false;
231 if (GraphicsLayer* layer = m_scrollableArea->layerForScrolling()) {
232 ASSERT(layer->scrollableArea() == m_scrollableArea);
233 if (!layer->platformLayer()->shouldScrollOnMainThread()) {
234 OwnPtr<WebCompositorAnimation> animation = adoptPtr(
235 Platform::current()->compositorSupport()->createAnimation(
236 *m_animationCurve,
237 WebCompositorAnimation::TargetPropertyScrollOffset));
238 // Being here means that either there is an animation that needs
239 // to be sent to the compositor, or an animation that needs to
240 // be updated (a new scroll event before the previous animation
241 // is finished). In either case, the start time is when the
242 // first animation was initiated. This re-targets the animation
243 // using the current time on main thread.
244 animation->setStartTime(m_startTime);
245
246 int animationId = animation->id();
247 int animationGroupId = animation->group();
248
249 sentToCompositor = addAnimation(animation.release());
250 if (sentToCompositor) {
251 m_runState = RunState::RunningOnCompositor;
252 m_compositorAnimationId = animationId;
253 m_compositorAnimationGroupId = animationGroupId;
254 }
255 }
256 }
257
258 if (!sentToCompositor) {
259 m_runState = RunState::RunningOnMainThread;
260 if (!m_scrollableArea->scheduleAnimation()) {
261 scrollToOffsetWithoutAnimation(m_targetOffset);
262 resetAnimationState();
263 }
264 }
265 }
266 }
267
268 void ScrollAnimator::notifyCompositorAnimationFinished(int groupId)
269 {
270 ScrollAnimatorCompositorCoordinator::compositorAnimationFinished(groupId);
271 }
272
273 void ScrollAnimator::cancelAnimation()
274 {
275 ScrollAnimatorCompositorCoordinator::cancelAnimation();
276 }
277
278 void ScrollAnimator::layerForCompositedScrollingDidChange(
279 WebCompositorAnimationTimeline* timeline)
280 {
281 reattachCompositorPlayerIfNeeded(timeline);
282 }
283
165 DEFINE_TRACE(ScrollAnimator) 284 DEFINE_TRACE(ScrollAnimator)
166 { 285 {
167 ScrollAnimatorBase::trace(visitor); 286 ScrollAnimatorBase::trace(visitor);
168 } 287 }
169 288
170 } // namespace blink 289 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698