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 "PlatformGestureEvent.h" 34#include "PlatformWheelEvent.h" 35#include "ScrollView.h" 36#include "ScrollableArea.h" 37#include "ScrollbarTheme.h" 38#include "ScrollbarThemeMac.h" 39#include "WebCoreSystemInterface.h" 40#include <wtf/PassOwnPtr.h> 41#include <wtf/UnusedParam.h> 42 43using namespace WebCore; 44using 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 60static 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 if (part == WebCore::ThumbPart && !wkScrollbarPainterIsHorizontal(scrollerPainter)) { 423 if (newAlpha == 1) { 424 IntRect thumbRect = IntRect(wkScrollbarPainterKnobRect(scrollerPainter)); 425 _animator->setVisibleScrollerThumbRect(thumbRect); 426 } else 427 _animator->setVisibleScrollerThumbRect(IntRect()); 428 } 429 430 [NSAnimationContext beginGrouping]; 431 [[NSAnimationContext currentContext] setDuration:duration]; 432 scrollbarPartAnimation.adoptNS([[ScrollbarPartAnimation alloc] initWithScrollbarPainter:scrollerPainter 433 part:part 434 scrollAnimator:_animator 435 animateAlphaTo:newAlpha 436 duration:duration]); 437 [scrollbarPartAnimation.get() setAnimationBlockingMode:NSAnimationNonblocking]; 438 [scrollbarPartAnimation.get() startAnimation]; 439 [NSAnimationContext endGrouping]; 440} 441 442- (void)scrollerImp:(id)scrollerImp animateKnobAlphaTo:(CGFloat)newKnobAlpha duration:(NSTimeInterval)duration 443{ 444 if (!_animator) 445 return; 446 447 WKScrollbarPainterRef scrollerPainter = (WKScrollbarPainterRef)scrollerImp; 448 if (wkScrollbarPainterIsHorizontal(scrollerPainter)) 449 [self setUpAnimation:_horizontalKnobAnimation scrollerPainter:scrollerPainter part:WebCore::ThumbPart animateAlphaTo:newKnobAlpha duration:duration]; 450 else 451 [self setUpAnimation:_verticalKnobAnimation scrollerPainter:scrollerPainter part:WebCore::ThumbPart animateAlphaTo:newKnobAlpha duration:duration]; 452} 453 454- (void)scrollerImp:(id)scrollerImp animateTrackAlphaTo:(CGFloat)newTrackAlpha duration:(NSTimeInterval)duration 455{ 456 if (!_animator) 457 return; 458 459 WKScrollbarPainterRef scrollerPainter = (WKScrollbarPainterRef)scrollerImp; 460 if (wkScrollbarPainterIsHorizontal(scrollerPainter)) 461 [self setUpAnimation:_horizontalTrackAnimation scrollerPainter:scrollerPainter part:WebCore::BackTrackPart animateAlphaTo:newTrackAlpha duration:duration]; 462 else 463 [self setUpAnimation:_verticalTrackAnimation scrollerPainter:scrollerPainter part:WebCore::BackTrackPart animateAlphaTo:newTrackAlpha duration:duration]; 464} 465 466- (void)scrollerImp:(id)scrollerImp overlayScrollerStateChangedTo:(NSUInteger)newOverlayScrollerState 467{ 468 UNUSED_PARAM(scrollerImp); 469 UNUSED_PARAM(newOverlayScrollerState); 470} 471 472- (void)scrollAnimatorDestroyed 473{ 474 _animator = 0; 475 [_verticalKnobAnimation.get() scrollAnimatorDestroyed]; 476 [_horizontalKnobAnimation.get() scrollAnimatorDestroyed]; 477 [_verticalTrackAnimation.get() scrollAnimatorDestroyed]; 478 [_horizontalTrackAnimation.get() scrollAnimatorDestroyed]; 479} 480 481@end 482 483#endif // USE(WK_SCROLLBAR_PAINTER) 484 485namespace WebCore { 486 487PassOwnPtr<ScrollAnimator> ScrollAnimator::create(ScrollableArea* scrollableArea) 488{ 489 return adoptPtr(new ScrollAnimatorMac(scrollableArea)); 490} 491 492ScrollAnimatorMac::ScrollAnimatorMac(ScrollableArea* scrollableArea) 493 : ScrollAnimator(scrollableArea) 494#if USE(WK_SCROLLBAR_PAINTER) 495 , m_initialScrollbarPaintTimer(this, &ScrollAnimatorMac::initialScrollbarPaintTimerFired) 496#endif 497#if ENABLE(RUBBER_BANDING) 498 , m_inScrollGesture(false) 499 , m_momentumScrollInProgress(false) 500 , m_ignoreMomentumScrolls(false) 501 , m_lastMomemtumScrollTimestamp(0) 502 , m_startTime(0) 503 , m_snapRubberBandTimer(this, &ScrollAnimatorMac::snapRubberBandTimerFired) 504#endif 505 , m_drawingIntoLayer(false) 506 , m_haveScrolledSincePageLoad(false) 507{ 508 m_scrollAnimationHelperDelegate.adoptNS([[ScrollAnimationHelperDelegate alloc] initWithScrollAnimator:this]); 509 m_scrollAnimationHelper.adoptNS([[NSClassFromString(@"NSScrollAnimationHelper") alloc] initWithDelegate:m_scrollAnimationHelperDelegate.get()]); 510 511#if USE(WK_SCROLLBAR_PAINTER) 512 m_scrollbarPainterControllerDelegate.adoptNS([[ScrollbarPainterControllerDelegate alloc] initWithScrollAnimator:this]); 513 m_scrollbarPainterController = wkMakeScrollbarPainterController(m_scrollbarPainterControllerDelegate.get()); 514 m_scrollbarPainterDelegate.adoptNS([[ScrollbarPainterDelegate alloc] initWithScrollAnimator:this]); 515#endif 516} 517 518ScrollAnimatorMac::~ScrollAnimatorMac() 519{ 520#if USE(WK_SCROLLBAR_PAINTER) 521 [m_scrollbarPainterControllerDelegate.get() scrollAnimatorDestroyed]; 522 [(id)m_scrollbarPainterController.get() setDelegate:nil]; 523 [m_scrollbarPainterDelegate.get() scrollAnimatorDestroyed]; 524 [m_scrollAnimationHelperDelegate.get() scrollAnimatorDestroyed]; 525#endif 526} 527 528bool ScrollAnimatorMac::scroll(ScrollbarOrientation orientation, ScrollGranularity granularity, float step, float multiplier) 529{ 530 m_haveScrolledSincePageLoad = true; 531 532 if (![[NSUserDefaults standardUserDefaults] boolForKey:@"AppleScrollAnimationEnabled"]) 533 return ScrollAnimator::scroll(orientation, granularity, step, multiplier); 534 535 if (granularity == ScrollByPixel) 536 return ScrollAnimator::scroll(orientation, granularity, step, multiplier); 537 538 float currentPos = orientation == HorizontalScrollbar ? m_currentPosX : m_currentPosY; 539 float newPos = std::max<float>(std::min<float>(currentPos + (step * multiplier), static_cast<float>(m_scrollableArea->scrollSize(orientation))), 0); 540 if (currentPos == newPos) 541 return false; 542 543 NSPoint newPoint; 544 if ([m_scrollAnimationHelper.get() _isAnimating]) { 545 NSPoint targetOrigin = [m_scrollAnimationHelper.get() targetOrigin]; 546 newPoint = orientation == HorizontalScrollbar ? NSMakePoint(newPos, targetOrigin.y) : NSMakePoint(targetOrigin.x, newPos); 547 } else 548 newPoint = orientation == HorizontalScrollbar ? NSMakePoint(newPos, m_currentPosY) : NSMakePoint(m_currentPosX, newPos); 549 550 [m_scrollAnimationHelper.get() scrollToPoint:newPoint]; 551 return true; 552} 553 554void ScrollAnimatorMac::scrollToOffsetWithoutAnimation(const FloatPoint& offset) 555{ 556 [m_scrollAnimationHelper.get() _stopRun]; 557 immediateScrollToPoint(offset); 558} 559 560float ScrollAnimatorMac::adjustScrollXPositionIfNecessary(float position) const 561{ 562 if (!m_scrollableArea->constrainsScrollingToContentEdge()) 563 return position; 564 565 return max<float>(min<float>(position, m_scrollableArea->contentsSize().width() - m_scrollableArea->visibleWidth()), 0); 566} 567 568float ScrollAnimatorMac::adjustScrollYPositionIfNecessary(float position) const 569{ 570 if (!m_scrollableArea->constrainsScrollingToContentEdge()) 571 return position; 572 573 return max<float>(min<float>(position, m_scrollableArea->contentsSize().height() - m_scrollableArea->visibleHeight()), 0); 574} 575 576FloatPoint ScrollAnimatorMac::adjustScrollPositionIfNecessary(const FloatPoint& position) const 577{ 578 if (!m_scrollableArea->constrainsScrollingToContentEdge()) 579 return position; 580 581 float newX = max<float>(min<float>(position.x(), m_scrollableArea->contentsSize().width() - m_scrollableArea->visibleWidth()), 0); 582 float newY = max<float>(min<float>(position.y(), m_scrollableArea->contentsSize().height() - m_scrollableArea->visibleHeight()), 0); 583 584 return FloatPoint(newX, newY); 585} 586 587void ScrollAnimatorMac::immediateScrollToPoint(const FloatPoint& newPosition) 588{ 589 FloatPoint adjustedPosition = adjustScrollPositionIfNecessary(newPosition); 590 591 if (adjustedPosition.x() == m_currentPosX && adjustedPosition.y() == m_currentPosY) 592 return; 593 594 m_currentPosX = adjustedPosition.x(); 595 m_currentPosY = adjustedPosition.y(); 596 notityPositionChanged(); 597} 598 599void ScrollAnimatorMac::immediateScrollByDeltaX(float deltaX) 600{ 601 float newPosX = adjustScrollXPositionIfNecessary(m_currentPosX + deltaX); 602 603 if (newPosX == m_currentPosX) 604 return; 605 606 m_currentPosX = newPosX; 607 notityPositionChanged(); 608} 609 610void ScrollAnimatorMac::immediateScrollByDeltaY(float deltaY) 611{ 612 float newPosY = adjustScrollYPositionIfNecessary(m_currentPosY + deltaY); 613 614 if (newPosY == m_currentPosY) 615 return; 616 617 m_currentPosY = newPosY; 618 notityPositionChanged(); 619} 620 621void ScrollAnimatorMac::notityPositionChanged() 622{ 623#if USE(WK_SCROLLBAR_PAINTER) 624 wkContentAreaScrolled(m_scrollbarPainterController.get()); 625#endif 626 ScrollAnimator::notityPositionChanged(); 627} 628 629void ScrollAnimatorMac::contentAreaWillPaint() const 630{ 631#if USE(WK_SCROLLBAR_PAINTER) 632 wkContentAreaWillPaint(m_scrollbarPainterController.get()); 633#endif 634} 635 636void ScrollAnimatorMac::mouseEnteredContentArea() const 637{ 638#if USE(WK_SCROLLBAR_PAINTER) 639 wkMouseEnteredContentArea(m_scrollbarPainterController.get()); 640#endif 641} 642 643void ScrollAnimatorMac::mouseExitedContentArea() const 644{ 645#if USE(WK_SCROLLBAR_PAINTER) 646 wkMouseExitedContentArea(m_scrollbarPainterController.get()); 647#endif 648} 649 650void ScrollAnimatorMac::mouseMovedInContentArea() const 651{ 652#if USE(WK_SCROLLBAR_PAINTER) 653 wkMouseMovedInContentArea(m_scrollbarPainterController.get()); 654#endif 655} 656 657void ScrollAnimatorMac::willStartLiveResize() 658{ 659#if USE(WK_SCROLLBAR_PAINTER) 660 wkWillStartLiveResize(m_scrollbarPainterController.get()); 661#endif 662} 663 664void ScrollAnimatorMac::contentsResized() const 665{ 666#if USE(WK_SCROLLBAR_PAINTER) 667 wkContentAreaResized(m_scrollbarPainterController.get()); 668#endif 669} 670 671void ScrollAnimatorMac::willEndLiveResize() 672{ 673#if USE(WK_SCROLLBAR_PAINTER) 674 wkWillEndLiveResize(m_scrollbarPainterController.get()); 675#endif 676} 677 678void ScrollAnimatorMac::contentAreaDidShow() const 679{ 680#if USE(WK_SCROLLBAR_PAINTER) 681 wkContentAreaDidShow(m_scrollbarPainterController.get()); 682#endif 683} 684 685void ScrollAnimatorMac::contentAreaDidHide() const 686{ 687#if USE(WK_SCROLLBAR_PAINTER) 688 wkContentAreaDidHide(m_scrollbarPainterController.get()); 689#endif 690} 691 692void ScrollAnimatorMac::didBeginScrollGesture() const 693{ 694#if USE(WK_SCROLLBAR_PAINTER) 695 wkDidBeginScrollGesture(m_scrollbarPainterController.get()); 696#endif 697} 698 699void ScrollAnimatorMac::didEndScrollGesture() const 700{ 701#if USE(WK_SCROLLBAR_PAINTER) 702 wkDidEndScrollGesture(m_scrollbarPainterController.get()); 703#endif 704} 705 706void ScrollAnimatorMac::didAddVerticalScrollbar(Scrollbar* scrollbar) 707{ 708#if USE(WK_SCROLLBAR_PAINTER) 709 WKScrollbarPainterRef painter = static_cast<WebCore::ScrollbarThemeMac*>(WebCore::ScrollbarTheme::nativeTheme())->painterForScrollbar(scrollbar); 710 wkScrollbarPainterSetDelegate(painter, m_scrollbarPainterDelegate.get()); 711 wkSetPainterForPainterController(m_scrollbarPainterController.get(), painter, false); 712 if (scrollableArea()->inLiveResize()) 713 wkSetScrollbarPainterKnobAlpha(painter, 1); 714#else 715 UNUSED_PARAM(scrollbar); 716#endif 717} 718 719void ScrollAnimatorMac::willRemoveVerticalScrollbar(Scrollbar* scrollbar) 720{ 721#if USE(WK_SCROLLBAR_PAINTER) 722 WKScrollbarPainterRef painter = static_cast<WebCore::ScrollbarThemeMac*>(WebCore::ScrollbarTheme::nativeTheme())->painterForScrollbar(scrollbar); 723 wkScrollbarPainterSetDelegate(painter, nil); 724 wkSetPainterForPainterController(m_scrollbarPainterController.get(), nil, false); 725#else 726 UNUSED_PARAM(scrollbar); 727#endif 728} 729 730void ScrollAnimatorMac::didAddHorizontalScrollbar(Scrollbar* scrollbar) 731{ 732#if USE(WK_SCROLLBAR_PAINTER) 733 WKScrollbarPainterRef painter = static_cast<WebCore::ScrollbarThemeMac*>(WebCore::ScrollbarTheme::nativeTheme())->painterForScrollbar(scrollbar); 734 wkScrollbarPainterSetDelegate(painter, m_scrollbarPainterDelegate.get()); 735 wkSetPainterForPainterController(m_scrollbarPainterController.get(), painter, true); 736 if (scrollableArea()->inLiveResize()) 737 wkSetScrollbarPainterKnobAlpha(painter, 1); 738#else 739 UNUSED_PARAM(scrollbar); 740#endif 741} 742 743void ScrollAnimatorMac::willRemoveHorizontalScrollbar(Scrollbar* scrollbar) 744{ 745#if USE(WK_SCROLLBAR_PAINTER) 746 WKScrollbarPainterRef painter = static_cast<WebCore::ScrollbarThemeMac*>(WebCore::ScrollbarTheme::nativeTheme())->painterForScrollbar(scrollbar); 747 wkScrollbarPainterSetDelegate(painter, nil); 748 wkSetPainterForPainterController(m_scrollbarPainterController.get(), nil, true); 749#else 750 UNUSED_PARAM(scrollbar); 751#endif 752} 753 754void ScrollAnimatorMac::cancelAnimations() 755{ 756 m_haveScrolledSincePageLoad = false; 757 758#if USE(WK_SCROLLBAR_PAINTER) 759 if (scrollbarPaintTimerIsActive()) 760 stopScrollbarPaintTimer(); 761 [m_scrollbarPainterDelegate.get() cancelAnimations]; 762#endif 763} 764 765#if ENABLE(RUBBER_BANDING) 766 767static const float scrollVelocityZeroingTimeout = 0.10f; 768static const float rubberbandStiffness = 20; 769static const float rubberbandDirectionLockStretchRatio = 1; 770static const float rubberbandMinimumRequiredDeltaBeforeStretch = 10; 771static const float rubberbandAmplitude = 0.31f; 772static const float rubberbandPeriod = 1.6f; 773 774static float elasticDeltaForTimeDelta(float initialPosition, float initialVelocity, float elapsedTime) 775{ 776 float amplitude = rubberbandAmplitude; 777 float period = rubberbandPeriod; 778 float criticalDampeningFactor = expf((-elapsedTime * rubberbandStiffness) / period); 779 780 return (initialPosition + (-initialVelocity * elapsedTime * amplitude)) * criticalDampeningFactor; 781} 782 783static float elasticDeltaForReboundDelta(float delta) 784{ 785 float stiffness = std::max(rubberbandStiffness, 1.0f); 786 return delta / stiffness; 787} 788 789static float reboundDeltaForElasticDelta(float delta) 790{ 791 return delta * rubberbandStiffness; 792} 793 794static float scrollWheelMultiplier() 795{ 796 static float multiplier = -1; 797 if (multiplier < 0) { 798 multiplier = [[NSUserDefaults standardUserDefaults] floatForKey:@"NSScrollWheelMultiplier"]; 799 if (multiplier <= 0) 800 multiplier = 1; 801 } 802 return multiplier; 803} 804 805void ScrollAnimatorMac::handleWheelEvent(PlatformWheelEvent& wheelEvent) 806{ 807 m_haveScrolledSincePageLoad = true; 808 809 if (!wheelEvent.hasPreciseScrollingDeltas()) { 810 ScrollAnimator::handleWheelEvent(wheelEvent); 811 return; 812 } 813 814 // FIXME: This is somewhat roundabout hack to allow forwarding wheel events 815 // up to the parent scrollable area. It takes advantage of the fact that 816 // the base class implemenatation of handleWheelEvent will not accept the 817 // wheel event if there is nowhere to scroll. 818 if (fabsf(wheelEvent.deltaY()) >= fabsf(wheelEvent.deltaX())) { 819 if (!allowsVerticalStretching()) { 820 ScrollAnimator::handleWheelEvent(wheelEvent); 821 return; 822 } 823 } else { 824 if (!allowsHorizontalStretching()) { 825 ScrollAnimator::handleWheelEvent(wheelEvent); 826 return; 827 } 828 } 829 830 wheelEvent.accept(); 831 832 bool isMometumScrollEvent = (wheelEvent.momentumPhase() != PlatformWheelEventPhaseNone); 833 if (m_ignoreMomentumScrolls && (isMometumScrollEvent || m_snapRubberBandTimer.isActive())) { 834 if (wheelEvent.momentumPhase() == PlatformWheelEventPhaseEnded) 835 m_ignoreMomentumScrolls = false; 836 return; 837 } 838 839 smoothScrollWithEvent(wheelEvent); 840} 841 842void ScrollAnimatorMac::handleGestureEvent(const PlatformGestureEvent& gestureEvent) 843{ 844 if (gestureEvent.type() == PlatformGestureEvent::ScrollBeginType) 845 beginScrollGesture(); 846 else 847 endScrollGesture(); 848} 849 850bool ScrollAnimatorMac::pinnedInDirection(float deltaX, float deltaY) 851{ 852 FloatSize limitDelta; 853 if (fabsf(deltaY) >= fabsf(deltaX)) { 854 if (deltaY < 0) { 855 // We are trying to scroll up. Make sure we are not pinned to the top 856 limitDelta.setHeight(m_scrollableArea->visibleContentRect().y() + + m_scrollableArea->scrollOrigin().y()); 857 } else { 858 // We are trying to scroll down. Make sure we are not pinned to the bottom 859 limitDelta.setHeight(m_scrollableArea->contentsSize().height() - (m_scrollableArea->visibleContentRect().maxY() + m_scrollableArea->scrollOrigin().y())); 860 } 861 } else if (deltaX != 0) { 862 if (deltaX < 0) { 863 // We are trying to scroll left. Make sure we are not pinned to the left 864 limitDelta.setWidth(m_scrollableArea->visibleContentRect().x() + m_scrollableArea->scrollOrigin().x()); 865 } else { 866 // We are trying to scroll right. Make sure we are not pinned to the right 867 limitDelta.setWidth(m_scrollableArea->contentsSize().width() - (m_scrollableArea->visibleContentRect().maxX() + m_scrollableArea->scrollOrigin().x())); 868 } 869 } 870 871 if ((deltaX != 0 || deltaY != 0) && (limitDelta.width() < 1 && limitDelta.height() < 1)) 872 return true; 873 return false; 874} 875 876bool ScrollAnimatorMac::allowsVerticalStretching() const 877{ 878 switch (m_scrollableArea->verticalScrollElasticity()) { 879 case ScrollElasticityAutomatic: { 880 Scrollbar* hScroller = m_scrollableArea->horizontalScrollbar(); 881 Scrollbar* vScroller = m_scrollableArea->verticalScrollbar(); 882 return (((vScroller && vScroller->enabled()) || (!hScroller || !hScroller->enabled()))); 883 } 884 case ScrollElasticityNone: 885 return false; 886 case ScrollElasticityAllowed: 887 return true; 888 } 889 890 ASSERT_NOT_REACHED(); 891 return false; 892} 893 894bool ScrollAnimatorMac::allowsHorizontalStretching() const 895{ 896 switch (m_scrollableArea->horizontalScrollElasticity()) { 897 case ScrollElasticityAutomatic: { 898 Scrollbar* hScroller = m_scrollableArea->horizontalScrollbar(); 899 Scrollbar* vScroller = m_scrollableArea->verticalScrollbar(); 900 return (((hScroller && hScroller->enabled()) || (!vScroller || !vScroller->enabled()))); 901 } 902 case ScrollElasticityNone: 903 return false; 904 case ScrollElasticityAllowed: 905 return true; 906 } 907 908 ASSERT_NOT_REACHED(); 909 return false; 910} 911 912void ScrollAnimatorMac::smoothScrollWithEvent(PlatformWheelEvent& wheelEvent) 913{ 914 m_haveScrolledSincePageLoad = true; 915 916 float deltaX = m_overflowScrollDelta.width(); 917 float deltaY = m_overflowScrollDelta.height(); 918 919 // Reset overflow values because we may decide to remove delta at various points and put it into overflow. 920 m_overflowScrollDelta = FloatSize(); 921 922 float eventCoallescedDeltaX = -wheelEvent.deltaX(); 923 float eventCoallescedDeltaY = -wheelEvent.deltaY(); 924 925 deltaX += eventCoallescedDeltaX; 926 deltaY += eventCoallescedDeltaY; 927 928 // Slightly prefer scrolling vertically by applying the = case to deltaY 929 if (fabsf(deltaY) >= fabsf(deltaX)) 930 deltaX = 0; 931 else 932 deltaY = 0; 933 934 bool isVerticallyStretched = false; 935 bool isHorizontallyStretched = false; 936 bool shouldStretch = false; 937 938 IntSize stretchAmount = m_scrollableArea->overhangAmount(); 939 940 isHorizontallyStretched = stretchAmount.width(); 941 isVerticallyStretched = stretchAmount.height(); 942 943 PlatformWheelEventPhase phase = wheelEvent.momentumPhase(); 944 945 // If we are starting momentum scrolling then do some setup. 946 if (!m_momentumScrollInProgress && (phase == PlatformWheelEventPhaseBegan || phase == PlatformWheelEventPhaseChanged)) 947 m_momentumScrollInProgress = true; 948 949 CFTimeInterval timeDelta = wheelEvent.timestamp() - m_lastMomemtumScrollTimestamp; 950 if (m_inScrollGesture || m_momentumScrollInProgress) { 951 if (m_lastMomemtumScrollTimestamp && timeDelta > 0 && timeDelta < scrollVelocityZeroingTimeout) { 952 m_momentumVelocity.setWidth(eventCoallescedDeltaX / (float)timeDelta); 953 m_momentumVelocity.setHeight(eventCoallescedDeltaY / (float)timeDelta); 954 m_lastMomemtumScrollTimestamp = wheelEvent.timestamp(); 955 } else { 956 m_lastMomemtumScrollTimestamp = wheelEvent.timestamp(); 957 m_momentumVelocity = FloatSize(); 958 } 959 960 if (isVerticallyStretched) { 961 if (!isHorizontallyStretched && pinnedInDirection(deltaX, 0)) { 962 // Stretching only in the vertical. 963 if (deltaY != 0 && (fabsf(deltaX / deltaY) < rubberbandDirectionLockStretchRatio)) 964 deltaX = 0; 965 else if (fabsf(deltaX) < rubberbandMinimumRequiredDeltaBeforeStretch) { 966 m_overflowScrollDelta.setWidth(m_overflowScrollDelta.width() + deltaX); 967 deltaX = 0; 968 } else 969 m_overflowScrollDelta.setWidth(m_overflowScrollDelta.width() + deltaX); 970 } 971 } else if (isHorizontallyStretched) { 972 // Stretching only in the horizontal. 973 if (pinnedInDirection(0, deltaY)) { 974 if (deltaX != 0 && (fabsf(deltaY / deltaX) < rubberbandDirectionLockStretchRatio)) 975 deltaY = 0; 976 else if (fabsf(deltaY) < rubberbandMinimumRequiredDeltaBeforeStretch) { 977 m_overflowScrollDelta.setHeight(m_overflowScrollDelta.height() + deltaY); 978 deltaY = 0; 979 } else 980 m_overflowScrollDelta.setHeight(m_overflowScrollDelta.height() + deltaY); 981 } 982 } else { 983 // Not stretching at all yet. 984 if (pinnedInDirection(deltaX, deltaY)) { 985 if (fabsf(deltaY) >= fabsf(deltaX)) { 986 if (fabsf(deltaX) < rubberbandMinimumRequiredDeltaBeforeStretch) { 987 m_overflowScrollDelta.setWidth(m_overflowScrollDelta.width() + deltaX); 988 deltaX = 0; 989 } else 990 m_overflowScrollDelta.setWidth(m_overflowScrollDelta.width() + deltaX); 991 } 992 shouldStretch = true; 993 } 994 } 995 } 996 997 if (deltaX != 0 || deltaY != 0) { 998 if (!(shouldStretch || isVerticallyStretched || isHorizontallyStretched)) { 999 if (deltaY != 0) { 1000 deltaY *= scrollWheelMultiplier(); 1001 immediateScrollByDeltaY(deltaY); 1002 } 1003 if (deltaX != 0) { 1004 deltaX *= scrollWheelMultiplier(); 1005 immediateScrollByDeltaX(deltaX); 1006 } 1007 } else { 1008 if (!allowsHorizontalStretching()) { 1009 deltaX = 0; 1010 eventCoallescedDeltaX = 0; 1011 } else if ((deltaX != 0) && !isHorizontallyStretched && !pinnedInDirection(deltaX, 0)) { 1012 deltaX *= scrollWheelMultiplier(); 1013 1014 m_scrollableArea->setConstrainsScrollingToContentEdge(false); 1015 immediateScrollByDeltaX(deltaX); 1016 m_scrollableArea->setConstrainsScrollingToContentEdge(true); 1017 1018 deltaX = 0; 1019 } 1020 1021 if (!allowsVerticalStretching()) { 1022 deltaY = 0; 1023 eventCoallescedDeltaY = 0; 1024 } else if ((deltaY != 0) && !isVerticallyStretched && !pinnedInDirection(0, deltaY)) { 1025 deltaY *= scrollWheelMultiplier(); 1026 1027 m_scrollableArea->setConstrainsScrollingToContentEdge(false); 1028 immediateScrollByDeltaY(deltaY); 1029 m_scrollableArea->setConstrainsScrollingToContentEdge(true); 1030 1031 deltaY = 0; 1032 } 1033 1034 IntSize stretchAmount = m_scrollableArea->overhangAmount(); 1035 1036 if (m_momentumScrollInProgress) { 1037 if ((pinnedInDirection(eventCoallescedDeltaX, eventCoallescedDeltaY) || (fabsf(eventCoallescedDeltaX) + fabsf(eventCoallescedDeltaY) <= 0)) && m_lastMomemtumScrollTimestamp) { 1038 m_ignoreMomentumScrolls = true; 1039 m_momentumScrollInProgress = false; 1040 snapRubberBand(); 1041 } 1042 } 1043 1044 m_stretchScrollForce.setWidth(m_stretchScrollForce.width() + deltaX); 1045 m_stretchScrollForce.setHeight(m_stretchScrollForce.height() + deltaY); 1046 1047 FloatSize dampedDelta(ceilf(elasticDeltaForReboundDelta(m_stretchScrollForce.width())), ceilf(elasticDeltaForReboundDelta(m_stretchScrollForce.height()))); 1048 FloatPoint origOrigin = (m_scrollableArea->visibleContentRect().location() + m_scrollableArea->scrollOrigin()) - stretchAmount; 1049 FloatPoint newOrigin = origOrigin + dampedDelta; 1050 1051 if (origOrigin != newOrigin) { 1052 m_scrollableArea->setConstrainsScrollingToContentEdge(false); 1053 immediateScrollToPoint(newOrigin); 1054 m_scrollableArea->setConstrainsScrollingToContentEdge(true); 1055 } 1056 } 1057 } 1058 1059 if (m_momentumScrollInProgress && phase == PlatformWheelEventPhaseEnded) { 1060 m_momentumScrollInProgress = false; 1061 m_ignoreMomentumScrolls = false; 1062 m_lastMomemtumScrollTimestamp = 0; 1063 } 1064} 1065 1066void ScrollAnimatorMac::beginScrollGesture() 1067{ 1068 didBeginScrollGesture(); 1069 1070 m_haveScrolledSincePageLoad = true; 1071 m_inScrollGesture = true; 1072 m_momentumScrollInProgress = false; 1073 m_ignoreMomentumScrolls = false; 1074 m_lastMomemtumScrollTimestamp = 0; 1075 m_momentumVelocity = FloatSize(); 1076 1077 IntSize stretchAmount = m_scrollableArea->overhangAmount(); 1078 m_stretchScrollForce.setWidth(reboundDeltaForElasticDelta(stretchAmount.width())); 1079 m_stretchScrollForce.setHeight(reboundDeltaForElasticDelta(stretchAmount.height())); 1080 1081 m_overflowScrollDelta = FloatSize(); 1082 1083 if (m_snapRubberBandTimer.isActive()) 1084 m_snapRubberBandTimer.stop(); 1085} 1086 1087void ScrollAnimatorMac::endScrollGesture() 1088{ 1089 didEndScrollGesture(); 1090 1091 snapRubberBand(); 1092} 1093 1094void ScrollAnimatorMac::snapRubberBand() 1095{ 1096 CFTimeInterval timeDelta = [[NSProcessInfo processInfo] systemUptime] - m_lastMomemtumScrollTimestamp; 1097 if (m_lastMomemtumScrollTimestamp && timeDelta >= scrollVelocityZeroingTimeout) 1098 m_momentumVelocity = FloatSize(); 1099 1100 m_inScrollGesture = false; 1101 1102 if (m_snapRubberBandTimer.isActive()) 1103 return; 1104 1105 m_startTime = [NSDate timeIntervalSinceReferenceDate]; 1106 m_startStretch = FloatSize(); 1107 m_origOrigin = FloatPoint(); 1108 m_origVelocity = FloatSize(); 1109 1110 m_snapRubberBandTimer.startRepeating(1.0/60.0); 1111} 1112 1113static inline float roundTowardZero(float num) 1114{ 1115 return num > 0 ? ceilf(num - 0.5f) : floorf(num + 0.5f); 1116} 1117 1118static inline float roundToDevicePixelTowardZero(float num) 1119{ 1120 float roundedNum = roundf(num); 1121 if (fabs(num - roundedNum) < 0.125) 1122 num = roundedNum; 1123 1124 return roundTowardZero(num); 1125} 1126 1127void ScrollAnimatorMac::snapRubberBandTimerFired(Timer<ScrollAnimatorMac>*) 1128{ 1129 if (!m_momentumScrollInProgress || m_ignoreMomentumScrolls) { 1130 CFTimeInterval timeDelta = [NSDate timeIntervalSinceReferenceDate] - m_startTime; 1131 1132 if (m_startStretch == FloatSize()) { 1133 m_startStretch = m_scrollableArea->overhangAmount(); 1134 if (m_startStretch == FloatSize()) { 1135 m_snapRubberBandTimer.stop(); 1136 m_stretchScrollForce = FloatSize(); 1137 m_startTime = 0; 1138 m_startStretch = FloatSize(); 1139 m_origOrigin = FloatPoint(); 1140 m_origVelocity = FloatSize(); 1141 1142 return; 1143 } 1144 1145 m_origOrigin = (m_scrollableArea->visibleContentRect().location() + m_scrollableArea->scrollOrigin()) - m_startStretch; 1146 m_origVelocity = m_momentumVelocity; 1147 1148 // Just like normal scrolling, prefer vertical rubberbanding 1149 if (fabsf(m_origVelocity.height()) >= fabsf(m_origVelocity.width())) 1150 m_origVelocity.setWidth(0); 1151 1152 // Don't rubber-band horizontally if it's not possible to scroll horizontally 1153 Scrollbar* hScroller = m_scrollableArea->horizontalScrollbar(); 1154 if (!hScroller || !hScroller->enabled()) 1155 m_origVelocity.setWidth(0); 1156 1157 // Don't rubber-band vertically if it's not possible to scroll horizontally 1158 Scrollbar* vScroller = m_scrollableArea->verticalScrollbar(); 1159 if (!vScroller || !vScroller->enabled()) 1160 m_origVelocity.setHeight(0); 1161 } 1162 1163 FloatPoint delta(roundToDevicePixelTowardZero(elasticDeltaForTimeDelta(m_startStretch.width(), -m_origVelocity.width(), (float)timeDelta)), 1164 roundToDevicePixelTowardZero(elasticDeltaForTimeDelta(m_startStretch.height(), -m_origVelocity.height(), (float)timeDelta))); 1165 1166 if (fabs(delta.x()) >= 1 || fabs(delta.y()) >= 1) { 1167 FloatPoint newOrigin = m_origOrigin + delta; 1168 1169 m_scrollableArea->setConstrainsScrollingToContentEdge(false); 1170 immediateScrollToPoint(newOrigin); 1171 m_scrollableArea->setConstrainsScrollingToContentEdge(true); 1172 1173 FloatSize newStretch = m_scrollableArea->overhangAmount(); 1174 1175 m_stretchScrollForce.setWidth(reboundDeltaForElasticDelta(newStretch.width())); 1176 m_stretchScrollForce.setHeight(reboundDeltaForElasticDelta(newStretch.height())); 1177 } else { 1178 immediateScrollToPoint(m_origOrigin); 1179 1180 m_scrollableArea->didCompleteRubberBand(roundedIntSize(m_startStretch)); 1181 1182 m_snapRubberBandTimer.stop(); 1183 m_stretchScrollForce = FloatSize(); 1184 1185 m_startTime = 0; 1186 m_startStretch = FloatSize(); 1187 m_origOrigin = FloatPoint(); 1188 m_origVelocity = FloatSize(); 1189 } 1190 } else { 1191 m_startTime = [NSDate timeIntervalSinceReferenceDate]; 1192 m_startStretch = FloatSize(); 1193 } 1194} 1195#endif 1196 1197#if USE(WK_SCROLLBAR_PAINTER) 1198void ScrollAnimatorMac::startScrollbarPaintTimer() 1199{ 1200 m_initialScrollbarPaintTimer.startOneShot(0.1); 1201} 1202 1203bool ScrollAnimatorMac::scrollbarPaintTimerIsActive() const 1204{ 1205 return m_initialScrollbarPaintTimer.isActive(); 1206} 1207 1208void ScrollAnimatorMac::stopScrollbarPaintTimer() 1209{ 1210 m_initialScrollbarPaintTimer.stop(); 1211} 1212 1213void ScrollAnimatorMac::initialScrollbarPaintTimerFired(Timer<ScrollAnimatorMac>*) 1214{ 1215 wkScrollbarPainterForceFlashScrollers(m_scrollbarPainterController.get()); 1216} 1217#endif 1218 1219void ScrollAnimatorMac::setVisibleScrollerThumbRect(const IntRect& scrollerThumb) 1220{ 1221 IntRect rectInViewCoordinates = scrollerThumb; 1222 if (Scrollbar* verticalScrollbar = m_scrollableArea->verticalScrollbar()) 1223 rectInViewCoordinates = verticalScrollbar->convertToContainingView(scrollerThumb); 1224 1225 if (rectInViewCoordinates == m_visibleScrollerThumbRect) 1226 return; 1227 1228 m_scrollableArea->setVisibleScrollerThumbRect(rectInViewCoordinates); 1229 m_visibleScrollerThumbRect = rectInViewCoordinates; 1230} 1231 1232} // namespace WebCore 1233 1234#endif // ENABLE(SMOOTH_SCROLLING) 1235