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