OLD | NEW |
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 Loading... |
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 |
OLD | NEW |