1 /* 2 * Copyright (C) 2010, 2011 Apple 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 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' 14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS 17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 23 * THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include "config.h" 27 28 #if ENABLE(SMOOTH_SCROLLING) 29 30 #include "ScrollAnimatorMac.h" 31 32 #include "FloatPoint.h" 33 #include "IntRect.h" 34 #include "PlatformGestureEvent.h" 35 #include "PlatformWheelEvent.h" 36 #include "ScrollView.h" 37 #include "ScrollableArea.h" 38 #include "ScrollbarTheme.h" 39 #include "ScrollbarThemeMac.h" 40 #include <wtf/PassOwnPtr.h> 41 #include <wtf/UnusedParam.h> 42 43 using namespace WebCore; 44 using namespace std; 45 46 @interface NSObject (ScrollAnimationHelperDetails) 47 - (id)initWithDelegate:(id)delegate; 48 - (void)_stopRun; 49 - (BOOL)_isAnimating; 50 - (NSPoint)targetOrigin; 51 @end 52 53 @interface ScrollAnimationHelperDelegate : NSObject 54 { 55 WebCore::ScrollAnimatorMac* _animator; 56 } 57 - (id)initWithScrollAnimator:(WebCore::ScrollAnimatorMac*)scrollAnimator; 58 @end 59 60 static NSSize abs(NSSize size) 61 { 62 NSSize finalSize = size; 63 if (finalSize.width < 0) 64 finalSize.width = -finalSize.width; 65 if (finalSize.height < 0) 66 finalSize.height = -finalSize.height; 67 return finalSize; 68 } 69 70 @implementation ScrollAnimationHelperDelegate 71 72 - (id)initWithScrollAnimator:(WebCore::ScrollAnimatorMac*)scrollAnimator 73 { 74 self = [super init]; 75 if (!self) 76 return nil; 77 78 _animator = scrollAnimator; 79 return self; 80 } 81 82 - (void)scrollAnimatorDestroyed 83 { 84 _animator = 0; 85 } 86 87 - (NSRect)bounds 88 { 89 if (!_animator) 90 return NSZeroRect; 91 92 WebCore::FloatPoint currentPosition = _animator->currentPosition(); 93 return NSMakeRect(currentPosition.x(), currentPosition.y(), 0, 0); 94 } 95 96 - (void)_immediateScrollToPoint:(NSPoint)newPosition 97 { 98 if (!_animator) 99 return; 100 _animator->immediateScrollToPoint(newPosition); 101 } 102 103 - (NSPoint)_pixelAlignProposedScrollPosition:(NSPoint)newOrigin 104 { 105 return newOrigin; 106 } 107 108 - (NSSize)convertSizeToBase:(NSSize)size 109 { 110 return abs(size); 111 } 112 113 - (NSSize)convertSizeFromBase:(NSSize)size 114 { 115 return abs(size); 116 } 117 118 - (NSSize)convertSizeToBacking:(NSSize)size 119 { 120 return abs(size); 121 } 122 123 - (NSSize)convertSizeFromBacking:(NSSize)size 124 { 125 return abs(size); 126 } 127 128 - (id)superview 129 { 130 return nil; 131 } 132 133 - (id)documentView 134 { 135 return nil; 136 } 137 138 - (id)window 139 { 140 return nil; 141 } 142 143 - (void)_recursiveRecomputeToolTips 144 { 145 } 146 147 @end 148 149 #if USE(WK_SCROLLBAR_PAINTER) 150 151 @interface ScrollbarPainterControllerDelegate : NSObject 152 { 153 WebCore::ScrollAnimatorMac* _animator; 154 } 155 - (id)initWithScrollAnimator:(WebCore::ScrollAnimatorMac*)scrollAnimator; 156 @end 157 158 @implementation ScrollbarPainterControllerDelegate 159 160 - (id)initWithScrollAnimator:(WebCore::ScrollAnimatorMac*)scrollAnimator 161 { 162 self = [super init]; 163 if (!self) 164 return nil; 165 166 _animator = scrollAnimator; 167 return self; 168 } 169 170 - (void)scrollAnimatorDestroyed 171 { 172 _animator = 0; 173 } 174 175 - (NSRect)contentAreaRectForScrollerImpPair:(id)scrollerImpPair 176 { 177 UNUSED_PARAM(scrollerImpPair); 178 if (!_animator) 179 return NSZeroRect; 180 181 WebCore::IntSize contentsSize = _animator->scrollableArea()->contentsSize(); 182 return NSMakeRect(0, 0, contentsSize.width(), contentsSize.height()); 183 } 184 185 - (BOOL)inLiveResizeForScrollerImpPair:(id)scrollerImpPair 186 { 187 UNUSED_PARAM(scrollerImpPair); 188 if (!_animator) 189 return NO; 190 191 return _animator->scrollableArea()->inLiveResize(); 192 } 193 194 - (NSPoint)mouseLocationInContentAreaForScrollerImpPair:(id)scrollerImpPair 195 { 196 UNUSED_PARAM(scrollerImpPair); 197 if (!_animator) 198 return NSZeroPoint; 199 200 return _animator->scrollableArea()->currentMousePosition(); 201 } 202 203 - (NSPoint)scrollerImpPair:(id)scrollerImpPair convertContentPoint:(NSPoint)pointInContentArea toScrollerImp:(id)scrollerImp 204 { 205 UNUSED_PARAM(scrollerImpPair); 206 if (!_animator) 207 return NSZeroPoint; 208 209 WebCore::Scrollbar* scrollbar = 0; 210 if (wkScrollbarPainterIsHorizontal((WKScrollbarPainterRef)scrollerImp)) 211 scrollbar = _animator->scrollableArea()->horizontalScrollbar(); 212 else 213 scrollbar = _animator->scrollableArea()->verticalScrollbar(); 214 215 // It is possible to have a null scrollbar here since it is possible for this delegate 216 // method to be called between the moment when a scrollbar has been set to 0 and the 217 // moment when its destructor has been called. We should probably de-couple some 218 // of the clean-up work in ScrollbarThemeMac::unregisterScrollbar() to avoid this 219 // issue. 220 if (!scrollbar) 221 return WebCore::IntPoint(); 222 223 return scrollbar->convertFromContainingView(WebCore::IntPoint(pointInContentArea)); 224 } 225 226 - (void)scrollerImpPair:(id)scrollerImpPair setContentAreaNeedsDisplayInRect:(NSRect)rect 227 { 228 UNUSED_PARAM(scrollerImpPair); 229 UNUSED_PARAM(rect); 230 } 231 232 - (void)scrollerImpPair:(id)scrollerImpPair updateScrollerStyleForNewRecommendedScrollerStyle:(NSScrollerStyle)newRecommendedScrollerStyle 233 { 234 if (!_animator) 235 return; 236 237 WKScrollbarPainterControllerRef painterController = (WKScrollbarPainterControllerRef)scrollerImpPair; 238 WebCore::ScrollbarThemeMac* macTheme = (WebCore::ScrollbarThemeMac*)WebCore::ScrollbarTheme::nativeTheme(); 239 240 WKScrollbarPainterRef oldVerticalPainter = wkVerticalScrollbarPainterForController(painterController); 241 if (oldVerticalPainter) { 242 WebCore::Scrollbar* verticalScrollbar = _animator->scrollableArea()->verticalScrollbar(); 243 WKScrollbarPainterRef newVerticalPainter = wkMakeScrollbarReplacementPainter(oldVerticalPainter, 244 newRecommendedScrollerStyle, 245 verticalScrollbar->controlSize(), 246 false); 247 macTheme->setNewPainterForScrollbar(verticalScrollbar, newVerticalPainter); 248 wkSetPainterForPainterController(painterController, newVerticalPainter, false); 249 250 // The different scrollbar styles have different thicknesses, so we must re-set the 251 // frameRect to the new thickness, and the re-layout below will ensure the position 252 // and length are properly updated. 253 int thickness = macTheme->scrollbarThickness(verticalScrollbar->controlSize()); 254 verticalScrollbar->setFrameRect(WebCore::IntRect(0, 0, thickness, thickness)); 255 } 256 257 WKScrollbarPainterRef oldHorizontalPainter = wkHorizontalScrollbarPainterForController(painterController); 258 if (oldHorizontalPainter) { 259 WebCore::Scrollbar* horizontalScrollbar = _animator->scrollableArea()->horizontalScrollbar(); 260 WKScrollbarPainterRef newHorizontalPainter = wkMakeScrollbarReplacementPainter(oldHorizontalPainter, 261 newRecommendedScrollerStyle, 262 horizontalScrollbar->controlSize(), 263 true); 264 macTheme->setNewPainterForScrollbar(horizontalScrollbar, newHorizontalPainter); 265 wkSetPainterForPainterController(painterController, newHorizontalPainter, true); 266 267 // The different scrollbar styles have different thicknesses, so we must re-set the 268 // frameRect to the new thickness, and the re-layout below will ensure the position 269 // and length are properly updated. 270 int thickness = macTheme->scrollbarThickness(horizontalScrollbar->controlSize()); 271 horizontalScrollbar->setFrameRect(WebCore::IntRect(0, 0, thickness, thickness)); 272 } 273 274 wkSetScrollbarPainterControllerStyle(painterController, newRecommendedScrollerStyle); 275 276 // The different scrollbar styles affect layout, so we must re-layout everything. 277 _animator->scrollableArea()->scrollbarStyleChanged(); 278 } 279 280 @end 281 282 @interface ScrollbarPartAnimation : NSAnimation 283 { 284 RetainPtr<WKScrollbarPainterRef> _scrollerPainter; 285 WebCore::ScrollbarPart _part; 286 WebCore::ScrollAnimatorMac* _animator; 287 CGFloat _initialAlpha; 288 CGFloat _newAlpha; 289 } 290 - (id)initWithScrollbarPainter:(WKScrollbarPainterRef)scrollerPainter part:(WebCore::ScrollbarPart)part scrollAnimator:(WebCore::ScrollAnimatorMac*)scrollAnimator animateAlphaTo:(CGFloat)newAlpha duration:(NSTimeInterval)duration; 291 @end 292 293 @implementation ScrollbarPartAnimation 294 295 - (id)initWithScrollbarPainter:(WKScrollbarPainterRef)scrollerPainter part:(WebCore::ScrollbarPart)part scrollAnimator:(WebCore::ScrollAnimatorMac*)scrollAnimator animateAlphaTo:(CGFloat)newAlpha duration:(NSTimeInterval)duration 296 { 297 self = [super initWithDuration:duration animationCurve:NSAnimationEaseInOut]; 298 if (!self) 299 return nil; 300 301 _scrollerPainter = scrollerPainter; 302 _part = part; 303 _animator = scrollAnimator; 304 _initialAlpha = _part == WebCore::ThumbPart ? wkScrollbarPainterKnobAlpha(_scrollerPainter.get()) : wkScrollbarPainterTrackAlpha(_scrollerPainter.get()); 305 _newAlpha = newAlpha; 306 307 return self; 308 } 309 310 - (void)setCurrentProgress:(NSAnimationProgress)progress 311 { 312 [super setCurrentProgress:progress]; 313 314 if (!_animator) 315 return; 316 317 CGFloat currentAlpha; 318 if (_initialAlpha > _newAlpha) 319 currentAlpha = 1 - progress; 320 else 321 currentAlpha = progress; 322 323 if (_part == WebCore::ThumbPart) 324 wkSetScrollbarPainterKnobAlpha(_scrollerPainter.get(), currentAlpha); 325 else 326 wkSetScrollbarPainterTrackAlpha(_scrollerPainter.get(), currentAlpha); 327 328 // Invalidate the scrollbars so that they paint the animation 329 if (WebCore::Scrollbar* verticalScrollbar = _animator->scrollableArea()->verticalScrollbar()) 330 verticalScrollbar->invalidateRect(WebCore::IntRect(0, 0, verticalScrollbar->width(), verticalScrollbar->height())); 331 if (WebCore::Scrollbar* horizontalScrollbar = _animator->scrollableArea()->horizontalScrollbar()) 332 horizontalScrollbar->invalidateRect(WebCore::IntRect(0, 0, horizontalScrollbar->width(), horizontalScrollbar->height())); 333 } 334 335 - (void)scrollAnimatorDestroyed 336 { 337 [self stopAnimation]; 338 _animator = 0; 339 } 340 341 @end 342 343 @interface ScrollbarPainterDelegate : NSObject<NSAnimationDelegate> 344 { 345 WebCore::ScrollAnimatorMac* _animator; 346 347 RetainPtr<ScrollbarPartAnimation> _verticalKnobAnimation; 348 RetainPtr<ScrollbarPartAnimation> _horizontalKnobAnimation; 349 350 RetainPtr<ScrollbarPartAnimation> _verticalTrackAnimation; 351 RetainPtr<ScrollbarPartAnimation> _horizontalTrackAnimation; 352 } 353 - (id)initWithScrollAnimator:(WebCore::ScrollAnimatorMac*)scrollAnimator; 354 - (void)cancelAnimations; 355 @end 356 357 @implementation ScrollbarPainterDelegate 358 359 - (id)initWithScrollAnimator:(WebCore::ScrollAnimatorMac*)scrollAnimator 360 { 361 self = [super init]; 362 if (!self) 363 return nil; 364 365 _animator = scrollAnimator; 366 return self; 367 } 368 369 - (void)cancelAnimations 370 { 371 [_verticalKnobAnimation.get() stopAnimation]; 372 [_horizontalKnobAnimation.get() stopAnimation]; 373 [_verticalTrackAnimation.get() stopAnimation]; 374 [_horizontalTrackAnimation.get() stopAnimation]; 375 } 376 377 - (NSRect)convertRectToBacking:(NSRect)aRect 378 { 379 return aRect; 380 } 381 382 - (NSRect)convertRectFromBacking:(NSRect)aRect 383 { 384 return aRect; 385 } 386 387 - (CALayer *)layer 388 { 389 if (!_animator) 390 return nil; 391 if (!_animator->isDrawingIntoLayer()) 392 return nil; 393 394 // FIXME: This should attempt to return an actual layer. 395 static CALayer *dummyLayer = [[CALayer alloc] init]; 396 return dummyLayer; 397 } 398 399 - (void)setUpAnimation:(RetainPtr<ScrollbarPartAnimation>&)scrollbarPartAnimation scrollerPainter:(WKScrollbarPainterRef)scrollerPainter part:(WebCore::ScrollbarPart)part animateAlphaTo:(CGFloat)newAlpha duration:(NSTimeInterval)duration 400 { 401 // If the user has scrolled the page, then the scrollbars must be animated here. 402 // This overrides the early returns. 403 bool mustAnimate = _animator->haveScrolledSincePageLoad(); 404 405 if (_animator->scrollbarPaintTimerIsActive() && !mustAnimate) 406 return; 407 408 if (_animator->scrollableArea()->shouldSuspendScrollAnimations() && !mustAnimate) { 409 _animator->startScrollbarPaintTimer(); 410 return; 411 } 412 413 // At this point, we are definitely going to animate now, so stop the timer. 414 _animator->stopScrollbarPaintTimer(); 415 416 // If we are currently animating, stop 417 if (scrollbarPartAnimation) { 418 [scrollbarPartAnimation.get() stopAnimation]; 419 scrollbarPartAnimation = nil; 420 } 421 422 [NSAnimationContext beginGrouping]; 423 [[NSAnimationContext currentContext] setDuration:duration]; 424 scrollbarPartAnimation.adoptNS([[ScrollbarPartAnimation alloc] initWithScrollbarPainter:scrollerPainter 425 part:part 426 scrollAnimator:_animator 427 animateAlphaTo:newAlpha 428 duration:duration]); 429 [scrollbarPartAnimation.get() setAnimationBlockingMode:NSAnimationNonblocking]; 430 [scrollbarPartAnimation.get() startAnimation]; 431 [NSAnimationContext endGrouping]; 432 } 433 434 - (void)scrollerImp:(id)scrollerImp animateKnobAlphaTo:(CGFloat)newKnobAlpha duration:(NSTimeInterval)duration 435 { 436 if (!_animator) 437 return; 438 439 WKScrollbarPainterRef scrollerPainter = (WKScrollbarPainterRef)scrollerImp; 440 if (wkScrollbarPainterIsHorizontal(scrollerPainter)) 441 [self setUpAnimation:_horizontalKnobAnimation scrollerPainter:scrollerPainter part:WebCore::ThumbPart animateAlphaTo:newKnobAlpha duration:duration]; 442 else 443 [self setUpAnimation:_verticalKnobAnimation scrollerPainter:scrollerPainter part:WebCore::ThumbPart animateAlphaTo:newKnobAlpha duration:duration]; 444 } 445 446 - (void)scrollerImp:(id)scrollerImp animateTrackAlphaTo:(CGFloat)newTrackAlpha duration:(NSTimeInterval)duration 447 { 448 if (!_animator) 449 return; 450 451 WKScrollbarPainterRef scrollerPainter = (WKScrollbarPainterRef)scrollerImp; 452 if (wkScrollbarPainterIsHorizontal(scrollerPainter)) 453 [self setUpAnimation:_horizontalTrackAnimation scrollerPainter:scrollerPainter part:WebCore::BackTrackPart animateAlphaTo:newTrackAlpha duration:duration]; 454 else 455 [self setUpAnimation:_verticalTrackAnimation scrollerPainter:scrollerPainter part:WebCore::BackTrackPart animateAlphaTo:newTrackAlpha duration:duration]; 456 } 457 458 - (void)scrollerImp:(id)scrollerImp overlayScrollerStateChangedTo:(NSUInteger)newOverlayScrollerState 459 { 460 UNUSED_PARAM(scrollerImp); 461 UNUSED_PARAM(newOverlayScrollerState); 462 } 463 464 - (void)scrollAnimatorDestroyed 465 { 466 _animator = 0; 467 [_verticalKnobAnimation.get() scrollAnimatorDestroyed]; 468 [_horizontalKnobAnimation.get() scrollAnimatorDestroyed]; 469 [_verticalTrackAnimation.get() scrollAnimatorDestroyed]; 470 [_horizontalTrackAnimation.get() scrollAnimatorDestroyed]; 471 } 472 473 @end 474 475 #endif // USE(WK_SCROLLBAR_PAINTER) 476 477 namespace WebCore { 478 479 PassOwnPtr<ScrollAnimator> ScrollAnimator::create(ScrollableArea* scrollableArea) 480 { 481 return adoptPtr(new ScrollAnimatorMac(scrollableArea)); 482 } 483 484 ScrollAnimatorMac::ScrollAnimatorMac(ScrollableArea* scrollableArea) 485 : ScrollAnimator(scrollableArea) 486 #if USE(WK_SCROLLBAR_PAINTER) 487 , m_initialScrollbarPaintTimer(this, &ScrollAnimatorMac::initialScrollbarPaintTimerFired) 488 #endif 489 #if ENABLE(RUBBER_BANDING) 490 , m_inScrollGesture(false) 491 , m_momentumScrollInProgress(false) 492 , m_ignoreMomentumScrolls(false) 493 , m_lastMomemtumScrollTimestamp(0) 494 , m_startTime(0) 495 , m_snapRubberBandTimer(this, &ScrollAnimatorMac::snapRubberBandTimerFired) 496 #endif 497 , m_drawingIntoLayer(false) 498 , m_haveScrolledSincePageLoad(false) 499 { 500 m_scrollAnimationHelperDelegate.adoptNS([[ScrollAnimationHelperDelegate alloc] initWithScrollAnimator:this]); 501 m_scrollAnimationHelper.adoptNS([[NSClassFromString(@"NSScrollAnimationHelper") alloc] initWithDelegate:m_scrollAnimationHelperDelegate.get()]); 502 503 #if USE(WK_SCROLLBAR_PAINTER) 504 m_scrollbarPainterControllerDelegate.adoptNS([[ScrollbarPainterControllerDelegate alloc] initWithScrollAnimator:this]); 505 m_scrollbarPainterController = wkMakeScrollbarPainterController(m_scrollbarPainterControllerDelegate.get()); 506 m_scrollbarPainterDelegate.adoptNS([[ScrollbarPainterDelegate alloc] initWithScrollAnimator:this]); 507 #endif 508 } 509 510 ScrollAnimatorMac::~ScrollAnimatorMac() 511 { 512 #if USE(WK_SCROLLBAR_PAINTER) 513 [m_scrollbarPainterControllerDelegate.get() scrollAnimatorDestroyed]; 514 [(id)m_scrollbarPainterController.get() setDelegate:nil]; 515 [m_scrollbarPainterDelegate.get() scrollAnimatorDestroyed]; 516 [m_scrollAnimationHelperDelegate.get() scrollAnimatorDestroyed]; 517 #endif 518 } 519 520 bool ScrollAnimatorMac::scroll(ScrollbarOrientation orientation, ScrollGranularity granularity, float step, float multiplier) 521 { 522 m_haveScrolledSincePageLoad = true; 523 524 if (![[NSUserDefaults standardUserDefaults] boolForKey:@"AppleScrollAnimationEnabled"]) 525 return ScrollAnimator::scroll(orientation, granularity, step, multiplier); 526 527 if (granularity == ScrollByPixel) 528 return ScrollAnimator::scroll(orientation, granularity, step, multiplier); 529 530 float currentPos = orientation == HorizontalScrollbar ? m_currentPosX : m_currentPosY; 531 float newPos = std::max<float>(std::min<float>(currentPos + (step * multiplier), static_cast<float>(m_scrollableArea->scrollSize(orientation))), 0); 532 if (currentPos == newPos) 533 return false; 534 535 NSPoint newPoint; 536 if ([m_scrollAnimationHelper.get() _isAnimating]) { 537 NSPoint targetOrigin = [m_scrollAnimationHelper.get() targetOrigin]; 538 newPoint = orientation == HorizontalScrollbar ? NSMakePoint(newPos, targetOrigin.y) : NSMakePoint(targetOrigin.x, newPos); 539 } else 540 newPoint = orientation == HorizontalScrollbar ? NSMakePoint(newPos, m_currentPosY) : NSMakePoint(m_currentPosX, newPos); 541 542 [m_scrollAnimationHelper.get() scrollToPoint:newPoint]; 543 return true; 544 } 545 546 void ScrollAnimatorMac::scrollToOffsetWithoutAnimation(const FloatPoint& offset) 547 { 548 [m_scrollAnimationHelper.get() _stopRun]; 549 immediateScrollToPoint(offset); 550 } 551 552 float ScrollAnimatorMac::adjustScrollXPositionIfNecessary(float position) const 553 { 554 if (!m_scrollableArea->constrainsScrollingToContentEdge()) 555 return position; 556 557 return max<float>(min<float>(position, m_scrollableArea->contentsSize().width() - m_scrollableArea->visibleWidth()), 0); 558 } 559 560 float ScrollAnimatorMac::adjustScrollYPositionIfNecessary(float position) const 561 { 562 if (!m_scrollableArea->constrainsScrollingToContentEdge()) 563 return position; 564 565 return max<float>(min<float>(position, m_scrollableArea->contentsSize().height() - m_scrollableArea->visibleHeight()), 0); 566 } 567 568 FloatPoint ScrollAnimatorMac::adjustScrollPositionIfNecessary(const FloatPoint& position) const 569 { 570 if (!m_scrollableArea->constrainsScrollingToContentEdge()) 571 return position; 572 573 float newX = max<float>(min<float>(position.x(), m_scrollableArea->contentsSize().width() - m_scrollableArea->visibleWidth()), 0); 574 float newY = max<float>(min<float>(position.y(), m_scrollableArea->contentsSize().height() - m_scrollableArea->visibleHeight()), 0); 575 576 return FloatPoint(newX, newY); 577 } 578 579 void ScrollAnimatorMac::immediateScrollToPoint(const FloatPoint& newPosition) 580 { 581 FloatPoint adjustedPosition = adjustScrollPositionIfNecessary(newPosition); 582 583 if (adjustedPosition.x() == m_currentPosX && adjustedPosition.y() == m_currentPosY) 584 return; 585 586 m_currentPosX = adjustedPosition.x(); 587 m_currentPosY = adjustedPosition.y(); 588 notityPositionChanged(); 589 } 590 591 void ScrollAnimatorMac::immediateScrollByDeltaX(float deltaX) 592 { 593 float newPosX = adjustScrollXPositionIfNecessary(m_currentPosX + deltaX); 594 595 if (newPosX == m_currentPosX) 596 return; 597 598 m_currentPosX = newPosX; 599 notityPositionChanged(); 600 } 601 602 void ScrollAnimatorMac::immediateScrollByDeltaY(float deltaY) 603 { 604 float newPosY = adjustScrollYPositionIfNecessary(m_currentPosY + deltaY); 605 606 if (newPosY == m_currentPosY) 607 return; 608 609 m_currentPosY = newPosY; 610 notityPositionChanged(); 611 } 612 613 void ScrollAnimatorMac::notityPositionChanged() 614 { 615 #if USE(WK_SCROLLBAR_PAINTER) 616 wkContentAreaScrolled(m_scrollbarPainterController.get()); 617 #endif 618 ScrollAnimator::notityPositionChanged(); 619 } 620 621 void ScrollAnimatorMac::contentAreaWillPaint() const 622 { 623 #if USE(WK_SCROLLBAR_PAINTER) 624 wkContentAreaWillPaint(m_scrollbarPainterController.get()); 625 #endif 626 } 627 628 void ScrollAnimatorMac::mouseEnteredContentArea() const 629 { 630 #if USE(WK_SCROLLBAR_PAINTER) 631 wkMouseEnteredContentArea(m_scrollbarPainterController.get()); 632 #endif 633 } 634 635 void ScrollAnimatorMac::mouseExitedContentArea() const 636 { 637 #if USE(WK_SCROLLBAR_PAINTER) 638 wkMouseExitedContentArea(m_scrollbarPainterController.get()); 639 #endif 640 } 641 642 void ScrollAnimatorMac::mouseMovedInContentArea() const 643 { 644 #if USE(WK_SCROLLBAR_PAINTER) 645 wkMouseMovedInContentArea(m_scrollbarPainterController.get()); 646 #endif 647 } 648 649 void ScrollAnimatorMac::willStartLiveResize() 650 { 651 #if USE(WK_SCROLLBAR_PAINTER) 652 wkWillStartLiveResize(m_scrollbarPainterController.get()); 653 #endif 654 } 655 656 void ScrollAnimatorMac::contentsResized() const 657 { 658 #if USE(WK_SCROLLBAR_PAINTER) 659 wkContentAreaResized(m_scrollbarPainterController.get()); 660 #endif 661 } 662 663 void ScrollAnimatorMac::willEndLiveResize() 664 { 665 #if USE(WK_SCROLLBAR_PAINTER) 666 wkWillEndLiveResize(m_scrollbarPainterController.get()); 667 #endif 668 } 669 670 void ScrollAnimatorMac::contentAreaDidShow() const 671 { 672 #if USE(WK_SCROLLBAR_PAINTER) 673 wkContentAreaDidShow(m_scrollbarPainterController.get()); 674 #endif 675 } 676 677 void ScrollAnimatorMac::contentAreaDidHide() const 678 { 679 #if USE(WK_SCROLLBAR_PAINTER) 680 wkContentAreaDidHide(m_scrollbarPainterController.get()); 681 #endif 682 } 683 684 void ScrollAnimatorMac::didBeginScrollGesture() const 685 { 686 #if USE(WK_SCROLLBAR_PAINTER) 687 wkDidBeginScrollGesture(m_scrollbarPainterController.get()); 688 #endif 689 } 690 691 void ScrollAnimatorMac::didEndScrollGesture() const 692 { 693 #if USE(WK_SCROLLBAR_PAINTER) 694 wkDidEndScrollGesture(m_scrollbarPainterController.get()); 695 #endif 696 } 697 698 void ScrollAnimatorMac::didAddVerticalScrollbar(Scrollbar* scrollbar) 699 { 700 #if USE(WK_SCROLLBAR_PAINTER) 701 WKScrollbarPainterRef painter = static_cast<WebCore::ScrollbarThemeMac*>(WebCore::ScrollbarTheme::nativeTheme())->painterForScrollbar(scrollbar); 702 wkScrollbarPainterSetDelegate(painter, m_scrollbarPainterDelegate.get()); 703 wkSetPainterForPainterController(m_scrollbarPainterController.get(), painter, false); 704 if (scrollableArea()->inLiveResize()) 705 wkSetScrollbarPainterKnobAlpha(painter, 1); 706 #else 707 UNUSED_PARAM(scrollbar); 708 #endif 709 } 710 711 void ScrollAnimatorMac::willRemoveVerticalScrollbar(Scrollbar* scrollbar) 712 { 713 #if USE(WK_SCROLLBAR_PAINTER) 714 WKScrollbarPainterRef painter = static_cast<WebCore::ScrollbarThemeMac*>(WebCore::ScrollbarTheme::nativeTheme())->painterForScrollbar(scrollbar); 715 wkScrollbarPainterSetDelegate(painter, nil); 716 wkSetPainterForPainterController(m_scrollbarPainterController.get(), nil, false); 717 #else 718 UNUSED_PARAM(scrollbar); 719 #endif 720 } 721 722 void ScrollAnimatorMac::didAddHorizontalScrollbar(Scrollbar* scrollbar) 723 { 724 #if USE(WK_SCROLLBAR_PAINTER) 725 WKScrollbarPainterRef painter = static_cast<WebCore::ScrollbarThemeMac*>(WebCore::ScrollbarTheme::nativeTheme())->painterForScrollbar(scrollbar); 726 wkScrollbarPainterSetDelegate(painter, m_scrollbarPainterDelegate.get()); 727 wkSetPainterForPainterController(m_scrollbarPainterController.get(), painter, true); 728 if (scrollableArea()->inLiveResize()) 729 wkSetScrollbarPainterKnobAlpha(painter, 1); 730 #else 731 UNUSED_PARAM(scrollbar); 732 #endif 733 } 734 735 void ScrollAnimatorMac::willRemoveHorizontalScrollbar(Scrollbar* scrollbar) 736 { 737 #if USE(WK_SCROLLBAR_PAINTER) 738 WKScrollbarPainterRef painter = static_cast<WebCore::ScrollbarThemeMac*>(WebCore::ScrollbarTheme::nativeTheme())->painterForScrollbar(scrollbar); 739 wkScrollbarPainterSetDelegate(painter, nil); 740 wkSetPainterForPainterController(m_scrollbarPainterController.get(), nil, true); 741 #else 742 UNUSED_PARAM(scrollbar); 743 #endif 744 } 745 746 void ScrollAnimatorMac::cancelAnimations() 747 { 748 m_haveScrolledSincePageLoad = false; 749 750 #if USE(WK_SCROLLBAR_PAINTER) 751 if (scrollbarPaintTimerIsActive()) 752 stopScrollbarPaintTimer(); 753 [m_scrollbarPainterDelegate.get() cancelAnimations]; 754 #endif 755 } 756 757 #if ENABLE(RUBBER_BANDING) 758 759 static const float scrollVelocityZeroingTimeout = 0.10f; 760 static const float rubberbandStiffness = 20; 761 static const float rubberbandDirectionLockStretchRatio = 1; 762 static const float rubberbandMinimumRequiredDeltaBeforeStretch = 10; 763 static const float rubberbandAmplitude = 0.31f; 764 static const float rubberbandPeriod = 1.6f; 765 766 static float elasticDeltaForTimeDelta(float initialPosition, float initialVelocity, float elapsedTime) 767 { 768 float amplitude = rubberbandAmplitude; 769 float period = rubberbandPeriod; 770 float criticalDampeningFactor = expf((-elapsedTime * rubberbandStiffness) / period); 771 772 return (initialPosition + (-initialVelocity * elapsedTime * amplitude)) * criticalDampeningFactor; 773 } 774 775 static float elasticDeltaForReboundDelta(float delta) 776 { 777 float stiffness = std::max(rubberbandStiffness, 1.0f); 778 return delta / stiffness; 779 } 780 781 static float reboundDeltaForElasticDelta(float delta) 782 { 783 return delta * rubberbandStiffness; 784 } 785 786 static float scrollWheelMultiplier() 787 { 788 static float multiplier = -1; 789 if (multiplier < 0) { 790 multiplier = [[NSUserDefaults standardUserDefaults] floatForKey:@"NSScrollWheelMultiplier"]; 791 if (multiplier <= 0) 792 multiplier = 1; 793 } 794 return multiplier; 795 } 796 797 void ScrollAnimatorMac::handleWheelEvent(PlatformWheelEvent& wheelEvent) 798 { 799 m_haveScrolledSincePageLoad = true; 800 801 if (!wheelEvent.hasPreciseScrollingDeltas()) { 802 ScrollAnimator::handleWheelEvent(wheelEvent); 803 return; 804 } 805 806 // FIXME: This is somewhat roundabout hack to allow forwarding wheel events 807 // up to the parent scrollable area. It takes advantage of the fact that 808 // the base class implemenatation of handleWheelEvent will not accept the 809 // wheel event if there is nowhere to scroll. 810 if (fabsf(wheelEvent.deltaY()) >= fabsf(wheelEvent.deltaX())) { 811 if (!allowsVerticalStretching()) { 812 ScrollAnimator::handleWheelEvent(wheelEvent); 813 return; 814 } 815 } else { 816 if (!allowsHorizontalStretching()) { 817 ScrollAnimator::handleWheelEvent(wheelEvent); 818 return; 819 } 820 } 821 822 wheelEvent.accept(); 823 824 bool isMometumScrollEvent = (wheelEvent.momentumPhase() != PlatformWheelEventPhaseNone); 825 if (m_ignoreMomentumScrolls && (isMometumScrollEvent || m_snapRubberBandTimer.isActive())) { 826 if (wheelEvent.momentumPhase() == PlatformWheelEventPhaseEnded) 827 m_ignoreMomentumScrolls = false; 828 return; 829 } 830 831 smoothScrollWithEvent(wheelEvent); 832 } 833 834 void ScrollAnimatorMac::handleGestureEvent(const PlatformGestureEvent& gestureEvent) 835 { 836 if (gestureEvent.type() == PlatformGestureEvent::ScrollBeginType) 837 beginScrollGesture(); 838 else 839 endScrollGesture(); 840 } 841 842 bool ScrollAnimatorMac::pinnedInDirection(float deltaX, float deltaY) 843 { 844 FloatSize limitDelta; 845 if (fabsf(deltaY) >= fabsf(deltaX)) { 846 if (deltaY < 0) { 847 // We are trying to scroll up. Make sure we are not pinned to the top 848 limitDelta.setHeight(m_scrollableArea->visibleContentRect().y() + + m_scrollableArea->scrollOrigin().y()); 849 } else { 850 // We are trying to scroll down. Make sure we are not pinned to the bottom 851 limitDelta.setHeight(m_scrollableArea->contentsSize().height() - (m_scrollableArea->visibleContentRect().maxY() + m_scrollableArea->scrollOrigin().y())); 852 } 853 } else if (deltaX != 0) { 854 if (deltaX < 0) { 855 // We are trying to scroll left. Make sure we are not pinned to the left 856 limitDelta.setWidth(m_scrollableArea->visibleContentRect().x() + m_scrollableArea->scrollOrigin().x()); 857 } else { 858 // We are trying to scroll right. Make sure we are not pinned to the right 859 limitDelta.setWidth(m_scrollableArea->contentsSize().width() - (m_scrollableArea->visibleContentRect().maxX() + m_scrollableArea->scrollOrigin().x())); 860 } 861 } 862 863 if ((deltaX != 0 || deltaY != 0) && (limitDelta.width() < 1 && limitDelta.height() < 1)) 864 return true; 865 return false; 866 } 867 868 bool ScrollAnimatorMac::allowsVerticalStretching() const 869 { 870 switch (m_scrollableArea->verticalScrollElasticity()) { 871 case ScrollElasticityAutomatic: { 872 Scrollbar* hScroller = m_scrollableArea->horizontalScrollbar(); 873 Scrollbar* vScroller = m_scrollableArea->verticalScrollbar(); 874 return (((vScroller && vScroller->enabled()) || (!hScroller || !hScroller->enabled()))); 875 } 876 case ScrollElasticityNone: 877 return false; 878 case ScrollElasticityAllowed: 879 return true; 880 } 881 882 ASSERT_NOT_REACHED(); 883 return false; 884 } 885 886 bool ScrollAnimatorMac::allowsHorizontalStretching() const 887 { 888 switch (m_scrollableArea->horizontalScrollElasticity()) { 889 case ScrollElasticityAutomatic: { 890 Scrollbar* hScroller = m_scrollableArea->horizontalScrollbar(); 891 Scrollbar* vScroller = m_scrollableArea->verticalScrollbar(); 892 return (((hScroller && hScroller->enabled()) || (!vScroller || !vScroller->enabled()))); 893 } 894 case ScrollElasticityNone: 895 return false; 896 case ScrollElasticityAllowed: 897 return true; 898 } 899 900 ASSERT_NOT_REACHED(); 901 return false; 902 } 903 904 void ScrollAnimatorMac::smoothScrollWithEvent(PlatformWheelEvent& wheelEvent) 905 { 906 m_haveScrolledSincePageLoad = true; 907 908 float deltaX = m_overflowScrollDelta.width(); 909 float deltaY = m_overflowScrollDelta.height(); 910 911 // Reset overflow values because we may decide to remove delta at various points and put it into overflow. 912 m_overflowScrollDelta = FloatSize(); 913 914 float eventCoallescedDeltaX = -wheelEvent.deltaX(); 915 float eventCoallescedDeltaY = -wheelEvent.deltaY(); 916 917 deltaX += eventCoallescedDeltaX; 918 deltaY += eventCoallescedDeltaY; 919 920 // Slightly prefer scrolling vertically by applying the = case to deltaY 921 if (fabsf(deltaY) >= fabsf(deltaX)) 922 deltaX = 0; 923 else 924 deltaY = 0; 925 926 bool isVerticallyStretched = false; 927 bool isHorizontallyStretched = false; 928 bool shouldStretch = false; 929 930 IntSize stretchAmount = m_scrollableArea->overhangAmount(); 931 932 isHorizontallyStretched = stretchAmount.width(); 933 isVerticallyStretched = stretchAmount.height(); 934 935 PlatformWheelEventPhase phase = wheelEvent.momentumPhase(); 936 937 // If we are starting momentum scrolling then do some setup. 938 if (!m_momentumScrollInProgress && (phase == PlatformWheelEventPhaseBegan || phase == PlatformWheelEventPhaseChanged)) 939 m_momentumScrollInProgress = true; 940 941 CFTimeInterval timeDelta = wheelEvent.timestamp() - m_lastMomemtumScrollTimestamp; 942 if (m_inScrollGesture || m_momentumScrollInProgress) { 943 if (m_lastMomemtumScrollTimestamp && timeDelta > 0 && timeDelta < scrollVelocityZeroingTimeout) { 944 m_momentumVelocity.setWidth(eventCoallescedDeltaX / (float)timeDelta); 945 m_momentumVelocity.setHeight(eventCoallescedDeltaY / (float)timeDelta); 946 m_lastMomemtumScrollTimestamp = wheelEvent.timestamp(); 947 } else { 948 m_lastMomemtumScrollTimestamp = wheelEvent.timestamp(); 949 m_momentumVelocity = FloatSize(); 950 } 951 952 if (isVerticallyStretched) { 953 if (!isHorizontallyStretched && pinnedInDirection(deltaX, 0)) { 954 // Stretching only in the vertical. 955 if (deltaY != 0 && (fabsf(deltaX / deltaY) < rubberbandDirectionLockStretchRatio)) 956 deltaX = 0; 957 else if (fabsf(deltaX) < rubberbandMinimumRequiredDeltaBeforeStretch) { 958 m_overflowScrollDelta.setWidth(m_overflowScrollDelta.width() + deltaX); 959 deltaX = 0; 960 } else 961 m_overflowScrollDelta.setWidth(m_overflowScrollDelta.width() + deltaX); 962 } 963 } else if (isHorizontallyStretched) { 964 // Stretching only in the horizontal. 965 if (pinnedInDirection(0, deltaY)) { 966 if (deltaX != 0 && (fabsf(deltaY / deltaX) < rubberbandDirectionLockStretchRatio)) 967 deltaY = 0; 968 else if (fabsf(deltaY) < rubberbandMinimumRequiredDeltaBeforeStretch) { 969 m_overflowScrollDelta.setHeight(m_overflowScrollDelta.height() + deltaY); 970 deltaY = 0; 971 } else 972 m_overflowScrollDelta.setHeight(m_overflowScrollDelta.height() + deltaY); 973 } 974 } else { 975 // Not stretching at all yet. 976 if (pinnedInDirection(deltaX, deltaY)) { 977 if (fabsf(deltaY) >= fabsf(deltaX)) { 978 if (fabsf(deltaX) < rubberbandMinimumRequiredDeltaBeforeStretch) { 979 m_overflowScrollDelta.setWidth(m_overflowScrollDelta.width() + deltaX); 980 deltaX = 0; 981 } else 982 m_overflowScrollDelta.setWidth(m_overflowScrollDelta.width() + deltaX); 983 } 984 shouldStretch = true; 985 } 986 } 987 } 988 989 if (deltaX != 0 || deltaY != 0) { 990 if (!(shouldStretch || isVerticallyStretched || isHorizontallyStretched)) { 991 if (deltaY != 0) { 992 deltaY *= scrollWheelMultiplier(); 993 immediateScrollByDeltaY(deltaY); 994 } 995 if (deltaX != 0) { 996 deltaX *= scrollWheelMultiplier(); 997 immediateScrollByDeltaX(deltaX); 998 } 999 } else { 1000 if (!allowsHorizontalStretching()) { 1001 deltaX = 0; 1002 eventCoallescedDeltaX = 0; 1003 } else if ((deltaX != 0) && !isHorizontallyStretched && !pinnedInDirection(deltaX, 0)) { 1004 deltaX *= scrollWheelMultiplier(); 1005 1006 m_scrollableArea->setConstrainsScrollingToContentEdge(false); 1007 immediateScrollByDeltaX(deltaX); 1008 m_scrollableArea->setConstrainsScrollingToContentEdge(true); 1009 1010 deltaX = 0; 1011 } 1012 1013 if (!allowsVerticalStretching()) { 1014 deltaY = 0; 1015 eventCoallescedDeltaY = 0; 1016 } else if ((deltaY != 0) && !isVerticallyStretched && !pinnedInDirection(0, deltaY)) { 1017 deltaY *= scrollWheelMultiplier(); 1018 1019 m_scrollableArea->setConstrainsScrollingToContentEdge(false); 1020 immediateScrollByDeltaY(deltaY); 1021 m_scrollableArea->setConstrainsScrollingToContentEdge(true); 1022 1023 deltaY = 0; 1024 } 1025 1026 IntSize stretchAmount = m_scrollableArea->overhangAmount(); 1027 1028 if (m_momentumScrollInProgress) { 1029 if ((pinnedInDirection(eventCoallescedDeltaX, eventCoallescedDeltaY) || (fabsf(eventCoallescedDeltaX) + fabsf(eventCoallescedDeltaY) <= 0)) && m_lastMomemtumScrollTimestamp) { 1030 m_ignoreMomentumScrolls = true; 1031 m_momentumScrollInProgress = false; 1032 snapRubberBand(); 1033 } 1034 } 1035 1036 m_stretchScrollForce.setWidth(m_stretchScrollForce.width() + deltaX); 1037 m_stretchScrollForce.setHeight(m_stretchScrollForce.height() + deltaY); 1038 1039 FloatSize dampedDelta(ceilf(elasticDeltaForReboundDelta(m_stretchScrollForce.width())), ceilf(elasticDeltaForReboundDelta(m_stretchScrollForce.height()))); 1040 FloatPoint origOrigin = (m_scrollableArea->visibleContentRect().location() + m_scrollableArea->scrollOrigin()) - stretchAmount; 1041 FloatPoint newOrigin = origOrigin + dampedDelta; 1042 1043 if (origOrigin != newOrigin) { 1044 m_scrollableArea->setConstrainsScrollingToContentEdge(false); 1045 immediateScrollToPoint(newOrigin); 1046 m_scrollableArea->setConstrainsScrollingToContentEdge(true); 1047 } 1048 } 1049 } 1050 1051 if (m_momentumScrollInProgress && phase == PlatformWheelEventPhaseEnded) { 1052 m_momentumScrollInProgress = false; 1053 m_ignoreMomentumScrolls = false; 1054 m_lastMomemtumScrollTimestamp = 0; 1055 } 1056 } 1057 1058 void ScrollAnimatorMac::beginScrollGesture() 1059 { 1060 didBeginScrollGesture(); 1061 1062 m_haveScrolledSincePageLoad = true; 1063 m_inScrollGesture = true; 1064 m_momentumScrollInProgress = false; 1065 m_ignoreMomentumScrolls = false; 1066 m_lastMomemtumScrollTimestamp = 0; 1067 m_momentumVelocity = FloatSize(); 1068 1069 IntSize stretchAmount = m_scrollableArea->overhangAmount(); 1070 m_stretchScrollForce.setWidth(reboundDeltaForElasticDelta(stretchAmount.width())); 1071 m_stretchScrollForce.setHeight(reboundDeltaForElasticDelta(stretchAmount.height())); 1072 1073 m_overflowScrollDelta = FloatSize(); 1074 1075 if (m_snapRubberBandTimer.isActive()) 1076 m_snapRubberBandTimer.stop(); 1077 } 1078 1079 void ScrollAnimatorMac::endScrollGesture() 1080 { 1081 didEndScrollGesture(); 1082 1083 snapRubberBand(); 1084 } 1085 1086 void ScrollAnimatorMac::snapRubberBand() 1087 { 1088 CFTimeInterval timeDelta = [[NSProcessInfo processInfo] systemUptime] - m_lastMomemtumScrollTimestamp; 1089 if (m_lastMomemtumScrollTimestamp && timeDelta >= scrollVelocityZeroingTimeout) 1090 m_momentumVelocity = FloatSize(); 1091 1092 m_inScrollGesture = false; 1093 1094 if (m_snapRubberBandTimer.isActive()) 1095 return; 1096 1097 m_startTime = [NSDate timeIntervalSinceReferenceDate]; 1098 m_startStretch = FloatSize(); 1099 m_origOrigin = FloatPoint(); 1100 m_origVelocity = FloatSize(); 1101 1102 m_snapRubberBandTimer.startRepeating(1.0/60.0); 1103 } 1104 1105 static inline float roundTowardZero(float num) 1106 { 1107 return num > 0 ? ceilf(num - 0.5f) : floorf(num + 0.5f); 1108 } 1109 1110 static inline float roundToDevicePixelTowardZero(float num) 1111 { 1112 float roundedNum = roundf(num); 1113 if (fabs(num - roundedNum) < 0.125) 1114 num = roundedNum; 1115 1116 return roundTowardZero(num); 1117 } 1118 1119 void ScrollAnimatorMac::snapRubberBandTimerFired(Timer<ScrollAnimatorMac>*) 1120 { 1121 if (!m_momentumScrollInProgress || m_ignoreMomentumScrolls) { 1122 CFTimeInterval timeDelta = [NSDate timeIntervalSinceReferenceDate] - m_startTime; 1123 1124 if (m_startStretch == FloatSize()) { 1125 m_startStretch = m_scrollableArea->overhangAmount(); 1126 if (m_startStretch == FloatSize()) { 1127 m_snapRubberBandTimer.stop(); 1128 m_stretchScrollForce = FloatSize(); 1129 m_startTime = 0; 1130 m_startStretch = FloatSize(); 1131 m_origOrigin = FloatPoint(); 1132 m_origVelocity = FloatSize(); 1133 1134 return; 1135 } 1136 1137 m_origOrigin = (m_scrollableArea->visibleContentRect().location() + m_scrollableArea->scrollOrigin()) - m_startStretch; 1138 m_origVelocity = m_momentumVelocity; 1139 1140 // Just like normal scrolling, prefer vertical rubberbanding 1141 if (fabsf(m_origVelocity.height()) >= fabsf(m_origVelocity.width())) 1142 m_origVelocity.setWidth(0); 1143 1144 // Don't rubber-band horizontally if it's not possible to scroll horizontally 1145 Scrollbar* hScroller = m_scrollableArea->horizontalScrollbar(); 1146 if (!hScroller || !hScroller->enabled()) 1147 m_origVelocity.setWidth(0); 1148 1149 // Don't rubber-band vertically if it's not possible to scroll horizontally 1150 Scrollbar* vScroller = m_scrollableArea->verticalScrollbar(); 1151 if (!vScroller || !vScroller->enabled()) 1152 m_origVelocity.setHeight(0); 1153 } 1154 1155 FloatPoint delta(roundToDevicePixelTowardZero(elasticDeltaForTimeDelta(m_startStretch.width(), -m_origVelocity.width(), (float)timeDelta)), 1156 roundToDevicePixelTowardZero(elasticDeltaForTimeDelta(m_startStretch.height(), -m_origVelocity.height(), (float)timeDelta))); 1157 1158 if (fabs(delta.x()) >= 1 || fabs(delta.y()) >= 1) { 1159 FloatPoint newOrigin = m_origOrigin + delta; 1160 1161 m_scrollableArea->setConstrainsScrollingToContentEdge(false); 1162 immediateScrollToPoint(newOrigin); 1163 m_scrollableArea->setConstrainsScrollingToContentEdge(true); 1164 1165 FloatSize newStretch = m_scrollableArea->overhangAmount(); 1166 1167 m_stretchScrollForce.setWidth(reboundDeltaForElasticDelta(newStretch.width())); 1168 m_stretchScrollForce.setHeight(reboundDeltaForElasticDelta(newStretch.height())); 1169 } else { 1170 immediateScrollToPoint(m_origOrigin); 1171 1172 m_scrollableArea->didCompleteRubberBand(roundedIntSize(m_startStretch)); 1173 1174 m_snapRubberBandTimer.stop(); 1175 m_stretchScrollForce = FloatSize(); 1176 1177 m_startTime = 0; 1178 m_startStretch = FloatSize(); 1179 m_origOrigin = FloatPoint(); 1180 m_origVelocity = FloatSize(); 1181 } 1182 } else { 1183 m_startTime = [NSDate timeIntervalSinceReferenceDate]; 1184 m_startStretch = FloatSize(); 1185 } 1186 } 1187 #endif 1188 1189 #if USE(WK_SCROLLBAR_PAINTER) 1190 void ScrollAnimatorMac::startScrollbarPaintTimer() 1191 { 1192 m_initialScrollbarPaintTimer.startOneShot(0.1); 1193 } 1194 1195 bool ScrollAnimatorMac::scrollbarPaintTimerIsActive() const 1196 { 1197 return m_initialScrollbarPaintTimer.isActive(); 1198 } 1199 1200 void ScrollAnimatorMac::stopScrollbarPaintTimer() 1201 { 1202 m_initialScrollbarPaintTimer.stop(); 1203 } 1204 1205 void ScrollAnimatorMac::initialScrollbarPaintTimerFired(Timer<ScrollAnimatorMac>*) 1206 { 1207 wkScrollbarPainterForceFlashScrollers(m_scrollbarPainterController.get()); 1208 } 1209 #endif 1210 1211 } // namespace WebCore 1212 1213 #endif // ENABLE(SMOOTH_SCROLLING) 1214