Replace use of OwnArrayPtr<Foo> with std::unique_ptr<Foo[]> in WebCore
[WebKit-https.git] / Source / WebCore / platform / ScrollAnimatorNone.cpp
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 #if ENABLE(SMOOTH_SCROLLING)
34
35 #include "ScrollAnimatorNone.h"
36
37 #include "FloatPoint.h"
38 #include "NotImplemented.h"
39 #include "ScrollableArea.h"
40 #include "ScrollbarTheme.h"
41 #include <algorithm>
42 #include <wtf/CurrentTime.h>
43 #include <wtf/PassOwnPtr.h>
44
45 #if ENABLE(GESTURE_EVENTS)
46 #include "PlatformGestureEvent.h"
47 #endif
48
49 using namespace std;
50
51 namespace WebCore {
52
53 const double kFrameRate = 60;
54 const double kTickTime = 1 / kFrameRate;
55 const double kMinimumTimerInterval = .001;
56 const double kZoomTicks = 11;
57
58 #if !(PLATFORM(BLACKBERRY))
59 PassOwnPtr<ScrollAnimator> ScrollAnimator::create(ScrollableArea* scrollableArea)
60 {
61     if (scrollableArea && scrollableArea->scrollAnimatorEnabled())
62         return adoptPtr(new ScrollAnimatorNone(scrollableArea));
63     return adoptPtr(new ScrollAnimator(scrollableArea));
64 }
65 #endif
66
67 ScrollAnimatorNone::Parameters::Parameters()
68     : m_isEnabled(false)
69 {
70 }
71
72 ScrollAnimatorNone::Parameters::Parameters(bool isEnabled, double animationTime, double repeatMinimumSustainTime, Curve attackCurve, double attackTime, Curve releaseCurve, double releaseTime, Curve coastTimeCurve, double maximumCoastTime)
73     : m_isEnabled(isEnabled)
74     , m_animationTime(animationTime)
75     , m_repeatMinimumSustainTime(repeatMinimumSustainTime)
76     , m_attackCurve(attackCurve)
77     , m_attackTime(attackTime)
78     , m_releaseCurve(releaseCurve)
79     , m_releaseTime(releaseTime)
80     , m_coastTimeCurve(coastTimeCurve)
81     , m_maximumCoastTime(maximumCoastTime)
82 {
83 }
84
85 double ScrollAnimatorNone::PerAxisData::curveAt(Curve curve, double t)
86 {
87     switch (curve) {
88     case Linear:
89         return t;
90     case Quadratic:
91         return t * t;
92     case Cubic:
93         return t * t * t;
94     case Quartic:
95         return t * t * t * t;
96     case Bounce:
97         // Time base is chosen to keep the bounce points simpler:
98         // 1 (half bounce coming in) + 1 + .5 + .25
99         const double kTimeBase = 2.75;
100         const double kTimeBaseSquared = kTimeBase * kTimeBase;
101         if (t < 1 / kTimeBase)
102             return kTimeBaseSquared * t * t;
103         if (t < 2 / kTimeBase) {
104             // Invert a [-.5,.5] quadratic parabola, center it in [1,2].
105             double t1 = t - 1.5 / kTimeBase;
106             const double kParabolaAtEdge = 1 - .5 * .5;
107             return kTimeBaseSquared * t1 * t1 + kParabolaAtEdge;
108         }
109         if (t < 2.5 / kTimeBase) {
110             // Invert a [-.25,.25] quadratic parabola, center it in [2,2.5].
111             double t2 = t - 2.25 / kTimeBase;
112             const double kParabolaAtEdge = 1 - .25 * .25;
113             return kTimeBaseSquared * t2 * t2 + kParabolaAtEdge;
114         }
115             // Invert a [-.125,.125] quadratic parabola, center it in [2.5,2.75].
116         const double kParabolaAtEdge = 1 - .125 * .125;
117         t -= 2.625 / kTimeBase;
118         return kTimeBaseSquared * t * t + kParabolaAtEdge;
119     }
120     ASSERT_NOT_REACHED();
121     return 0;
122 }
123
124 double ScrollAnimatorNone::PerAxisData::attackCurve(Curve curve, double deltaTime, double curveT, double startPosition, double attackPosition)
125 {
126     double t = deltaTime / curveT;
127     double positionFactor = curveAt(curve, t);
128     return startPosition + positionFactor * (attackPosition - startPosition);
129 }
130
131 double ScrollAnimatorNone::PerAxisData::releaseCurve(Curve curve, double deltaTime, double curveT, double releasePosition, double desiredPosition)
132 {
133     double t = deltaTime / curveT;
134     double positionFactor = 1 - curveAt(curve, 1 - t);
135     return releasePosition + (positionFactor * (desiredPosition - releasePosition));
136 }
137
138 double ScrollAnimatorNone::PerAxisData::coastCurve(Curve curve, double factor)
139 {
140     return 1 - curveAt(curve, 1 - factor);
141 }
142
143 double ScrollAnimatorNone::PerAxisData::curveIntegralAt(Curve curve, double t)
144 {
145     switch (curve) {
146     case Linear:
147         return t * t / 2;
148     case Quadratic:
149         return t * t * t / 3;
150     case Cubic:
151         return t * t * t * t / 4;
152     case Quartic:
153         return t * t * t * t * t / 5;
154     case Bounce:
155         const double kTimeBase = 2.75;
156         const double kTimeBaseSquared = kTimeBase * kTimeBase;
157         const double kTimeBaseSquaredOverThree = kTimeBaseSquared / 3;
158         double area;
159         double t1 = min(t, 1 / kTimeBase);
160         area = kTimeBaseSquaredOverThree * t1 * t1 * t1;
161         if (t < 1 / kTimeBase)
162             return area;
163
164         t1 = min(t - 1 / kTimeBase, 1 / kTimeBase);
165         // The integral of kTimeBaseSquared * (t1 - .5 / kTimeBase) * (t1 - .5 / kTimeBase) + kParabolaAtEdge
166         const double kSecondInnerOffset = kTimeBaseSquared * .5 / kTimeBase;
167         double bounceArea = t1 * (t1 * (kTimeBaseSquaredOverThree * t1 - kSecondInnerOffset) + 1);
168         area += bounceArea;
169         if (t < 2 / kTimeBase)
170             return area;
171
172         t1 = min(t - 2 / kTimeBase, 0.5 / kTimeBase);
173         // The integral of kTimeBaseSquared * (t1 - .25 / kTimeBase) * (t1 - .25 / kTimeBase) + kParabolaAtEdge
174         const double kThirdInnerOffset = kTimeBaseSquared * .25 / kTimeBase;
175         bounceArea =  t1 * (t1 * (kTimeBaseSquaredOverThree * t1 - kThirdInnerOffset) + 1);
176         area += bounceArea;
177         if (t < 2.5 / kTimeBase)
178             return area;
179
180         t1 = t - 2.5 / kTimeBase;
181         // The integral of kTimeBaseSquared * (t1 - .125 / kTimeBase) * (t1 - .125 / kTimeBase) + kParabolaAtEdge
182         const double kFourthInnerOffset = kTimeBaseSquared * .125 / kTimeBase;
183         bounceArea = t1 * (t1 * (kTimeBaseSquaredOverThree * t1 - kFourthInnerOffset) + 1);
184         area += bounceArea;
185         return area;
186     }
187     ASSERT_NOT_REACHED();
188     return 0;
189 }
190
191 double ScrollAnimatorNone::PerAxisData::attackArea(Curve curve, double startT, double endT)
192 {
193     double startValue = curveIntegralAt(curve, startT);
194     double endValue = curveIntegralAt(curve, endT);
195     return endValue - startValue;
196 }
197
198 double ScrollAnimatorNone::PerAxisData::releaseArea(Curve curve, double startT, double endT)
199 {
200     double startValue = curveIntegralAt(curve, 1 - endT);
201     double endValue = curveIntegralAt(curve, 1 - startT);
202     return endValue - startValue;
203 }
204
205 ScrollAnimatorNone::PerAxisData::PerAxisData(ScrollAnimatorNone* parent, float* currentPosition, int visibleLength)
206     : m_currentPosition(currentPosition)
207     , m_visibleLength(visibleLength)
208 {
209     reset();
210 }
211
212 void ScrollAnimatorNone::PerAxisData::reset()
213 {
214     m_currentVelocity = 0;
215
216     m_desiredPosition = 0;
217     m_desiredVelocity = 0;
218
219     m_startPosition = 0;
220     m_startTime = 0;
221     m_startVelocity = 0;
222
223     m_animationTime = 0;
224     m_lastAnimationTime = 0;
225
226     m_attackPosition = 0;
227     m_attackTime = 0;
228     m_attackCurve = Quadratic;
229
230     m_releasePosition = 0;
231     m_releaseTime = 0;
232     m_releaseCurve = Quadratic;
233 }
234
235
236 bool ScrollAnimatorNone::PerAxisData::updateDataFromParameters(float step, float multiplier, float scrollableSize, double currentTime, Parameters* parameters)
237 {
238     float delta = step * multiplier;
239     if (!m_startTime || !delta || (delta < 0) != (m_desiredPosition - *m_currentPosition < 0)) {
240         m_desiredPosition = *m_currentPosition;
241         m_startTime = 0;
242     }
243     float newPosition = m_desiredPosition + delta;
244
245     if (newPosition < 0 || newPosition > scrollableSize)
246         newPosition = max(min(newPosition, scrollableSize), 0.0f);
247
248     if (newPosition == m_desiredPosition)
249         return false;
250
251     m_desiredPosition = newPosition;
252
253     if (!m_startTime) {
254         m_attackTime = parameters->m_attackTime;
255         m_attackCurve = parameters->m_attackCurve;
256     }
257     m_animationTime = parameters->m_animationTime;
258     m_releaseTime = parameters->m_releaseTime;
259     m_releaseCurve = parameters->m_releaseCurve;
260
261     // Prioritize our way out of over constraint.
262     if (m_attackTime + m_releaseTime > m_animationTime) {
263         if (m_releaseTime > m_animationTime)
264             m_releaseTime = m_animationTime;
265         m_attackTime = m_animationTime - m_releaseTime;
266     }
267
268     if (!m_startTime) {
269         // FIXME: This should be the time from the event that got us here.
270         m_startTime = currentTime - kTickTime / 2;
271         m_startPosition = *m_currentPosition;
272         m_lastAnimationTime = m_startTime;
273     }
274     m_startVelocity = m_currentVelocity;
275
276     double remainingDelta = m_desiredPosition - *m_currentPosition;
277
278     double attackAreaLeft = 0;
279
280     double deltaTime = m_lastAnimationTime - m_startTime;
281     double attackTimeLeft = max(0., m_attackTime - deltaTime);
282     double timeLeft = m_animationTime - deltaTime;
283     double minTimeLeft = m_releaseTime + min(parameters->m_repeatMinimumSustainTime, m_animationTime - m_releaseTime - attackTimeLeft);
284     if (timeLeft < minTimeLeft) {
285         m_animationTime = deltaTime + minTimeLeft;
286         timeLeft = minTimeLeft;
287     }
288
289     if (parameters->m_maximumCoastTime > (parameters->m_repeatMinimumSustainTime + parameters->m_releaseTime)) {
290         double targetMaxCoastVelocity = m_visibleLength * .25 * kFrameRate;
291         // This needs to be as minimal as possible while not being intrusive to page up/down.
292         double minCoastDelta = m_visibleLength;
293
294         if (fabs(remainingDelta) > minCoastDelta) {
295             double maxCoastDelta = parameters->m_maximumCoastTime * targetMaxCoastVelocity;
296             double coastFactor = min(1., (fabs(remainingDelta) - minCoastDelta) / (maxCoastDelta - minCoastDelta));
297
298             // We could play with the curve here - linear seems a little soft. Initial testing makes me want to feed into the sustain time more aggressively.
299             double coastMinTimeLeft = min(parameters->m_maximumCoastTime, minTimeLeft + coastCurve(parameters->m_coastTimeCurve, coastFactor) * (parameters->m_maximumCoastTime - minTimeLeft));
300
301             double additionalTime = max(0., coastMinTimeLeft - minTimeLeft);
302             if (additionalTime) {
303                 double additionalReleaseTime = min(additionalTime, parameters->m_releaseTime / (parameters->m_releaseTime + parameters->m_repeatMinimumSustainTime) * additionalTime);
304                 m_releaseTime = parameters->m_releaseTime + additionalReleaseTime;
305                 m_animationTime = deltaTime + coastMinTimeLeft;
306                 timeLeft = coastMinTimeLeft;
307             }
308         }
309     }
310
311     double releaseTimeLeft = min(timeLeft, m_releaseTime);
312     double sustainTimeLeft = max(0., timeLeft - releaseTimeLeft - attackTimeLeft);
313
314     if (attackTimeLeft) {
315         double attackSpot = deltaTime / m_attackTime;
316         attackAreaLeft = attackArea(m_attackCurve, attackSpot, 1) * m_attackTime;
317     }
318
319     double releaseSpot = (m_releaseTime - releaseTimeLeft) / m_releaseTime;
320     double releaseAreaLeft  = releaseArea(m_releaseCurve, releaseSpot, 1) * m_releaseTime;
321
322     m_desiredVelocity = remainingDelta / (attackAreaLeft + sustainTimeLeft + releaseAreaLeft);
323     m_releasePosition = m_desiredPosition - m_desiredVelocity * releaseAreaLeft;
324     if (attackAreaLeft)
325         m_attackPosition = m_startPosition + m_desiredVelocity * attackAreaLeft;
326     else
327         m_attackPosition = m_releasePosition - (m_animationTime - m_releaseTime - m_attackTime) * m_desiredVelocity;
328
329     if (sustainTimeLeft) {
330         double roundOff = m_releasePosition - ((attackAreaLeft ? m_attackPosition : *m_currentPosition) + m_desiredVelocity * sustainTimeLeft);
331         m_desiredVelocity += roundOff / sustainTimeLeft;
332     }
333
334     return true;
335 }
336
337 // FIXME: Add in jank detection trace events into this function.
338 bool ScrollAnimatorNone::PerAxisData::animateScroll(double currentTime)
339 {
340     double lastScrollInterval = currentTime - m_lastAnimationTime;
341     if (lastScrollInterval < kMinimumTimerInterval)
342         return true;
343
344     m_lastAnimationTime = currentTime;
345
346     double deltaTime = currentTime - m_startTime;
347     double newPosition = *m_currentPosition;
348
349     if (deltaTime > m_animationTime) {
350         *m_currentPosition = m_desiredPosition;
351         reset();
352         return false;
353     }
354     if (deltaTime < m_attackTime)
355         newPosition = attackCurve(m_attackCurve, deltaTime, m_attackTime, m_startPosition, m_attackPosition);
356     else if (deltaTime < (m_animationTime - m_releaseTime))
357         newPosition = m_attackPosition + (deltaTime - m_attackTime) * m_desiredVelocity;
358     else {
359         // release is based on targeting the exact final position.
360         double releaseDeltaT = deltaTime - (m_animationTime - m_releaseTime);
361         newPosition = releaseCurve(m_releaseCurve, releaseDeltaT, m_releaseTime, m_releasePosition, m_desiredPosition);
362     }
363
364     // Normalize velocity to a per second amount. Could be used to check for jank.
365     if (lastScrollInterval > 0)
366         m_currentVelocity = (newPosition - *m_currentPosition) / lastScrollInterval;
367     *m_currentPosition = newPosition;
368
369     return true;
370 }
371
372 void ScrollAnimatorNone::PerAxisData::updateVisibleLength(int visibleLength)
373 {
374     m_visibleLength = visibleLength;
375 }
376
377 ScrollAnimatorNone::ScrollAnimatorNone(ScrollableArea* scrollableArea)
378     : ScrollAnimator(scrollableArea)
379     , m_horizontalData(this, &m_currentPosX, scrollableArea->visibleWidth())
380     , m_verticalData(this, &m_currentPosY, scrollableArea->visibleHeight())
381     , m_startTime(0)
382 #if USE(REQUEST_ANIMATION_FRAME_TIMER)
383     , m_animationTimer(this, &ScrollAnimatorNone::animationTimerFired)
384 #else
385     , m_animationActive(false)
386 #endif
387 {
388 }
389
390 ScrollAnimatorNone::~ScrollAnimatorNone()
391 {
392     stopAnimationTimerIfNeeded();
393 }
394
395 ScrollAnimatorNone::Parameters ScrollAnimatorNone::parametersForScrollGranularity(ScrollGranularity granularity) const
396 {
397 #if !PLATFORM(QT)
398     switch (granularity) {
399     case ScrollByDocument:
400         return Parameters(true, 20 * kTickTime, 10 * kTickTime, Cubic, 10 * kTickTime, Cubic, 10 * kTickTime, Linear, 1);
401     case ScrollByLine:
402         return Parameters(true, 10 * kTickTime, 7 * kTickTime, Cubic, 3 * kTickTime, Cubic, 3 * kTickTime, Linear, 1);
403     case ScrollByPage:
404         return Parameters(true, 15 * kTickTime, 10 * kTickTime, Cubic, 5 * kTickTime, Cubic, 5 * kTickTime, Linear, 1);
405     case ScrollByPixel:
406         return Parameters(true, 11 * kTickTime, 2 * kTickTime, Cubic, 3 * kTickTime, Cubic, 3 * kTickTime, Quadratic, 1.25);
407     default:
408         ASSERT_NOT_REACHED();
409     }
410 #else
411     // This is a slightly different strategy for the animation with a steep attack curve and natural release curve.
412     // The fast acceleration makes the animation look more responsive to user input.
413     switch (granularity) {
414     case ScrollByDocument:
415         return Parameters(true, 20 * kTickTime, 10 * kTickTime, Cubic, 6 * kTickTime, Quadratic, 10 * kTickTime, Quadratic, 22 * kTickTime);
416     case ScrollByLine:
417         return Parameters(true, 6 * kTickTime, 5 * kTickTime, Cubic, 1 * kTickTime, Quadratic, 4 * kTickTime, Linear, 1);
418     case ScrollByPage:
419         return Parameters(true, 12 * kTickTime, 10 * kTickTime, Cubic, 3 * kTickTime, Quadratic, 6 * kTickTime, Linear, 1);
420     case ScrollByPixel:
421         return Parameters(true, 8 * kTickTime, 3 * kTickTime, Cubic, 2 * kTickTime, Quadratic, 5 * kTickTime, Quadratic, 1.25);
422     default:
423         ASSERT_NOT_REACHED();
424     }
425 #endif
426     return Parameters();
427 }
428
429 bool ScrollAnimatorNone::scroll(ScrollbarOrientation orientation, ScrollGranularity granularity, float step, float multiplier)
430 {
431     if (!m_scrollableArea->scrollAnimatorEnabled())
432         return ScrollAnimator::scroll(orientation, granularity, step, multiplier);
433
434     // FIXME: get the type passed in. MouseWheel could also be by line, but should still have different
435     // animation parameters than the keyboard.
436     Parameters parameters;
437     switch (granularity) {
438     case ScrollByDocument:
439     case ScrollByLine:
440     case ScrollByPage:
441     case ScrollByPixel:
442         parameters = parametersForScrollGranularity(granularity);
443         break;
444     case ScrollByPrecisePixel:
445         return ScrollAnimator::scroll(orientation, granularity, step, multiplier);
446     }
447
448     // If the individual input setting is disabled, bail.
449     if (!parameters.m_isEnabled)
450         return ScrollAnimator::scroll(orientation, granularity, step, multiplier);
451
452     // This is an animatable scroll. Set the animation in motion using the appropriate parameters.
453     float scrollableSize = static_cast<float>(m_scrollableArea->scrollSize(orientation));
454
455     PerAxisData& data = (orientation == VerticalScrollbar) ? m_verticalData : m_horizontalData;
456     bool needToScroll = data.updateDataFromParameters(step, multiplier, scrollableSize, monotonicallyIncreasingTime(), &parameters);
457     if (needToScroll && !animationTimerActive()) {
458         m_startTime = data.m_startTime;
459         animationWillStart();
460         animationTimerFired();
461     }
462     return needToScroll;
463 }
464
465 void ScrollAnimatorNone::scrollToOffsetWithoutAnimation(const FloatPoint& offset)
466 {
467     stopAnimationTimerIfNeeded();
468
469     FloatSize delta = FloatSize(offset.x() - *m_horizontalData.m_currentPosition, offset.y() - *m_verticalData.m_currentPosition);
470
471     m_horizontalData.reset();
472     *m_horizontalData.m_currentPosition = offset.x();
473     m_horizontalData.m_desiredPosition = offset.x();
474
475     m_verticalData.reset();
476     *m_verticalData.m_currentPosition = offset.y();
477     m_verticalData.m_desiredPosition = offset.y();
478
479     notifyPositionChanged(delta);
480 }
481
482 #if !USE(REQUEST_ANIMATION_FRAME_TIMER)
483 void ScrollAnimatorNone::cancelAnimations()
484 {
485     m_animationActive = false;
486 }
487
488 void ScrollAnimatorNone::serviceScrollAnimations()
489 {
490     if (m_animationActive)
491         animationTimerFired();
492 }
493 #endif
494
495 void ScrollAnimatorNone::willEndLiveResize()
496 {
497     updateVisibleLengths();
498 }
499
500 void ScrollAnimatorNone::didAddVerticalScrollbar(Scrollbar*)
501 {
502     updateVisibleLengths();
503 }
504
505 void ScrollAnimatorNone::didAddHorizontalScrollbar(Scrollbar*)
506 {
507     updateVisibleLengths();
508 }
509
510 void ScrollAnimatorNone::updateVisibleLengths()
511 {
512     m_horizontalData.updateVisibleLength(scrollableArea()->visibleWidth());
513     m_verticalData.updateVisibleLength(scrollableArea()->visibleHeight());
514 }
515
516 #if USE(REQUEST_ANIMATION_FRAME_TIMER)
517 void ScrollAnimatorNone::animationTimerFired(Timer<ScrollAnimatorNone>* timer)
518 {
519     animationTimerFired();
520 }
521 #endif
522
523 void ScrollAnimatorNone::animationTimerFired()
524 {
525     double currentTime = monotonicallyIncreasingTime();
526     double deltaToNextFrame = ceil((currentTime - m_startTime) * kFrameRate) / kFrameRate - (currentTime - m_startTime);
527     currentTime += deltaToNextFrame;
528
529     bool continueAnimation = false;
530     if (m_horizontalData.m_startTime && m_horizontalData.animateScroll(currentTime))
531         continueAnimation = true;
532     if (m_verticalData.m_startTime && m_verticalData.animateScroll(currentTime))
533         continueAnimation = true;
534
535     if (continueAnimation)
536 #if USE(REQUEST_ANIMATION_FRAME_TIMER)
537         startNextTimer(max(kMinimumTimerInterval, deltaToNextFrame));
538 #else
539         startNextTimer();
540     else
541         m_animationActive = false;
542 #endif
543
544     notifyPositionChanged(FloatSize());
545
546     if (!continueAnimation)
547         animationDidFinish();
548 }
549
550 #if USE(REQUEST_ANIMATION_FRAME_TIMER)
551 void ScrollAnimatorNone::startNextTimer(double delay)
552 {
553     m_animationTimer.startOneShot(delay);
554 }
555 #else
556 void ScrollAnimatorNone::startNextTimer()
557 {
558     if (scrollableArea()->scheduleAnimation())
559         m_animationActive = true;
560 }
561 #endif
562
563 bool ScrollAnimatorNone::animationTimerActive()
564 {
565 #if USE(REQUEST_ANIMATION_FRAME_TIMER)
566     return m_animationTimer.isActive();
567 #else
568     return m_animationActive;
569 #endif
570 }
571
572 void ScrollAnimatorNone::stopAnimationTimerIfNeeded()
573 {
574     if (animationTimerActive())
575 #if USE(REQUEST_ANIMATION_FRAME_TIMER)
576         m_animationTimer.stop();
577 #else
578         m_animationActive = false;
579 #endif
580 }
581
582 } // namespace WebCore
583
584 #endif // ENABLE(SMOOTH_SCROLLING)