2011-04-09 Jon Lee <jonlee@apple.com>
[WebKit-https.git] / Source / WebCore / platform / mac / ScrollAnimatorMac.mm
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         _animator->scrollableArea()->invalidateScrollbarRect(verticalScrollbar, WebCore::IntRect(0, 0, verticalScrollbar->width(), verticalScrollbar->height()));
331     if (WebCore::Scrollbar* horizontalScrollbar = _animator->scrollableArea()->horizontalScrollbar())
332         _animator->scrollableArea()->invalidateScrollbarRect(horizontalScrollbar, 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::didAddVerticalScrollbar(Scrollbar* scrollbar)
685 {
686 #if USE(WK_SCROLLBAR_PAINTER)
687     WKScrollbarPainterRef painter = static_cast<WebCore::ScrollbarThemeMac*>(WebCore::ScrollbarTheme::nativeTheme())->painterForScrollbar(scrollbar);
688     wkScrollbarPainterSetDelegate(painter, m_scrollbarPainterDelegate.get());
689     wkSetPainterForPainterController(m_scrollbarPainterController.get(), painter, false);
690     if (scrollableArea()->inLiveResize())
691         wkSetScrollbarPainterKnobAlpha(painter, 1);
692 #else
693     UNUSED_PARAM(scrollbar);
694 #endif
695 }
696
697 void ScrollAnimatorMac::willRemoveVerticalScrollbar(Scrollbar* scrollbar)
698 {
699 #if USE(WK_SCROLLBAR_PAINTER)
700     WKScrollbarPainterRef painter = static_cast<WebCore::ScrollbarThemeMac*>(WebCore::ScrollbarTheme::nativeTheme())->painterForScrollbar(scrollbar);
701     wkScrollbarPainterSetDelegate(painter, nil);
702     wkSetPainterForPainterController(m_scrollbarPainterController.get(), nil, false);
703 #else
704     UNUSED_PARAM(scrollbar);
705 #endif
706 }
707
708 void ScrollAnimatorMac::didAddHorizontalScrollbar(Scrollbar* scrollbar)
709 {
710 #if USE(WK_SCROLLBAR_PAINTER)
711     WKScrollbarPainterRef painter = static_cast<WebCore::ScrollbarThemeMac*>(WebCore::ScrollbarTheme::nativeTheme())->painterForScrollbar(scrollbar);
712     wkScrollbarPainterSetDelegate(painter, m_scrollbarPainterDelegate.get());
713     wkSetPainterForPainterController(m_scrollbarPainterController.get(), painter, true);
714     if (scrollableArea()->inLiveResize())
715         wkSetScrollbarPainterKnobAlpha(painter, 1);
716 #else
717     UNUSED_PARAM(scrollbar);
718 #endif
719 }
720
721 void ScrollAnimatorMac::willRemoveHorizontalScrollbar(Scrollbar* scrollbar)
722 {
723 #if USE(WK_SCROLLBAR_PAINTER)
724     WKScrollbarPainterRef painter = static_cast<WebCore::ScrollbarThemeMac*>(WebCore::ScrollbarTheme::nativeTheme())->painterForScrollbar(scrollbar);
725     wkScrollbarPainterSetDelegate(painter, nil);
726     wkSetPainterForPainterController(m_scrollbarPainterController.get(), nil, true);
727 #else
728     UNUSED_PARAM(scrollbar);
729 #endif
730 }
731
732 void ScrollAnimatorMac::cancelAnimations()
733 {
734     m_haveScrolledSincePageLoad = false;
735
736 #if USE(WK_SCROLLBAR_PAINTER)
737     if (scrollbarPaintTimerIsActive())
738         stopScrollbarPaintTimer();
739     [m_scrollbarPainterDelegate.get() cancelAnimations];
740 #endif
741 }
742
743 #if ENABLE(RUBBER_BANDING)
744
745 static const float scrollVelocityZeroingTimeout = 0.10f;
746 static const float rubberbandStiffness = 20;
747 static const float rubberbandDirectionLockStretchRatio = 1;
748 static const float rubberbandMinimumRequiredDeltaBeforeStretch = 10;
749 static const float rubberbandAmplitude = 0.31f;
750 static const float rubberbandPeriod = 1.6f;
751
752 static float elasticDeltaForTimeDelta(float initialPosition, float initialVelocity, float elapsedTime)
753 {
754     float amplitude = rubberbandAmplitude;
755     float period = rubberbandPeriod;
756     float criticalDampeningFactor = expf((-elapsedTime * rubberbandStiffness) / period);
757              
758     return (initialPosition + (-initialVelocity * elapsedTime * amplitude)) * criticalDampeningFactor;
759 }
760
761 static float elasticDeltaForReboundDelta(float delta)
762 {
763     float stiffness = std::max(rubberbandStiffness, 1.0f);
764     return delta / stiffness;
765 }
766
767 static float reboundDeltaForElasticDelta(float delta)
768 {
769     return delta * rubberbandStiffness;
770 }
771
772 static float scrollWheelMultiplier()
773 {
774     static float multiplier = -1;
775     if (multiplier < 0) {
776         multiplier = [[NSUserDefaults standardUserDefaults] floatForKey:@"NSScrollWheelMultiplier"];
777         if (multiplier <= 0)
778             multiplier = 1;
779     }
780     return multiplier;
781 }
782
783 void ScrollAnimatorMac::handleWheelEvent(PlatformWheelEvent& wheelEvent)
784 {
785     m_haveScrolledSincePageLoad = true;
786
787     if (!wheelEvent.hasPreciseScrollingDeltas()) {
788         ScrollAnimator::handleWheelEvent(wheelEvent);
789         return;
790     }
791
792     wheelEvent.accept();
793
794     bool isMometumScrollEvent = (wheelEvent.momentumPhase() != PlatformWheelEventPhaseNone);
795     if (m_ignoreMomentumScrolls && (isMometumScrollEvent || m_snapRubberBandTimer.isActive())) {
796         if (wheelEvent.momentumPhase() == PlatformWheelEventPhaseEnded)
797             m_ignoreMomentumScrolls = false;
798         return;
799     }
800
801     smoothScrollWithEvent(wheelEvent);
802 }
803
804 void ScrollAnimatorMac::handleGestureEvent(const PlatformGestureEvent& gestureEvent)
805 {
806     if (gestureEvent.type() == PlatformGestureEvent::ScrollBeginType)
807         beginScrollGesture();
808     else
809         endScrollGesture();
810 }
811
812 bool ScrollAnimatorMac::pinnedInDirection(float deltaX, float deltaY)
813 {
814     FloatSize limitDelta;
815     if (fabsf(deltaY) >= fabsf(deltaX)) {
816         if (deltaY < 0) {
817             // We are trying to scroll up.  Make sure we are not pinned to the top
818             limitDelta.setHeight(m_scrollableArea->visibleContentRect().y() + + m_scrollableArea->scrollOrigin().y());
819         } else {
820             // We are trying to scroll down.  Make sure we are not pinned to the bottom
821             limitDelta.setHeight(m_scrollableArea->contentsSize().height() - (m_scrollableArea->visibleContentRect().maxY() + m_scrollableArea->scrollOrigin().y()));
822         }
823     } else if (deltaX != 0) {
824         if (deltaX < 0) {
825             // We are trying to scroll left.  Make sure we are not pinned to the left
826             limitDelta.setWidth(m_scrollableArea->visibleContentRect().x() + m_scrollableArea->scrollOrigin().x());
827         } else {
828             // We are trying to scroll right.  Make sure we are not pinned to the right
829             limitDelta.setWidth(m_scrollableArea->contentsSize().width() - (m_scrollableArea->visibleContentRect().maxX() + m_scrollableArea->scrollOrigin().x()));
830         }
831     }
832     
833     if ((deltaX != 0 || deltaY != 0) && (limitDelta.width() < 1 && limitDelta.height() < 1))
834         return true;
835     return false;
836 }
837
838 bool ScrollAnimatorMac::allowsVerticalStretching() const
839 {
840     Scrollbar* hScroller = m_scrollableArea->horizontalScrollbar();
841     Scrollbar* vScroller = m_scrollableArea->verticalScrollbar();
842     if (((vScroller && vScroller->enabled()) || (!hScroller || !hScroller->enabled())))
843         return true;
844
845     return false;
846 }
847
848 bool ScrollAnimatorMac::allowsHorizontalStretching() const
849 {
850     Scrollbar* hScroller = m_scrollableArea->horizontalScrollbar();
851     Scrollbar* vScroller = m_scrollableArea->verticalScrollbar();
852     if (((hScroller && hScroller->enabled()) || (!vScroller || !vScroller->enabled())))
853         return true;
854
855     return false;
856 }
857
858 void ScrollAnimatorMac::smoothScrollWithEvent(PlatformWheelEvent& wheelEvent)
859 {
860     m_haveScrolledSincePageLoad = true;
861
862     float deltaX = m_overflowScrollDelta.width();
863     float deltaY = m_overflowScrollDelta.height();
864
865     // Reset overflow values because we may decide to remove delta at various points and put it into overflow.
866     m_overflowScrollDelta = FloatSize();
867
868     float eventCoallescedDeltaX = -wheelEvent.deltaX();
869     float eventCoallescedDeltaY = -wheelEvent.deltaY();
870
871     deltaX += eventCoallescedDeltaX;
872     deltaY += eventCoallescedDeltaY;
873
874     // Slightly prefer scrolling vertically by applying the = case to deltaY
875     if (fabsf(deltaY) >= fabsf(deltaX))
876         deltaX = 0;
877     else
878         deltaY = 0;
879     
880     bool isVerticallyStretched = false;
881     bool isHorizontallyStretched = false;
882     bool shouldStretch = false;
883     
884     IntSize stretchAmount = m_scrollableArea->overhangAmount();
885
886     isHorizontallyStretched = stretchAmount.width();
887     isVerticallyStretched = stretchAmount.height();
888
889     PlatformWheelEventPhase phase = wheelEvent.momentumPhase();
890
891     // If we are starting momentum scrolling then do some setup.
892     if (!m_momentumScrollInProgress && (phase == PlatformWheelEventPhaseBegan || phase == PlatformWheelEventPhaseChanged))
893         m_momentumScrollInProgress = true;
894
895     CFTimeInterval timeDelta = wheelEvent.timestamp() - m_lastMomemtumScrollTimestamp;
896     if (m_inScrollGesture || m_momentumScrollInProgress) {
897         if (m_lastMomemtumScrollTimestamp && timeDelta > 0 && timeDelta < scrollVelocityZeroingTimeout) {
898             m_momentumVelocity.setWidth(eventCoallescedDeltaX / (float)timeDelta);
899             m_momentumVelocity.setHeight(eventCoallescedDeltaY / (float)timeDelta);
900             m_lastMomemtumScrollTimestamp = wheelEvent.timestamp();
901         } else {
902             m_lastMomemtumScrollTimestamp = wheelEvent.timestamp();
903             m_momentumVelocity = FloatSize();
904         }
905
906         if (isVerticallyStretched) {
907             if (!isHorizontallyStretched && pinnedInDirection(deltaX, 0)) {                
908                 // Stretching only in the vertical.
909                 if (deltaY != 0 && (fabsf(deltaX / deltaY) < rubberbandDirectionLockStretchRatio))
910                     deltaX = 0;
911                 else if (fabsf(deltaX) < rubberbandMinimumRequiredDeltaBeforeStretch) {
912                     m_overflowScrollDelta.setWidth(m_overflowScrollDelta.width() + deltaX);
913                     deltaX = 0;
914                 } else
915                     m_overflowScrollDelta.setWidth(m_overflowScrollDelta.width() + deltaX);
916             }
917         } else if (isHorizontallyStretched) {
918             // Stretching only in the horizontal.
919             if (pinnedInDirection(0, deltaY)) {
920                 if (deltaX != 0 && (fabsf(deltaY / deltaX) < rubberbandDirectionLockStretchRatio))
921                     deltaY = 0;
922                 else if (fabsf(deltaY) < rubberbandMinimumRequiredDeltaBeforeStretch) {
923                     m_overflowScrollDelta.setHeight(m_overflowScrollDelta.height() + deltaY);
924                     deltaY = 0;
925                 } else
926                     m_overflowScrollDelta.setHeight(m_overflowScrollDelta.height() + deltaY);
927             }
928         } else {
929             // Not stretching at all yet.
930             if (pinnedInDirection(deltaX, deltaY)) {
931                 if (fabsf(deltaY) >= fabsf(deltaX)) {
932                     if (fabsf(deltaX) < rubberbandMinimumRequiredDeltaBeforeStretch) {
933                         m_overflowScrollDelta.setWidth(m_overflowScrollDelta.width() + deltaX);
934                         deltaX = 0;
935                     } else
936                         m_overflowScrollDelta.setWidth(m_overflowScrollDelta.width() + deltaX);
937                 }
938                 shouldStretch = true;
939             }
940         }
941     }
942
943     if (deltaX != 0 || deltaY != 0) {
944         if (!(shouldStretch || isVerticallyStretched || isHorizontallyStretched)) {
945             if (deltaY != 0) {
946                 deltaY *= scrollWheelMultiplier();
947                 immediateScrollByDeltaY(deltaY);
948             }
949             if (deltaX != 0) {
950                 deltaX *= scrollWheelMultiplier();
951                 immediateScrollByDeltaX(deltaX);
952             }
953         } else {
954             if (!allowsHorizontalStretching()) {
955                 deltaX = 0;
956                 eventCoallescedDeltaX = 0;
957             } else if ((deltaX != 0) && !isHorizontallyStretched && !pinnedInDirection(deltaX, 0)) {
958                 deltaX *= scrollWheelMultiplier();
959
960                 m_scrollableArea->setConstrainsScrollingToContentEdge(false);
961                 immediateScrollByDeltaX(deltaX);
962                 m_scrollableArea->setConstrainsScrollingToContentEdge(true);
963
964                 deltaX = 0;
965             }
966             
967             if (!allowsVerticalStretching()) {
968                 deltaY = 0;
969                 eventCoallescedDeltaY = 0;
970             } else if ((deltaY != 0) && !isVerticallyStretched && !pinnedInDirection(0, deltaY)) {
971                 deltaY *= scrollWheelMultiplier();
972
973                 m_scrollableArea->setConstrainsScrollingToContentEdge(false);
974                 immediateScrollByDeltaY(deltaY);
975                 m_scrollableArea->setConstrainsScrollingToContentEdge(true);
976
977                 deltaY = 0;
978             }
979             
980             IntSize stretchAmount = m_scrollableArea->overhangAmount();
981         
982             if (m_momentumScrollInProgress) {
983                 if ((pinnedInDirection(eventCoallescedDeltaX, eventCoallescedDeltaY) || (fabsf(eventCoallescedDeltaX) + fabsf(eventCoallescedDeltaY) <= 0)) && m_lastMomemtumScrollTimestamp) {
984                     m_ignoreMomentumScrolls = true;
985                     m_momentumScrollInProgress = false;
986                     snapRubberBand();
987                 }
988             }
989
990             m_stretchScrollForce.setWidth(m_stretchScrollForce.width() + deltaX);
991             m_stretchScrollForce.setHeight(m_stretchScrollForce.height() + deltaY);
992
993             FloatSize dampedDelta(ceilf(elasticDeltaForReboundDelta(m_stretchScrollForce.width())), ceilf(elasticDeltaForReboundDelta(m_stretchScrollForce.height())));
994             FloatPoint origOrigin = (m_scrollableArea->visibleContentRect().location() + m_scrollableArea->scrollOrigin()) - stretchAmount;
995             FloatPoint newOrigin = origOrigin + dampedDelta;
996
997             if (origOrigin != newOrigin) {
998                 m_scrollableArea->setConstrainsScrollingToContentEdge(false);
999                 immediateScrollToPoint(newOrigin);
1000                 m_scrollableArea->setConstrainsScrollingToContentEdge(true);
1001             }
1002         }
1003     }
1004
1005     if (m_momentumScrollInProgress && phase == PlatformWheelEventPhaseEnded) {
1006         m_momentumScrollInProgress = false;
1007         m_ignoreMomentumScrolls = false;
1008         m_lastMomemtumScrollTimestamp = 0;
1009     }
1010 }
1011
1012 void ScrollAnimatorMac::beginScrollGesture()
1013 {
1014     m_haveScrolledSincePageLoad = true;
1015     m_inScrollGesture = true;
1016     m_momentumScrollInProgress = false;
1017     m_ignoreMomentumScrolls = false;
1018     m_lastMomemtumScrollTimestamp = 0;
1019     m_momentumVelocity = FloatSize();
1020
1021     IntSize stretchAmount = m_scrollableArea->overhangAmount();
1022     m_stretchScrollForce.setWidth(reboundDeltaForElasticDelta(stretchAmount.width()));
1023     m_stretchScrollForce.setHeight(reboundDeltaForElasticDelta(stretchAmount.height()));
1024
1025     m_overflowScrollDelta = FloatSize();
1026     
1027     if (m_snapRubberBandTimer.isActive())
1028         m_snapRubberBandTimer.stop();
1029 }
1030
1031 void ScrollAnimatorMac::endScrollGesture()
1032 {
1033     snapRubberBand();
1034 }
1035
1036 void ScrollAnimatorMac::snapRubberBand()
1037 {
1038     CFTimeInterval timeDelta = [[NSProcessInfo processInfo] systemUptime] - m_lastMomemtumScrollTimestamp;
1039     if (m_lastMomemtumScrollTimestamp && timeDelta >= scrollVelocityZeroingTimeout)
1040         m_momentumVelocity = FloatSize();
1041
1042     m_inScrollGesture = false;
1043
1044     if (m_snapRubberBandTimer.isActive())
1045         return;
1046
1047     m_startTime = [NSDate timeIntervalSinceReferenceDate];
1048     m_startStretch = FloatSize();
1049     m_origOrigin = FloatPoint();
1050     m_origVelocity = FloatSize();
1051
1052     m_snapRubberBandTimer.startRepeating(1.0/60.0);
1053 }
1054
1055 static inline float roundTowardZero(float num)
1056 {
1057     return num > 0 ? ceilf(num - 0.5f) : floorf(num + 0.5f);
1058 }
1059
1060 static inline float roundToDevicePixelTowardZero(float num)
1061 {
1062     float roundedNum = roundf(num);
1063     if (fabs(num - roundedNum) < 0.125)
1064         num = roundedNum;
1065
1066     return roundTowardZero(num);
1067 }
1068
1069 void ScrollAnimatorMac::snapRubberBandTimerFired(Timer<ScrollAnimatorMac>*)
1070 {
1071     if (!m_momentumScrollInProgress || m_ignoreMomentumScrolls) {
1072         CFTimeInterval timeDelta = [NSDate timeIntervalSinceReferenceDate] - m_startTime;
1073
1074         if (m_startStretch == FloatSize()) {
1075             m_startStretch = m_scrollableArea->overhangAmount();
1076             if (m_startStretch == FloatSize()) {    
1077                 m_snapRubberBandTimer.stop();
1078                 m_stretchScrollForce = FloatSize();
1079                 m_startTime = 0;
1080                 m_startStretch = FloatSize();
1081                 m_origOrigin = FloatPoint();
1082                 m_origVelocity = FloatSize();
1083
1084                 return;
1085             }
1086
1087             m_origOrigin = (m_scrollableArea->visibleContentRect().location() + m_scrollableArea->scrollOrigin()) - m_startStretch;
1088             m_origVelocity = m_momentumVelocity;
1089
1090             // Just like normal scrolling, prefer vertical rubberbanding
1091             if (fabsf(m_origVelocity.height()) >= fabsf(m_origVelocity.width()))
1092                 m_origVelocity.setWidth(0);
1093             
1094             // Don't rubber-band horizontally if it's not possible to scroll horizontally
1095             Scrollbar* hScroller = m_scrollableArea->horizontalScrollbar();
1096             if (!hScroller || !hScroller->enabled())
1097                 m_origVelocity.setWidth(0);
1098             
1099             // Don't rubber-band vertically if it's not possible to scroll horizontally
1100             Scrollbar* vScroller = m_scrollableArea->verticalScrollbar();
1101             if (!vScroller || !vScroller->enabled())
1102                 m_origVelocity.setHeight(0);
1103         }
1104
1105         FloatPoint delta(roundToDevicePixelTowardZero(elasticDeltaForTimeDelta(m_startStretch.width(), -m_origVelocity.width(), (float)timeDelta)),
1106                          roundToDevicePixelTowardZero(elasticDeltaForTimeDelta(m_startStretch.height(), -m_origVelocity.height(), (float)timeDelta)));
1107
1108         if (fabs(delta.x()) >= 1 || fabs(delta.y()) >= 1) {
1109             FloatPoint newOrigin = m_origOrigin + delta;
1110
1111             m_scrollableArea->setConstrainsScrollingToContentEdge(false);
1112             immediateScrollToPoint(newOrigin);
1113             m_scrollableArea->setConstrainsScrollingToContentEdge(true);
1114
1115             FloatSize newStretch = m_scrollableArea->overhangAmount();
1116             
1117             m_stretchScrollForce.setWidth(reboundDeltaForElasticDelta(newStretch.width()));
1118             m_stretchScrollForce.setHeight(reboundDeltaForElasticDelta(newStretch.height()));
1119         } else {
1120             immediateScrollToPoint(m_origOrigin);
1121
1122             m_scrollableArea->didCompleteRubberBand(roundedIntSize(m_startStretch));
1123
1124             m_snapRubberBandTimer.stop();
1125             m_stretchScrollForce = FloatSize();
1126             
1127             m_startTime = 0;
1128             m_startStretch = FloatSize();
1129             m_origOrigin = FloatPoint();
1130             m_origVelocity = FloatSize();
1131         }
1132     } else {
1133         m_startTime = [NSDate timeIntervalSinceReferenceDate];
1134         m_startStretch = FloatSize();
1135     }
1136 }
1137 #endif
1138
1139 #if USE(WK_SCROLLBAR_PAINTER)
1140 void ScrollAnimatorMac::startScrollbarPaintTimer()
1141 {
1142     m_initialScrollbarPaintTimer.startOneShot(0.1);
1143 }
1144
1145 bool ScrollAnimatorMac::scrollbarPaintTimerIsActive() const
1146 {
1147     return m_initialScrollbarPaintTimer.isActive();
1148 }
1149
1150 void ScrollAnimatorMac::stopScrollbarPaintTimer()
1151 {
1152     m_initialScrollbarPaintTimer.stop();
1153 }
1154
1155 void ScrollAnimatorMac::initialScrollbarPaintTimerFired(Timer<ScrollAnimatorMac>*)
1156 {
1157     wkScrollbarPainterForceFlashScrollers(m_scrollbarPainterController.get());
1158 }
1159 #endif
1160
1161 } // namespace WebCore
1162
1163 #endif // ENABLE(SMOOTH_SCROLLING)