OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (c) 2011, Google Inc. All rights reserved. | |
3 * | |
4 * Redistribution and use in source and binary forms, with or without | |
5 * modification, are permitted provided that the following conditions are | |
6 * met: | |
7 * | |
8 * * Redistributions of source code must retain the above copyright | |
9 * notice, this list of conditions and the following disclaimer. | |
10 * * Redistributions in binary form must reproduce the above | |
11 * copyright notice, this list of conditions and the following disclaimer | |
12 * in the documentation and/or other materials provided with the | |
13 * distribution. | |
14 * * Neither the name of Google Inc. nor the names of its | |
15 * contributors may be used to endorse or promote products derived from | |
16 * this software without specific prior written permission. | |
17 * | |
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
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. | |
29 */ | |
30 | |
31 #include "config.h" | |
32 | |
33 #include "core/platform/ScrollAnimatorNone.h" | |
34 | |
35 #include <algorithm> | |
36 #include "core/platform/ScrollableArea.h" | |
37 #include "wtf/CurrentTime.h" | |
38 #include "wtf/PassOwnPtr.h" | |
39 | |
40 #include "platform/TraceEvent.h" | |
41 | |
42 using namespace std; | |
43 | |
44 namespace WebCore { | |
45 | |
46 const double kFrameRate = 60; | |
47 const double kTickTime = 1 / kFrameRate; | |
48 const double kMinimumTimerInterval = .001; | |
49 | |
50 PassOwnPtr<ScrollAnimator> ScrollAnimator::create(ScrollableArea* scrollableArea
) | |
51 { | |
52 if (scrollableArea && scrollableArea->scrollAnimatorEnabled()) | |
53 return adoptPtr(new ScrollAnimatorNone(scrollableArea)); | |
54 return adoptPtr(new ScrollAnimator(scrollableArea)); | |
55 } | |
56 | |
57 ScrollAnimatorNone::Parameters::Parameters() | |
58 : m_isEnabled(false) | |
59 { | |
60 } | |
61 | |
62 ScrollAnimatorNone::Parameters::Parameters(bool isEnabled, double animationTime,
double repeatMinimumSustainTime, Curve attackCurve, double attackTime, Curve re
leaseCurve, double releaseTime, Curve coastTimeCurve, double maximumCoastTime) | |
63 : m_isEnabled(isEnabled) | |
64 , m_animationTime(animationTime) | |
65 , m_repeatMinimumSustainTime(repeatMinimumSustainTime) | |
66 , m_attackCurve(attackCurve) | |
67 , m_attackTime(attackTime) | |
68 , m_releaseCurve(releaseCurve) | |
69 , m_releaseTime(releaseTime) | |
70 , m_coastTimeCurve(coastTimeCurve) | |
71 , m_maximumCoastTime(maximumCoastTime) | |
72 { | |
73 } | |
74 | |
75 double ScrollAnimatorNone::PerAxisData::curveAt(Curve curve, double t) | |
76 { | |
77 switch (curve) { | |
78 case Linear: | |
79 return t; | |
80 case Quadratic: | |
81 return t * t; | |
82 case Cubic: | |
83 return t * t * t; | |
84 case Quartic: | |
85 return t * t * t * t; | |
86 case Bounce: | |
87 // Time base is chosen to keep the bounce points simpler: | |
88 // 1 (half bounce coming in) + 1 + .5 + .25 | |
89 const double kTimeBase = 2.75; | |
90 const double kTimeBaseSquared = kTimeBase * kTimeBase; | |
91 if (t < 1 / kTimeBase) | |
92 return kTimeBaseSquared * t * t; | |
93 if (t < 2 / kTimeBase) { | |
94 // Invert a [-.5,.5] quadratic parabola, center it in [1,2]. | |
95 double t1 = t - 1.5 / kTimeBase; | |
96 const double kParabolaAtEdge = 1 - .5 * .5; | |
97 return kTimeBaseSquared * t1 * t1 + kParabolaAtEdge; | |
98 } | |
99 if (t < 2.5 / kTimeBase) { | |
100 // Invert a [-.25,.25] quadratic parabola, center it in [2,2.5]. | |
101 double t2 = t - 2.25 / kTimeBase; | |
102 const double kParabolaAtEdge = 1 - .25 * .25; | |
103 return kTimeBaseSquared * t2 * t2 + kParabolaAtEdge; | |
104 } | |
105 // Invert a [-.125,.125] quadratic parabola, center it in [2.5,2.75]
. | |
106 const double kParabolaAtEdge = 1 - .125 * .125; | |
107 t -= 2.625 / kTimeBase; | |
108 return kTimeBaseSquared * t * t + kParabolaAtEdge; | |
109 } | |
110 ASSERT_NOT_REACHED(); | |
111 return 0; | |
112 } | |
113 | |
114 double ScrollAnimatorNone::PerAxisData::attackCurve(Curve curve, double deltaTim
e, double curveT, double startPosition, double attackPosition) | |
115 { | |
116 double t = deltaTime / curveT; | |
117 double positionFactor = curveAt(curve, t); | |
118 return startPosition + positionFactor * (attackPosition - startPosition); | |
119 } | |
120 | |
121 double ScrollAnimatorNone::PerAxisData::releaseCurve(Curve curve, double deltaTi
me, double curveT, double releasePosition, double desiredPosition) | |
122 { | |
123 double t = deltaTime / curveT; | |
124 double positionFactor = 1 - curveAt(curve, 1 - t); | |
125 return releasePosition + (positionFactor * (desiredPosition - releasePositio
n)); | |
126 } | |
127 | |
128 double ScrollAnimatorNone::PerAxisData::coastCurve(Curve curve, double factor) | |
129 { | |
130 return 1 - curveAt(curve, 1 - factor); | |
131 } | |
132 | |
133 double ScrollAnimatorNone::PerAxisData::curveIntegralAt(Curve curve, double t) | |
134 { | |
135 switch (curve) { | |
136 case Linear: | |
137 return t * t / 2; | |
138 case Quadratic: | |
139 return t * t * t / 3; | |
140 case Cubic: | |
141 return t * t * t * t / 4; | |
142 case Quartic: | |
143 return t * t * t * t * t / 5; | |
144 case Bounce: | |
145 const double kTimeBase = 2.75; | |
146 const double kTimeBaseSquared = kTimeBase * kTimeBase; | |
147 const double kTimeBaseSquaredOverThree = kTimeBaseSquared / 3; | |
148 double area; | |
149 double t1 = min(t, 1 / kTimeBase); | |
150 area = kTimeBaseSquaredOverThree * t1 * t1 * t1; | |
151 if (t < 1 / kTimeBase) | |
152 return area; | |
153 | |
154 t1 = min(t - 1 / kTimeBase, 1 / kTimeBase); | |
155 // The integral of kTimeBaseSquared * (t1 - .5 / kTimeBase) * (t1 - .5 /
kTimeBase) + kParabolaAtEdge | |
156 const double kSecondInnerOffset = kTimeBaseSquared * .5 / kTimeBase; | |
157 double bounceArea = t1 * (t1 * (kTimeBaseSquaredOverThree * t1 - kSecond
InnerOffset) + 1); | |
158 area += bounceArea; | |
159 if (t < 2 / kTimeBase) | |
160 return area; | |
161 | |
162 t1 = min(t - 2 / kTimeBase, 0.5 / kTimeBase); | |
163 // The integral of kTimeBaseSquared * (t1 - .25 / kTimeBase) * (t1 - .25
/ kTimeBase) + kParabolaAtEdge | |
164 const double kThirdInnerOffset = kTimeBaseSquared * .25 / kTimeBase; | |
165 bounceArea = t1 * (t1 * (kTimeBaseSquaredOverThree * t1 - kThirdInnerOf
fset) + 1); | |
166 area += bounceArea; | |
167 if (t < 2.5 / kTimeBase) | |
168 return area; | |
169 | |
170 t1 = t - 2.5 / kTimeBase; | |
171 // The integral of kTimeBaseSquared * (t1 - .125 / kTimeBase) * (t1 - .1
25 / kTimeBase) + kParabolaAtEdge | |
172 const double kFourthInnerOffset = kTimeBaseSquared * .125 / kTimeBase; | |
173 bounceArea = t1 * (t1 * (kTimeBaseSquaredOverThree * t1 - kFourthInnerOf
fset) + 1); | |
174 area += bounceArea; | |
175 return area; | |
176 } | |
177 ASSERT_NOT_REACHED(); | |
178 return 0; | |
179 } | |
180 | |
181 double ScrollAnimatorNone::PerAxisData::attackArea(Curve curve, double startT, d
ouble endT) | |
182 { | |
183 double startValue = curveIntegralAt(curve, startT); | |
184 double endValue = curveIntegralAt(curve, endT); | |
185 return endValue - startValue; | |
186 } | |
187 | |
188 double ScrollAnimatorNone::PerAxisData::releaseArea(Curve curve, double startT,
double endT) | |
189 { | |
190 double startValue = curveIntegralAt(curve, 1 - endT); | |
191 double endValue = curveIntegralAt(curve, 1 - startT); | |
192 return endValue - startValue; | |
193 } | |
194 | |
195 ScrollAnimatorNone::PerAxisData::PerAxisData(ScrollAnimatorNone* parent, float*
currentPosition, int visibleLength) | |
196 : m_currentPosition(currentPosition) | |
197 , m_visibleLength(visibleLength) | |
198 { | |
199 reset(); | |
200 } | |
201 | |
202 void ScrollAnimatorNone::PerAxisData::reset() | |
203 { | |
204 m_currentVelocity = 0; | |
205 | |
206 m_desiredPosition = 0; | |
207 m_desiredVelocity = 0; | |
208 | |
209 m_startPosition = 0; | |
210 m_startTime = 0; | |
211 m_startVelocity = 0; | |
212 | |
213 m_animationTime = 0; | |
214 m_lastAnimationTime = 0; | |
215 | |
216 m_attackPosition = 0; | |
217 m_attackTime = 0; | |
218 m_attackCurve = Quadratic; | |
219 | |
220 m_releasePosition = 0; | |
221 m_releaseTime = 0; | |
222 m_releaseCurve = Quadratic; | |
223 } | |
224 | |
225 | |
226 bool ScrollAnimatorNone::PerAxisData::updateDataFromParameters(float step, float
multiplier, float scrollableSize, double currentTime, Parameters* parameters) | |
227 { | |
228 float delta = step * multiplier; | |
229 if (!m_startTime || !delta || (delta < 0) != (m_desiredPosition - *m_current
Position < 0)) { | |
230 m_desiredPosition = *m_currentPosition; | |
231 m_startTime = 0; | |
232 } | |
233 float newPosition = m_desiredPosition + delta; | |
234 | |
235 if (newPosition < 0 || newPosition > scrollableSize) | |
236 newPosition = max(min(newPosition, scrollableSize), 0.0f); | |
237 | |
238 if (newPosition == m_desiredPosition) | |
239 return false; | |
240 | |
241 m_desiredPosition = newPosition; | |
242 | |
243 if (!m_startTime) { | |
244 m_attackTime = parameters->m_attackTime; | |
245 m_attackCurve = parameters->m_attackCurve; | |
246 } | |
247 m_animationTime = parameters->m_animationTime; | |
248 m_releaseTime = parameters->m_releaseTime; | |
249 m_releaseCurve = parameters->m_releaseCurve; | |
250 | |
251 // Prioritize our way out of over constraint. | |
252 if (m_attackTime + m_releaseTime > m_animationTime) { | |
253 if (m_releaseTime > m_animationTime) | |
254 m_releaseTime = m_animationTime; | |
255 m_attackTime = m_animationTime - m_releaseTime; | |
256 } | |
257 | |
258 if (!m_startTime) { | |
259 // FIXME: This should be the time from the event that got us here. | |
260 m_startTime = currentTime - kTickTime / 2; | |
261 m_startPosition = *m_currentPosition; | |
262 m_lastAnimationTime = m_startTime; | |
263 } | |
264 m_startVelocity = m_currentVelocity; | |
265 | |
266 double remainingDelta = m_desiredPosition - *m_currentPosition; | |
267 | |
268 double attackAreaLeft = 0; | |
269 | |
270 double deltaTime = m_lastAnimationTime - m_startTime; | |
271 double attackTimeLeft = max(0., m_attackTime - deltaTime); | |
272 double timeLeft = m_animationTime - deltaTime; | |
273 double minTimeLeft = m_releaseTime + min(parameters->m_repeatMinimumSustainT
ime, m_animationTime - m_releaseTime - attackTimeLeft); | |
274 if (timeLeft < minTimeLeft) { | |
275 m_animationTime = deltaTime + minTimeLeft; | |
276 timeLeft = minTimeLeft; | |
277 } | |
278 | |
279 if (parameters->m_maximumCoastTime > (parameters->m_repeatMinimumSustainTime
+ parameters->m_releaseTime)) { | |
280 double targetMaxCoastVelocity = m_visibleLength * .25 * kFrameRate; | |
281 // This needs to be as minimal as possible while not being intrusive to
page up/down. | |
282 double minCoastDelta = m_visibleLength; | |
283 | |
284 if (fabs(remainingDelta) > minCoastDelta) { | |
285 double maxCoastDelta = parameters->m_maximumCoastTime * targetMaxCoa
stVelocity; | |
286 double coastFactor = min(1., (fabs(remainingDelta) - minCoastDelta)
/ (maxCoastDelta - minCoastDelta)); | |
287 | |
288 // We could play with the curve here - linear seems a little soft. I
nitial testing makes me want to feed into the sustain time more aggressively. | |
289 double coastMinTimeLeft = min(parameters->m_maximumCoastTime, minTim
eLeft + coastCurve(parameters->m_coastTimeCurve, coastFactor) * (parameters->m_m
aximumCoastTime - minTimeLeft)); | |
290 | |
291 double additionalTime = max(0., coastMinTimeLeft - minTimeLeft); | |
292 if (additionalTime) { | |
293 double additionalReleaseTime = min(additionalTime, parameters->m
_releaseTime / (parameters->m_releaseTime + parameters->m_repeatMinimumSustainTi
me) * additionalTime); | |
294 m_releaseTime = parameters->m_releaseTime + additionalReleaseTim
e; | |
295 m_animationTime = deltaTime + coastMinTimeLeft; | |
296 timeLeft = coastMinTimeLeft; | |
297 } | |
298 } | |
299 } | |
300 | |
301 double releaseTimeLeft = min(timeLeft, m_releaseTime); | |
302 double sustainTimeLeft = max(0., timeLeft - releaseTimeLeft - attackTimeLeft
); | |
303 | |
304 if (attackTimeLeft) { | |
305 double attackSpot = deltaTime / m_attackTime; | |
306 attackAreaLeft = attackArea(m_attackCurve, attackSpot, 1) * m_attackTime
; | |
307 } | |
308 | |
309 double releaseSpot = (m_releaseTime - releaseTimeLeft) / m_releaseTime; | |
310 double releaseAreaLeft = releaseArea(m_releaseCurve, releaseSpot, 1) * m_re
leaseTime; | |
311 | |
312 m_desiredVelocity = remainingDelta / (attackAreaLeft + sustainTimeLeft + rel
easeAreaLeft); | |
313 m_releasePosition = m_desiredPosition - m_desiredVelocity * releaseAreaLeft; | |
314 if (attackAreaLeft) | |
315 m_attackPosition = m_startPosition + m_desiredVelocity * attackAreaLeft; | |
316 else | |
317 m_attackPosition = m_releasePosition - (m_animationTime - m_releaseTime
- m_attackTime) * m_desiredVelocity; | |
318 | |
319 if (sustainTimeLeft) { | |
320 double roundOff = m_releasePosition - ((attackAreaLeft ? m_attackPositio
n : *m_currentPosition) + m_desiredVelocity * sustainTimeLeft); | |
321 m_desiredVelocity += roundOff / sustainTimeLeft; | |
322 } | |
323 | |
324 return true; | |
325 } | |
326 | |
327 // FIXME: Add in jank detection trace events into this function. | |
328 bool ScrollAnimatorNone::PerAxisData::animateScroll(double currentTime) | |
329 { | |
330 double lastScrollInterval = currentTime - m_lastAnimationTime; | |
331 if (lastScrollInterval < kMinimumTimerInterval) | |
332 return true; | |
333 | |
334 m_lastAnimationTime = currentTime; | |
335 | |
336 double deltaTime = currentTime - m_startTime; | |
337 double newPosition = *m_currentPosition; | |
338 | |
339 if (deltaTime > m_animationTime) { | |
340 *m_currentPosition = m_desiredPosition; | |
341 reset(); | |
342 return false; | |
343 } | |
344 if (deltaTime < m_attackTime) | |
345 newPosition = attackCurve(m_attackCurve, deltaTime, m_attackTime, m_star
tPosition, m_attackPosition); | |
346 else if (deltaTime < (m_animationTime - m_releaseTime)) | |
347 newPosition = m_attackPosition + (deltaTime - m_attackTime) * m_desiredV
elocity; | |
348 else { | |
349 // release is based on targeting the exact final position. | |
350 double releaseDeltaT = deltaTime - (m_animationTime - m_releaseTime); | |
351 newPosition = releaseCurve(m_releaseCurve, releaseDeltaT, m_releaseTime,
m_releasePosition, m_desiredPosition); | |
352 } | |
353 | |
354 // Normalize velocity to a per second amount. Could be used to check for jan
k. | |
355 if (lastScrollInterval > 0) | |
356 m_currentVelocity = (newPosition - *m_currentPosition) / lastScrollInter
val; | |
357 *m_currentPosition = newPosition; | |
358 | |
359 return true; | |
360 } | |
361 | |
362 void ScrollAnimatorNone::PerAxisData::updateVisibleLength(int visibleLength) | |
363 { | |
364 m_visibleLength = visibleLength; | |
365 } | |
366 | |
367 ScrollAnimatorNone::ScrollAnimatorNone(ScrollableArea* scrollableArea) | |
368 : ScrollAnimator(scrollableArea) | |
369 , m_horizontalData(this, &m_currentPosX, scrollableArea->visibleWidth()) | |
370 , m_verticalData(this, &m_currentPosY, scrollableArea->visibleHeight()) | |
371 , m_startTime(0) | |
372 , m_animationActive(false) | |
373 { | |
374 } | |
375 | |
376 ScrollAnimatorNone::~ScrollAnimatorNone() | |
377 { | |
378 stopAnimationTimerIfNeeded(); | |
379 } | |
380 | |
381 ScrollAnimatorNone::Parameters ScrollAnimatorNone::parametersForScrollGranularit
y(ScrollGranularity granularity) const | |
382 { | |
383 switch (granularity) { | |
384 case ScrollByDocument: | |
385 return Parameters(true, 20 * kTickTime, 10 * kTickTime, Cubic, 10 * kTic
kTime, Cubic, 10 * kTickTime, Linear, 1); | |
386 case ScrollByLine: | |
387 return Parameters(true, 10 * kTickTime, 7 * kTickTime, Cubic, 3 * kTickT
ime, Cubic, 3 * kTickTime, Linear, 1); | |
388 case ScrollByPage: | |
389 return Parameters(true, 15 * kTickTime, 10 * kTickTime, Cubic, 5 * kTick
Time, Cubic, 5 * kTickTime, Linear, 1); | |
390 case ScrollByPixel: | |
391 return Parameters(true, 11 * kTickTime, 2 * kTickTime, Cubic, 3 * kTickT
ime, Cubic, 3 * kTickTime, Quadratic, 1.25); | |
392 default: | |
393 ASSERT_NOT_REACHED(); | |
394 } | |
395 return Parameters(); | |
396 } | |
397 | |
398 bool ScrollAnimatorNone::scroll(ScrollbarOrientation orientation, ScrollGranular
ity granularity, float step, float multiplier) | |
399 { | |
400 if (!m_scrollableArea->scrollAnimatorEnabled()) | |
401 return ScrollAnimator::scroll(orientation, granularity, step, multiplier
); | |
402 | |
403 TRACE_EVENT0("webkit", "ScrollAnimatorNone::scroll"); | |
404 | |
405 // FIXME: get the type passed in. MouseWheel could also be by line, but shou
ld still have different | |
406 // animation parameters than the keyboard. | |
407 Parameters parameters; | |
408 switch (granularity) { | |
409 case ScrollByDocument: | |
410 case ScrollByLine: | |
411 case ScrollByPage: | |
412 case ScrollByPixel: | |
413 parameters = parametersForScrollGranularity(granularity); | |
414 break; | |
415 case ScrollByPrecisePixel: | |
416 return ScrollAnimator::scroll(orientation, granularity, step, multiplier
); | |
417 } | |
418 | |
419 // If the individual input setting is disabled, bail. | |
420 if (!parameters.m_isEnabled) | |
421 return ScrollAnimator::scroll(orientation, granularity, step, multiplier
); | |
422 | |
423 // This is an animatable scroll. Set the animation in motion using the appro
priate parameters. | |
424 float scrollableSize = static_cast<float>(m_scrollableArea->scrollSize(orien
tation)); | |
425 | |
426 PerAxisData& data = (orientation == VerticalScrollbar) ? m_verticalData : m_
horizontalData; | |
427 bool needToScroll = data.updateDataFromParameters(step, multiplier, scrollab
leSize, WTF::monotonicallyIncreasingTime(), ¶meters); | |
428 if (needToScroll && !animationTimerActive()) { | |
429 m_startTime = data.m_startTime; | |
430 animationWillStart(); | |
431 animationTimerFired(); | |
432 } | |
433 return needToScroll; | |
434 } | |
435 | |
436 void ScrollAnimatorNone::scrollToOffsetWithoutAnimation(const FloatPoint& offset
) | |
437 { | |
438 stopAnimationTimerIfNeeded(); | |
439 | |
440 FloatSize delta = FloatSize(offset.x() - *m_horizontalData.m_currentPosition
, offset.y() - *m_verticalData.m_currentPosition); | |
441 | |
442 m_horizontalData.reset(); | |
443 *m_horizontalData.m_currentPosition = offset.x(); | |
444 m_horizontalData.m_desiredPosition = offset.x(); | |
445 | |
446 m_verticalData.reset(); | |
447 *m_verticalData.m_currentPosition = offset.y(); | |
448 m_verticalData.m_desiredPosition = offset.y(); | |
449 | |
450 notifyPositionChanged(delta); | |
451 } | |
452 | |
453 void ScrollAnimatorNone::cancelAnimations() | |
454 { | |
455 m_animationActive = false; | |
456 } | |
457 | |
458 void ScrollAnimatorNone::serviceScrollAnimations() | |
459 { | |
460 if (m_animationActive) | |
461 animationTimerFired(); | |
462 } | |
463 | |
464 void ScrollAnimatorNone::willEndLiveResize() | |
465 { | |
466 updateVisibleLengths(); | |
467 } | |
468 | |
469 void ScrollAnimatorNone::didAddVerticalScrollbar(Scrollbar*) | |
470 { | |
471 updateVisibleLengths(); | |
472 } | |
473 | |
474 void ScrollAnimatorNone::didAddHorizontalScrollbar(Scrollbar*) | |
475 { | |
476 updateVisibleLengths(); | |
477 } | |
478 | |
479 void ScrollAnimatorNone::updateVisibleLengths() | |
480 { | |
481 m_horizontalData.updateVisibleLength(scrollableArea()->visibleWidth()); | |
482 m_verticalData.updateVisibleLength(scrollableArea()->visibleHeight()); | |
483 } | |
484 | |
485 void ScrollAnimatorNone::animationTimerFired() | |
486 { | |
487 TRACE_EVENT0("webkit", "ScrollAnimatorNone::animationTimerFired"); | |
488 | |
489 double currentTime = WTF::monotonicallyIncreasingTime(); | |
490 | |
491 bool continueAnimation = false; | |
492 if (m_horizontalData.m_startTime && m_horizontalData.animateScroll(currentTi
me)) | |
493 continueAnimation = true; | |
494 if (m_verticalData.m_startTime && m_verticalData.animateScroll(currentTime)) | |
495 continueAnimation = true; | |
496 | |
497 if (continueAnimation) | |
498 startNextTimer(); | |
499 else | |
500 m_animationActive = false; | |
501 | |
502 TRACE_EVENT0("webkit", "ScrollAnimatorNone::notifyPositionChanged"); | |
503 notifyPositionChanged(FloatSize()); | |
504 | |
505 if (!continueAnimation) | |
506 animationDidFinish(); | |
507 } | |
508 | |
509 void ScrollAnimatorNone::startNextTimer() | |
510 { | |
511 if (scrollableArea()->scheduleAnimation()) | |
512 m_animationActive = true; | |
513 } | |
514 | |
515 bool ScrollAnimatorNone::animationTimerActive() | |
516 { | |
517 return m_animationActive; | |
518 } | |
519 | |
520 void ScrollAnimatorNone::stopAnimationTimerIfNeeded() | |
521 { | |
522 if (animationTimerActive()) | |
523 m_animationActive = false; | |
524 } | |
525 | |
526 } // namespace WebCore | |
OLD | NEW |