OSDN Git Service

Merge WebKit at r84325: Initial merge by git.
[android-x86/external-webkit.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         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)