~ubuntu-branches/ubuntu/raring/qtwebkit-source/raring-proposed

« back to all changes in this revision

Viewing changes to Source/WebCore/platform/ScrollAnimatorNone.cpp

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2013-02-18 14:24:18 UTC
  • Revision ID: package-import@ubuntu.com-20130218142418-eon0jmjg3nj438uy
Tags: upstream-2.3
ImportĀ upstreamĀ versionĀ 2.3

Show diffs side-by-side

added added

removed removed

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