2 * Copyright (C) 2010, 2011, 2015 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
28 #if ENABLE(SMOOTH_SCROLLING)
30 #include "ScrollAnimatorMac.h"
32 #include "BlockExceptions.h"
33 #include "FloatPoint.h"
34 #include "GraphicsLayer.h"
35 #include "NSScrollerImpDetails.h"
36 #include "PlatformWheelEvent.h"
37 #include "ScrollView.h"
38 #include "ScrollableArea.h"
39 #include "ScrollbarTheme.h"
40 #include "ScrollbarThemeMac.h"
41 #include "WebCoreSystemInterface.h"
43 using namespace WebCore;
45 static bool supportsUIStateTransitionProgress()
47 // FIXME: This is temporary until all platforms that support ScrollbarPainter support this part of the API.
48 static bool globalSupportsUIStateTransitionProgress = [NSClassFromString(@"NSScrollerImp") instancesRespondToSelector:@selector(mouseEnteredScroller)];
49 return globalSupportsUIStateTransitionProgress;
52 static bool supportsExpansionTransitionProgress()
54 static bool globalSupportsExpansionTransitionProgress = [NSClassFromString(@"NSScrollerImp") instancesRespondToSelector:@selector(expansionTransitionProgress)];
55 return globalSupportsExpansionTransitionProgress;
58 static bool supportsContentAreaScrolledInDirection()
60 static bool globalSupportsContentAreaScrolledInDirection = [NSClassFromString(@"NSScrollerImpPair") instancesRespondToSelector:@selector(contentAreaScrolledInDirection:)];
61 return globalSupportsContentAreaScrolledInDirection;
64 static ScrollbarThemeMac* macScrollbarTheme()
66 ScrollbarTheme* scrollbarTheme = ScrollbarTheme::theme();
67 return !scrollbarTheme->isMockTheme() ? static_cast<ScrollbarThemeMac*>(scrollbarTheme) : 0;
70 static ScrollbarPainter scrollbarPainterForScrollbar(Scrollbar* scrollbar)
72 if (ScrollbarThemeMac* scrollbarTheme = macScrollbarTheme())
73 return scrollbarTheme->painterForScrollbar(scrollbar);
78 @interface NSObject (ScrollAnimationHelperDetails)
79 - (id)initWithDelegate:(id)delegate;
82 - (NSPoint)targetOrigin;
86 @interface WebScrollAnimationHelperDelegate : NSObject
88 WebCore::ScrollAnimatorMac* _animator;
90 - (id)initWithScrollAnimator:(WebCore::ScrollAnimatorMac*)scrollAnimator;
93 static NSSize abs(NSSize size)
95 NSSize finalSize = size;
96 if (finalSize.width < 0)
97 finalSize.width = -finalSize.width;
98 if (finalSize.height < 0)
99 finalSize.height = -finalSize.height;
103 @implementation WebScrollAnimationHelperDelegate
105 - (id)initWithScrollAnimator:(WebCore::ScrollAnimatorMac*)scrollAnimator
111 _animator = scrollAnimator;
125 WebCore::FloatPoint currentPosition = _animator->currentPosition();
126 return NSMakeRect(currentPosition.x(), currentPosition.y(), 0, 0);
129 - (void)_immediateScrollToPoint:(NSPoint)newPosition
133 _animator->immediateScrollToPointForScrollAnimation(newPosition);
136 - (NSPoint)_pixelAlignProposedScrollPosition:(NSPoint)newOrigin
141 - (NSSize)convertSizeToBase:(NSSize)size
146 - (NSSize)convertSizeFromBase:(NSSize)size
151 - (NSSize)convertSizeToBacking:(NSSize)size
156 - (NSSize)convertSizeFromBacking:(NSSize)size
176 - (void)_recursiveRecomputeToolTips
182 @interface WebScrollbarPainterControllerDelegate : NSObject
184 ScrollableArea* _scrollableArea;
186 - (id)initWithScrollableArea:(ScrollableArea*)scrollableArea;
189 @implementation WebScrollbarPainterControllerDelegate
191 - (id)initWithScrollableArea:(ScrollableArea*)scrollableArea
197 _scrollableArea = scrollableArea;
206 - (NSRect)contentAreaRectForScrollerImpPair:(id)scrollerImpPair
208 UNUSED_PARAM(scrollerImpPair);
209 if (!_scrollableArea)
212 WebCore::IntSize contentsSize = _scrollableArea->contentsSize();
213 return NSMakeRect(0, 0, contentsSize.width(), contentsSize.height());
216 - (BOOL)inLiveResizeForScrollerImpPair:(id)scrollerImpPair
218 UNUSED_PARAM(scrollerImpPair);
219 if (!_scrollableArea)
222 return _scrollableArea->inLiveResize();
225 - (NSPoint)mouseLocationInContentAreaForScrollerImpPair:(id)scrollerImpPair
227 UNUSED_PARAM(scrollerImpPair);
228 if (!_scrollableArea)
231 return _scrollableArea->lastKnownMousePosition();
234 - (NSPoint)scrollerImpPair:(id)scrollerImpPair convertContentPoint:(NSPoint)pointInContentArea toScrollerImp:(id)scrollerImp
236 UNUSED_PARAM(scrollerImpPair);
238 if (!_scrollableArea || !scrollerImp)
241 WebCore::Scrollbar* scrollbar = 0;
242 if ([scrollerImp isHorizontal])
243 scrollbar = _scrollableArea->horizontalScrollbar();
245 scrollbar = _scrollableArea->verticalScrollbar();
247 // It is possible to have a null scrollbar here since it is possible for this delegate
248 // method to be called between the moment when a scrollbar has been set to 0 and the
249 // moment when its destructor has been called. We should probably de-couple some
250 // of the clean-up work in ScrollbarThemeMac::unregisterScrollbar() to avoid this
255 ASSERT(scrollerImp == scrollbarPainterForScrollbar(scrollbar));
257 return scrollbar->convertFromContainingView(WebCore::IntPoint(pointInContentArea));
260 - (void)scrollerImpPair:(id)scrollerImpPair setContentAreaNeedsDisplayInRect:(NSRect)rect
262 UNUSED_PARAM(scrollerImpPair);
265 if (!_scrollableArea)
268 if ([scrollerImpPair overlayScrollerStateIsLocked])
271 _scrollableArea->scrollAnimator().contentAreaWillPaint();
274 - (void)scrollerImpPair:(id)scrollerImpPair updateScrollerStyleForNewRecommendedScrollerStyle:(NSScrollerStyle)newRecommendedScrollerStyle
276 if (!_scrollableArea)
279 [scrollerImpPair setScrollerStyle:newRecommendedScrollerStyle];
281 static_cast<ScrollAnimatorMac&>(_scrollableArea->scrollAnimator()).updateScrollerStyle();
286 enum FeatureToAnimate {
293 @interface WebScrollbarPartAnimation : NSAnimation
295 Scrollbar* _scrollbar;
296 RetainPtr<ScrollbarPainter> _scrollbarPainter;
297 FeatureToAnimate _featureToAnimate;
301 - (id)initWithScrollbar:(Scrollbar*)scrollbar featureToAnimate:(FeatureToAnimate)featureToAnimate animateFrom:(CGFloat)startValue animateTo:(CGFloat)endValue duration:(NSTimeInterval)duration;
304 @implementation WebScrollbarPartAnimation
306 - (id)initWithScrollbar:(Scrollbar*)scrollbar featureToAnimate:(FeatureToAnimate)featureToAnimate animateFrom:(CGFloat)startValue animateTo:(CGFloat)endValue duration:(NSTimeInterval)duration
308 self = [super initWithDuration:duration animationCurve:NSAnimationEaseInOut];
312 _scrollbar = scrollbar;
313 _featureToAnimate = featureToAnimate;
314 _startValue = startValue;
315 _endValue = endValue;
317 [self setAnimationBlockingMode:NSAnimationNonblocking];
322 - (void)startAnimation
326 _scrollbarPainter = scrollbarPainterForScrollbar(_scrollbar);
328 [super startAnimation];
331 - (void)setStartValue:(CGFloat)startValue
333 _startValue = startValue;
336 - (void)setEndValue:(CGFloat)endValue
338 _endValue = endValue;
341 - (void)setCurrentProgress:(NSAnimationProgress)progress
343 [super setCurrentProgress:progress];
347 CGFloat currentValue;
348 if (_startValue > _endValue)
349 currentValue = 1 - progress;
351 currentValue = progress;
353 switch (_featureToAnimate) {
355 [_scrollbarPainter setKnobAlpha:currentValue];
358 [_scrollbarPainter setTrackAlpha:currentValue];
360 case UIStateTransition:
361 [_scrollbarPainter setUiStateTransitionProgress:currentValue];
363 case ExpansionTransition:
364 [_scrollbarPainter setExpansionTransitionProgress:currentValue];
368 if (!_scrollbar->supportsUpdateOnSecondaryThread())
369 _scrollbar->invalidate();
374 BEGIN_BLOCK_OBJC_EXCEPTIONS;
375 [self stopAnimation];
376 END_BLOCK_OBJC_EXCEPTIONS;
382 @interface WebScrollbarPainterDelegate : NSObject<NSAnimationDelegate>
384 WebCore::Scrollbar* _scrollbar;
386 RetainPtr<WebScrollbarPartAnimation> _knobAlphaAnimation;
387 RetainPtr<WebScrollbarPartAnimation> _trackAlphaAnimation;
388 RetainPtr<WebScrollbarPartAnimation> _uiStateTransitionAnimation;
389 RetainPtr<WebScrollbarPartAnimation> _expansionTransitionAnimation;
391 - (id)initWithScrollbar:(WebCore::Scrollbar*)scrollbar;
392 - (void)cancelAnimations;
395 @implementation WebScrollbarPainterDelegate
397 - (id)initWithScrollbar:(WebCore::Scrollbar*)scrollbar
403 _scrollbar = scrollbar;
407 - (void)cancelAnimations
409 BEGIN_BLOCK_OBJC_EXCEPTIONS;
410 [_knobAlphaAnimation stopAnimation];
411 [_trackAlphaAnimation stopAnimation];
412 [_uiStateTransitionAnimation stopAnimation];
413 [_expansionTransitionAnimation stopAnimation];
414 END_BLOCK_OBJC_EXCEPTIONS;
417 - (ScrollAnimatorMac*)scrollAnimator
419 return &static_cast<ScrollAnimatorMac&>(_scrollbar->scrollableArea().scrollAnimator());
422 - (NSRect)convertRectToBacking:(NSRect)aRect
427 - (NSRect)convertRectFromBacking:(NSRect)aRect
437 if (!ScrollbarThemeMac::isCurrentlyDrawingIntoLayer())
440 GraphicsLayer* layer;
441 if (_scrollbar->orientation() == VerticalScrollbar)
442 layer = _scrollbar->scrollableArea().layerForVerticalScrollbar();
444 layer = _scrollbar->scrollableArea().layerForHorizontalScrollbar();
446 static CALayer *dummyLayer = [[CALayer alloc] init];
447 return layer ? layer->platformLayer() : dummyLayer;
450 - (NSPoint)mouseLocationInScrollerForScrollerImp:(id)scrollerImp
455 ASSERT_UNUSED(scrollerImp, scrollerImp == scrollbarPainterForScrollbar(_scrollbar));
457 return _scrollbar->convertFromContainingView(_scrollbar->scrollableArea().lastKnownMousePosition());
460 - (NSRect)convertRectToLayer:(NSRect)rect
465 - (BOOL)shouldUseLayerPerPartForScrollerImp:(id)scrollerImp
467 UNUSED_PARAM(scrollerImp);
472 return _scrollbar->supportsUpdateOnSecondaryThread();
475 - (void)setUpAlphaAnimation:(RetainPtr<WebScrollbarPartAnimation>&)scrollbarPartAnimation scrollerPainter:(ScrollbarPainter)scrollerPainter part:(WebCore::ScrollbarPart)part animateAlphaTo:(CGFloat)newAlpha duration:(NSTimeInterval)duration
477 // If the user has scrolled the page, then the scrollbars must be animated here.
478 // This overrides the early returns.
479 bool mustAnimate = [self scrollAnimator]->haveScrolledSincePageLoad();
481 if ([self scrollAnimator]->scrollbarPaintTimerIsActive() && !mustAnimate)
484 if (_scrollbar->scrollableArea().shouldSuspendScrollAnimations() && !mustAnimate) {
485 [self scrollAnimator]->startScrollbarPaintTimer();
489 // At this point, we are definitely going to animate now, so stop the timer.
490 [self scrollAnimator]->stopScrollbarPaintTimer();
492 // If we are currently animating, stop
493 if (scrollbarPartAnimation) {
494 [scrollbarPartAnimation stopAnimation];
495 scrollbarPartAnimation = nil;
498 if (ScrollbarThemeMac* macTheme = macScrollbarTheme())
499 macTheme->setPaintCharacteristicsForScrollbar(_scrollbar);
501 if (part == WebCore::ThumbPart && _scrollbar->orientation() == VerticalScrollbar) {
503 IntRect thumbRect = IntRect([scrollerPainter rectForPart:NSScrollerKnob]);
504 [self scrollAnimator]->setVisibleScrollerThumbRect(thumbRect);
506 [self scrollAnimator]->setVisibleScrollerThumbRect(IntRect());
509 scrollbarPartAnimation = adoptNS([[WebScrollbarPartAnimation alloc] initWithScrollbar:_scrollbar
510 featureToAnimate:part == ThumbPart ? ThumbAlpha : TrackAlpha
511 animateFrom:part == ThumbPart ? [scrollerPainter knobAlpha] : [scrollerPainter trackAlpha]
514 [scrollbarPartAnimation startAnimation];
517 - (void)scrollerImp:(id)scrollerImp animateKnobAlphaTo:(CGFloat)newKnobAlpha duration:(NSTimeInterval)duration
522 ASSERT(scrollerImp == scrollbarPainterForScrollbar(_scrollbar));
524 ScrollbarPainter scrollerPainter = (ScrollbarPainter)scrollerImp;
525 if (![self scrollAnimator]->scrollbarsCanBeActive()) {
526 [scrollerImp setKnobAlpha:0];
527 _scrollbar->invalidate();
531 // If we are fading the scrollbar away, that is a good indication that we are no longer going to
532 // be moving it around on the scrolling thread. Calling [scrollerPainter setUsePresentationValue:NO]
533 // will pass that information on to the ScrollbarPainter API.
534 if (newKnobAlpha == 0 && _scrollbar->supportsUpdateOnSecondaryThread())
535 [scrollerPainter setUsePresentationValue:NO];
537 [self setUpAlphaAnimation:_knobAlphaAnimation scrollerPainter:scrollerPainter part:WebCore::ThumbPart animateAlphaTo:newKnobAlpha duration:duration];
540 - (void)scrollerImp:(id)scrollerImp animateTrackAlphaTo:(CGFloat)newTrackAlpha duration:(NSTimeInterval)duration
545 ASSERT(scrollerImp == scrollbarPainterForScrollbar(_scrollbar));
547 ScrollbarPainter scrollerPainter = (ScrollbarPainter)scrollerImp;
548 [self setUpAlphaAnimation:_trackAlphaAnimation scrollerPainter:scrollerPainter part:WebCore::BackTrackPart animateAlphaTo:newTrackAlpha duration:duration];
551 - (void)scrollerImp:(id)scrollerImp animateUIStateTransitionWithDuration:(NSTimeInterval)duration
556 if (!supportsUIStateTransitionProgress())
559 ASSERT(scrollerImp == scrollbarPainterForScrollbar(_scrollbar));
561 ScrollbarPainter scrollbarPainter = (ScrollbarPainter)scrollerImp;
563 // UIStateTransition always animates to 1. In case an animation is in progress this avoids a hard transition.
564 [scrollbarPainter setUiStateTransitionProgress:1 - [scrollerImp uiStateTransitionProgress]];
566 // If the UI state transition is happening, then we are no longer moving the scrollbar on the scrolling thread.
567 if (_scrollbar->supportsUpdateOnSecondaryThread())
568 [scrollbarPainter setUsePresentationValue:NO];
570 if (!_uiStateTransitionAnimation)
571 _uiStateTransitionAnimation = adoptNS([[WebScrollbarPartAnimation alloc] initWithScrollbar:_scrollbar
572 featureToAnimate:UIStateTransition
573 animateFrom:[scrollbarPainter uiStateTransitionProgress]
577 // If we don't need to initialize the animation, just reset the values in case they have changed.
578 [_uiStateTransitionAnimation setStartValue:[scrollbarPainter uiStateTransitionProgress]];
579 [_uiStateTransitionAnimation setEndValue:1.0];
580 [_uiStateTransitionAnimation setDuration:duration];
582 [_uiStateTransitionAnimation startAnimation];
585 - (void)scrollerImp:(id)scrollerImp animateExpansionTransitionWithDuration:(NSTimeInterval)duration
590 if (!supportsExpansionTransitionProgress())
593 ASSERT(scrollerImp == scrollbarPainterForScrollbar(_scrollbar));
595 ScrollbarPainter scrollbarPainter = (ScrollbarPainter)scrollerImp;
597 // ExpansionTransition always animates to 1. In case an animation is in progress this avoids a hard transition.
598 [scrollbarPainter setExpansionTransitionProgress:1 - [scrollerImp expansionTransitionProgress]];
600 if (!_expansionTransitionAnimation) {
601 _expansionTransitionAnimation = adoptNS([[WebScrollbarPartAnimation alloc] initWithScrollbar:_scrollbar
602 featureToAnimate:ExpansionTransition
603 animateFrom:[scrollbarPainter expansionTransitionProgress]
607 // If we don't need to initialize the animation, just reset the values in case they have changed.
608 [_expansionTransitionAnimation setStartValue:[scrollbarPainter uiStateTransitionProgress]];
609 [_expansionTransitionAnimation setEndValue:1.0];
610 [_expansionTransitionAnimation setDuration:duration];
612 [_expansionTransitionAnimation startAnimation];
615 - (void)scrollerImp:(id)scrollerImp overlayScrollerStateChangedTo:(NSUInteger)newOverlayScrollerState
617 UNUSED_PARAM(scrollerImp);
618 UNUSED_PARAM(newOverlayScrollerState);
624 BEGIN_BLOCK_OBJC_EXCEPTIONS;
625 [_knobAlphaAnimation invalidate];
626 [_trackAlphaAnimation invalidate];
627 [_uiStateTransitionAnimation invalidate];
628 [_expansionTransitionAnimation invalidate];
629 END_BLOCK_OBJC_EXCEPTIONS;
636 std::unique_ptr<ScrollAnimator> ScrollAnimator::create(ScrollableArea& scrollableArea)
638 return std::make_unique<ScrollAnimatorMac>(scrollableArea);
641 ScrollAnimatorMac::ScrollAnimatorMac(ScrollableArea& scrollableArea)
642 : ScrollAnimator(scrollableArea)
643 , m_initialScrollbarPaintTimer(*this, &ScrollAnimatorMac::initialScrollbarPaintTimerFired)
644 , m_sendContentAreaScrolledTimer(*this, &ScrollAnimatorMac::sendContentAreaScrolledTimerFired)
645 , m_haveScrolledSincePageLoad(false)
646 , m_needsScrollerStyleUpdate(false)
648 m_scrollAnimationHelperDelegate = adoptNS([[WebScrollAnimationHelperDelegate alloc] initWithScrollAnimator:this]);
649 m_scrollAnimationHelper = adoptNS([[NSClassFromString(@"NSScrollAnimationHelper") alloc] initWithDelegate:m_scrollAnimationHelperDelegate.get()]);
651 m_scrollbarPainterControllerDelegate = adoptNS([[WebScrollbarPainterControllerDelegate alloc] initWithScrollableArea:&scrollableArea]);
652 m_scrollbarPainterController = adoptNS([[NSClassFromString(@"NSScrollerImpPair") alloc] init]);
653 [m_scrollbarPainterController setDelegate:(id)m_scrollbarPainterControllerDelegate.get()];
654 [m_scrollbarPainterController setScrollerStyle:recommendedScrollerStyle()];
657 ScrollAnimatorMac::~ScrollAnimatorMac()
659 BEGIN_BLOCK_OBJC_EXCEPTIONS;
660 [m_scrollbarPainterControllerDelegate invalidate];
661 [m_scrollbarPainterController setDelegate:nil];
662 [m_horizontalScrollbarPainterDelegate invalidate];
663 [m_verticalScrollbarPainterDelegate invalidate];
664 [m_scrollAnimationHelperDelegate invalidate];
665 END_BLOCK_OBJC_EXCEPTIONS;
668 static bool scrollAnimationEnabledForSystem()
670 NSString* scrollAnimationDefaultsKey = @"NSScrollAnimationEnabled";
671 static bool enabled = [[NSUserDefaults standardUserDefaults] boolForKey:scrollAnimationDefaultsKey];
675 #if ENABLE(RUBBER_BANDING)
676 static bool rubberBandingEnabledForSystem()
678 static bool initialized = false;
679 static bool enabled = true;
680 // Caches the result, which is consistent with other apps like the Finder, which all
681 // require a restart after changing this default.
683 // Uses -objectForKey: and not -boolForKey: in order to default to true if the value wasn't set.
684 id value = [[NSUserDefaults standardUserDefaults] objectForKey:@"NSScrollViewRubberbanding"];
685 if ([value isKindOfClass:[NSNumber class]])
686 enabled = [value boolValue];
693 bool ScrollAnimatorMac::scroll(ScrollbarOrientation orientation, ScrollGranularity granularity, float step, float multiplier)
695 m_haveScrolledSincePageLoad = true;
697 if (!scrollAnimationEnabledForSystem() || !m_scrollableArea.scrollAnimatorEnabled())
698 return ScrollAnimator::scroll(orientation, granularity, step, multiplier);
700 if (granularity == ScrollByPixel)
701 return ScrollAnimator::scroll(orientation, granularity, step, multiplier);
703 float currentPos = orientation == HorizontalScrollbar ? m_currentPosX : m_currentPosY;
704 float newPos = std::max<float>(std::min<float>(currentPos + (step * multiplier), static_cast<float>(m_scrollableArea.scrollSize(orientation))), 0);
705 if (currentPos == newPos)
709 if ([m_scrollAnimationHelper _isAnimating]) {
710 NSPoint targetOrigin = [m_scrollAnimationHelper targetOrigin];
711 newPoint = orientation == HorizontalScrollbar ? NSMakePoint(newPos, targetOrigin.y) : NSMakePoint(targetOrigin.x, newPos);
713 newPoint = orientation == HorizontalScrollbar ? NSMakePoint(newPos, m_currentPosY) : NSMakePoint(m_currentPosX, newPos);
715 [m_scrollAnimationHelper scrollToPoint:newPoint];
719 void ScrollAnimatorMac::scrollToOffsetWithoutAnimation(const FloatPoint& offset)
721 [m_scrollAnimationHelper _stopRun];
722 immediateScrollTo(offset);
725 FloatPoint ScrollAnimatorMac::adjustScrollPositionIfNecessary(const FloatPoint& position) const
727 if (!m_scrollableArea.constrainsScrollingToContentEdge())
730 float newX = std::max<float>(std::min<float>(position.x(), m_scrollableArea.totalContentsSize().width() - m_scrollableArea.visibleWidth()), 0);
731 float newY = std::max<float>(std::min<float>(position.y(), m_scrollableArea.totalContentsSize().height() - m_scrollableArea.visibleHeight()), 0);
733 return FloatPoint(newX, newY);
736 void ScrollAnimatorMac::adjustScrollPositionToBoundsIfNecessary()
738 bool currentlyConstrainsToContentEdge = m_scrollableArea.constrainsScrollingToContentEdge();
739 m_scrollableArea.setConstrainsScrollingToContentEdge(true);
741 IntPoint currentScrollPosition = absoluteScrollPosition();
742 FloatPoint nearestPointWithinBounds = adjustScrollPositionIfNecessary(absoluteScrollPosition());
743 immediateScrollBy(nearestPointWithinBounds - currentScrollPosition);
745 m_scrollableArea.setConstrainsScrollingToContentEdge(currentlyConstrainsToContentEdge);
748 void ScrollAnimatorMac::immediateScrollTo(const FloatPoint& newPosition)
750 FloatPoint adjustedPosition = adjustScrollPositionIfNecessary(newPosition);
752 bool positionChanged = adjustedPosition.x() != m_currentPosX || adjustedPosition.y() != m_currentPosY;
753 if (!positionChanged && !scrollableArea().scrollOriginChanged())
756 FloatSize delta = FloatSize(adjustedPosition.x() - m_currentPosX, adjustedPosition.y() - m_currentPosY);
758 m_currentPosX = adjustedPosition.x();
759 m_currentPosY = adjustedPosition.y();
760 notifyPositionChanged(delta);
763 bool ScrollAnimatorMac::isRubberBandInProgress() const
765 #if !ENABLE(RUBBER_BANDING)
768 return m_scrollController.isRubberBandInProgress();
772 void ScrollAnimatorMac::immediateScrollToPointForScrollAnimation(const FloatPoint& newPosition)
774 ASSERT(m_scrollAnimationHelper);
775 immediateScrollTo(newPosition);
778 void ScrollAnimatorMac::notifyPositionChanged(const FloatSize& delta)
780 notifyContentAreaScrolled(delta);
781 ScrollAnimator::notifyPositionChanged(delta);
784 void ScrollAnimatorMac::contentAreaWillPaint() const
786 if ([m_scrollbarPainterController overlayScrollerStateIsLocked])
789 [m_scrollbarPainterController contentAreaWillDraw];
792 void ScrollAnimatorMac::mouseEnteredContentArea() const
794 if ([m_scrollbarPainterController overlayScrollerStateIsLocked])
797 [m_scrollbarPainterController mouseEnteredContentArea];
800 void ScrollAnimatorMac::mouseExitedContentArea() const
802 if ([m_scrollbarPainterController overlayScrollerStateIsLocked])
805 [m_scrollbarPainterController mouseExitedContentArea];
808 void ScrollAnimatorMac::mouseMovedInContentArea() const
810 if ([m_scrollbarPainterController overlayScrollerStateIsLocked])
813 [m_scrollbarPainterController mouseMovedInContentArea];
816 void ScrollAnimatorMac::mouseEnteredScrollbar(Scrollbar* scrollbar) const
818 // At this time, only legacy scrollbars needs to send notifications here.
819 if (recommendedScrollerStyle() != NSScrollerStyleLegacy)
822 if ([m_scrollbarPainterController overlayScrollerStateIsLocked])
825 if (!supportsUIStateTransitionProgress())
827 if (ScrollbarPainter painter = scrollbarPainterForScrollbar(scrollbar))
828 [painter mouseEnteredScroller];
831 void ScrollAnimatorMac::mouseExitedScrollbar(Scrollbar* scrollbar) const
833 // At this time, only legacy scrollbars needs to send notifications here.
834 if (recommendedScrollerStyle() != NSScrollerStyleLegacy)
837 if ([m_scrollbarPainterController overlayScrollerStateIsLocked])
840 if (!supportsUIStateTransitionProgress())
842 if (ScrollbarPainter painter = scrollbarPainterForScrollbar(scrollbar))
843 [painter mouseExitedScroller];
846 void ScrollAnimatorMac::willStartLiveResize()
848 if ([m_scrollbarPainterController overlayScrollerStateIsLocked])
851 [m_scrollbarPainterController startLiveResize];
854 void ScrollAnimatorMac::contentsResized() const
856 if ([m_scrollbarPainterController overlayScrollerStateIsLocked])
859 [m_scrollbarPainterController contentAreaDidResize];
862 void ScrollAnimatorMac::willEndLiveResize()
864 if ([m_scrollbarPainterController overlayScrollerStateIsLocked])
867 [m_scrollbarPainterController endLiveResize];
870 void ScrollAnimatorMac::contentAreaDidShow() const
872 if ([m_scrollbarPainterController overlayScrollerStateIsLocked])
875 [m_scrollbarPainterController windowOrderedIn];
878 void ScrollAnimatorMac::contentAreaDidHide() const
880 if ([m_scrollbarPainterController overlayScrollerStateIsLocked])
883 [m_scrollbarPainterController windowOrderedOut];
886 void ScrollAnimatorMac::didBeginScrollGesture() const
888 if ([m_scrollbarPainterController overlayScrollerStateIsLocked])
891 [m_scrollbarPainterController beginScrollGesture];
894 void ScrollAnimatorMac::didEndScrollGesture() const
896 if ([m_scrollbarPainterController overlayScrollerStateIsLocked])
899 [m_scrollbarPainterController endScrollGesture];
902 void ScrollAnimatorMac::mayBeginScrollGesture() const
904 if ([m_scrollbarPainterController overlayScrollerStateIsLocked])
907 [m_scrollbarPainterController beginScrollGesture];
908 [m_scrollbarPainterController contentAreaScrolled];
911 void ScrollAnimatorMac::lockOverlayScrollbarStateToHidden(bool shouldLockState)
914 [m_scrollbarPainterController lockOverlayScrollerState:ScrollbarOverlayStateHidden];
916 [m_scrollbarPainterController unlockOverlayScrollerState];
918 // We never update scroller style for PainterControllers that are locked. If we have a pending
919 // need to update the style, do it once we've unlocked the scroller state.
920 if (m_needsScrollerStyleUpdate)
921 updateScrollerStyle();
925 bool ScrollAnimatorMac::scrollbarsCanBeActive() const
927 return ![m_scrollbarPainterController overlayScrollerStateIsLocked];
930 void ScrollAnimatorMac::didAddVerticalScrollbar(Scrollbar* scrollbar)
932 ScrollbarPainter painter = scrollbarPainterForScrollbar(scrollbar);
936 ASSERT(!m_verticalScrollbarPainterDelegate);
937 m_verticalScrollbarPainterDelegate = adoptNS([[WebScrollbarPainterDelegate alloc] initWithScrollbar:scrollbar]);
939 [painter setDelegate:(id)m_verticalScrollbarPainterDelegate.get()];
940 if (GraphicsLayer* layer = scrollbar->scrollableArea().layerForVerticalScrollbar())
941 [painter setLayer:layer->platformLayer()];
943 [m_scrollbarPainterController setVerticalScrollerImp:painter];
944 if (scrollableArea().inLiveResize())
945 [painter setKnobAlpha:1];
948 void ScrollAnimatorMac::willRemoveVerticalScrollbar(Scrollbar* scrollbar)
950 ScrollbarPainter painter = scrollbarPainterForScrollbar(scrollbar);
954 ASSERT(m_verticalScrollbarPainterDelegate);
955 [m_verticalScrollbarPainterDelegate invalidate];
956 m_verticalScrollbarPainterDelegate = nullptr;
958 [painter setDelegate:nil];
959 [m_scrollbarPainterController setVerticalScrollerImp:nil];
962 void ScrollAnimatorMac::didAddHorizontalScrollbar(Scrollbar* scrollbar)
964 ScrollbarPainter painter = scrollbarPainterForScrollbar(scrollbar);
968 ASSERT(!m_horizontalScrollbarPainterDelegate);
969 m_horizontalScrollbarPainterDelegate = adoptNS([[WebScrollbarPainterDelegate alloc] initWithScrollbar:scrollbar]);
971 [painter setDelegate:(id)m_horizontalScrollbarPainterDelegate.get()];
972 if (GraphicsLayer* layer = scrollbar->scrollableArea().layerForHorizontalScrollbar())
973 [painter setLayer:layer->platformLayer()];
975 [m_scrollbarPainterController setHorizontalScrollerImp:painter];
976 if (scrollableArea().inLiveResize())
977 [painter setKnobAlpha:1];
980 void ScrollAnimatorMac::willRemoveHorizontalScrollbar(Scrollbar* scrollbar)
982 ScrollbarPainter painter = scrollbarPainterForScrollbar(scrollbar);
986 ASSERT(m_horizontalScrollbarPainterDelegate);
987 [m_horizontalScrollbarPainterDelegate invalidate];
988 m_horizontalScrollbarPainterDelegate = nullptr;
990 [painter setDelegate:nil];
991 [m_scrollbarPainterController setHorizontalScrollerImp:nil];
994 void ScrollAnimatorMac::verticalScrollbarLayerDidChange()
996 GraphicsLayer* layer = m_scrollableArea.layerForVerticalScrollbar();
997 Scrollbar* scrollbar = m_scrollableArea.verticalScrollbar();
1001 ScrollbarPainter painter = scrollbarPainterForScrollbar(scrollbar);
1005 [painter setLayer:layer ? layer->platformLayer() : nil];
1008 void ScrollAnimatorMac::horizontalScrollbarLayerDidChange()
1010 GraphicsLayer* layer = m_scrollableArea.layerForHorizontalScrollbar();
1011 Scrollbar* scrollbar = m_scrollableArea.horizontalScrollbar();
1015 ScrollbarPainter painter = scrollbarPainterForScrollbar(scrollbar);
1019 [painter setLayer:layer ? layer->platformLayer() : nil];
1022 bool ScrollAnimatorMac::shouldScrollbarParticipateInHitTesting(Scrollbar* scrollbar)
1024 // Non-overlay scrollbars should always participate in hit testing.
1025 if (recommendedScrollerStyle() != NSScrollerStyleOverlay)
1028 if (scrollbar->isAlphaLocked())
1031 // Overlay scrollbars should participate in hit testing whenever they are at all visible.
1032 ScrollbarPainter painter = scrollbarPainterForScrollbar(scrollbar);
1035 return [painter knobAlpha] > 0;
1038 void ScrollAnimatorMac::notifyContentAreaScrolled(const FloatSize& delta)
1040 // This function is called when a page is going into the page cache, but the page
1041 // isn't really scrolling in that case. We should only pass the message on to the
1042 // ScrollbarPainterController when we're really scrolling on an active page.
1043 if ([m_scrollbarPainterController overlayScrollerStateIsLocked])
1046 if (m_scrollableArea.isHandlingWheelEvent())
1047 sendContentAreaScrolled(delta);
1049 sendContentAreaScrolledSoon(delta);
1052 void ScrollAnimatorMac::cancelAnimations()
1054 m_haveScrolledSincePageLoad = false;
1056 if (scrollbarPaintTimerIsActive())
1057 stopScrollbarPaintTimer();
1058 [m_horizontalScrollbarPainterDelegate cancelAnimations];
1059 [m_verticalScrollbarPainterDelegate cancelAnimations];
1062 void ScrollAnimatorMac::handleWheelEventPhase(PlatformWheelEventPhase phase)
1064 // This may not have been set to true yet if the wheel event was handled by the ScrollingTree,
1065 // So set it to true here.
1066 m_haveScrolledSincePageLoad = true;
1068 if (phase == PlatformWheelEventPhaseBegan)
1069 didBeginScrollGesture();
1070 else if (phase == PlatformWheelEventPhaseEnded || phase == PlatformWheelEventPhaseCancelled)
1071 didEndScrollGesture();
1072 else if (phase == PlatformWheelEventPhaseMayBegin)
1073 mayBeginScrollGesture();
1076 #if ENABLE(RUBBER_BANDING)
1077 bool ScrollAnimatorMac::handleWheelEvent(const PlatformWheelEvent& wheelEvent)
1079 m_haveScrolledSincePageLoad = true;
1081 if (!wheelEvent.hasPreciseScrollingDeltas() || !rubberBandingEnabledForSystem())
1082 return ScrollAnimator::handleWheelEvent(wheelEvent);
1084 // FIXME: This is somewhat roundabout hack to allow forwarding wheel events
1085 // up to the parent scrollable area. It takes advantage of the fact that
1086 // the base class implementation of handleWheelEvent will not accept the
1087 // wheel event if there is nowhere to scroll.
1088 if (fabsf(wheelEvent.deltaY()) >= fabsf(wheelEvent.deltaX())) {
1089 if (!allowsVerticalStretching(wheelEvent))
1090 return ScrollAnimator::handleWheelEvent(wheelEvent);
1092 if (!allowsHorizontalStretching(wheelEvent))
1093 return ScrollAnimator::handleWheelEvent(wheelEvent);
1096 bool didHandleEvent = m_scrollController.handleWheelEvent(wheelEvent);
1099 handleWheelEventPhase(wheelEvent.phase());
1101 return didHandleEvent;
1104 bool ScrollAnimatorMac::pinnedInDirection(const FloatSize& direction)
1106 FloatSize limitDelta;
1107 if (fabsf(direction.height()) >= fabsf(direction.width())) {
1108 if (direction.height() < 0) {
1109 // We are trying to scroll up. Make sure we are not pinned to the top
1110 limitDelta.setHeight(m_scrollableArea.visibleContentRect().y() + m_scrollableArea.scrollOrigin().y());
1112 // We are trying to scroll down. Make sure we are not pinned to the bottom
1113 limitDelta.setHeight(m_scrollableArea.totalContentsSize().height() - (m_scrollableArea.visibleContentRect().maxY() + m_scrollableArea.scrollOrigin().y()));
1115 } else if (direction.width()) {
1116 if (direction.width() < 0) {
1117 // We are trying to scroll left. Make sure we are not pinned to the left
1118 limitDelta.setWidth(m_scrollableArea.visibleContentRect().x() + m_scrollableArea.scrollOrigin().x());
1120 // We are trying to scroll right. Make sure we are not pinned to the right
1121 limitDelta.setWidth(m_scrollableArea.totalContentsSize().width() - (m_scrollableArea.visibleContentRect().maxX() + m_scrollableArea.scrollOrigin().x()));
1125 if ((direction.width() || direction.height()) && (limitDelta.width() < 1 && limitDelta.height() < 1))
1130 // FIXME: We should find a way to share some of the code from newGestureIsStarting(), isAlreadyPinnedInDirectionOfGesture(),
1131 // allowsVerticalStretching(), and allowsHorizontalStretching() with the implementation in ScrollingTreeFrameScrollingNodeMac.
1132 static bool newGestureIsStarting(const PlatformWheelEvent& wheelEvent)
1134 return wheelEvent.phase() == PlatformWheelEventPhaseMayBegin || wheelEvent.phase() == PlatformWheelEventPhaseBegan;
1137 bool ScrollAnimatorMac::isAlreadyPinnedInDirectionOfGesture(const PlatformWheelEvent& wheelEvent, ScrollEventAxis axis)
1140 case ScrollEventAxis::Vertical:
1141 return (wheelEvent.deltaY() > 0 && m_scrollableArea.scrolledToTop()) || (wheelEvent.deltaY() < 0 && m_scrollableArea.scrolledToBottom());
1142 case ScrollEventAxis::Horizontal:
1143 return (wheelEvent.deltaX() > 0 && m_scrollableArea.scrolledToLeft()) || (wheelEvent.deltaX() < 0 && m_scrollableArea.scrolledToRight());
1146 ASSERT_NOT_REACHED();
1150 #if ENABLE(CSS_SCROLL_SNAP)
1151 static bool gestureShouldBeginSnap(const PlatformWheelEvent& wheelEvent, const Vector<LayoutUnit>* snapOffsets)
1156 if (wheelEvent.phase() != PlatformWheelEventPhaseEnded && !wheelEvent.isEndGesture())
1163 bool ScrollAnimatorMac::allowsVerticalStretching(const PlatformWheelEvent& wheelEvent)
1165 switch (m_scrollableArea.verticalScrollElasticity()) {
1166 case ScrollElasticityAutomatic: {
1167 Scrollbar* hScroller = m_scrollableArea.horizontalScrollbar();
1168 Scrollbar* vScroller = m_scrollableArea.verticalScrollbar();
1169 bool scrollbarsAllowStretching = ((vScroller && vScroller->enabled()) || (!hScroller || !hScroller->enabled()));
1170 bool eventPreventsStretching = m_scrollableArea.hasScrollableOrRubberbandableAncestor() && newGestureIsStarting(wheelEvent) && isAlreadyPinnedInDirectionOfGesture(wheelEvent, ScrollEventAxis::Vertical);
1171 #if ENABLE(CSS_SCROLL_SNAP)
1172 if (!eventPreventsStretching)
1173 eventPreventsStretching = gestureShouldBeginSnap(wheelEvent, m_scrollableArea.verticalSnapOffsets());
1175 return scrollbarsAllowStretching && !eventPreventsStretching;
1177 case ScrollElasticityNone:
1179 case ScrollElasticityAllowed:
1183 ASSERT_NOT_REACHED();
1187 bool ScrollAnimatorMac::allowsHorizontalStretching(const PlatformWheelEvent& wheelEvent)
1189 switch (m_scrollableArea.horizontalScrollElasticity()) {
1190 case ScrollElasticityAutomatic: {
1191 Scrollbar* hScroller = m_scrollableArea.horizontalScrollbar();
1192 Scrollbar* vScroller = m_scrollableArea.verticalScrollbar();
1193 bool scrollbarsAllowStretching = ((hScroller && hScroller->enabled()) || (!vScroller || !vScroller->enabled()));
1194 bool eventPreventsStretching = m_scrollableArea.hasScrollableOrRubberbandableAncestor() && newGestureIsStarting(wheelEvent) && isAlreadyPinnedInDirectionOfGesture(wheelEvent, ScrollEventAxis::Horizontal);
1195 #if ENABLE(CSS_SCROLL_SNAP)
1196 if (!eventPreventsStretching)
1197 eventPreventsStretching = gestureShouldBeginSnap(wheelEvent, m_scrollableArea.horizontalSnapOffsets());
1199 return scrollbarsAllowStretching && !eventPreventsStretching;
1201 case ScrollElasticityNone:
1203 case ScrollElasticityAllowed:
1207 ASSERT_NOT_REACHED();
1211 IntSize ScrollAnimatorMac::stretchAmount()
1213 return m_scrollableArea.overhangAmount();
1216 bool ScrollAnimatorMac::canScrollHorizontally()
1218 Scrollbar* scrollbar = m_scrollableArea.horizontalScrollbar();
1221 return scrollbar->enabled();
1224 bool ScrollAnimatorMac::canScrollVertically()
1226 Scrollbar* scrollbar = m_scrollableArea.verticalScrollbar();
1229 return scrollbar->enabled();
1232 bool ScrollAnimatorMac::shouldRubberBandInDirection(ScrollDirection)
1237 IntPoint ScrollAnimatorMac::absoluteScrollPosition()
1239 return m_scrollableArea.visibleContentRect().location() + m_scrollableArea.scrollOrigin();
1242 void ScrollAnimatorMac::immediateScrollByWithoutContentEdgeConstraints(const FloatSize& delta)
1244 m_scrollableArea.setConstrainsScrollingToContentEdge(false);
1245 immediateScrollBy(delta);
1246 m_scrollableArea.setConstrainsScrollingToContentEdge(true);
1249 void ScrollAnimatorMac::immediateScrollBy(const FloatSize& delta)
1251 FloatPoint newPos = adjustScrollPositionIfNecessary(FloatPoint(m_currentPosX, m_currentPosY) + delta);
1252 if (newPos.x() == m_currentPosX && newPos.y() == m_currentPosY)
1255 FloatSize adjustedDelta = FloatSize(newPos.x() - m_currentPosX, newPos.y() - m_currentPosY);
1257 m_currentPosX = newPos.x();
1258 m_currentPosY = newPos.y();
1259 notifyPositionChanged(adjustedDelta);
1263 void ScrollAnimatorMac::updateScrollerStyle()
1265 if ([m_scrollbarPainterController overlayScrollerStateIsLocked]) {
1266 m_needsScrollerStyleUpdate = true;
1270 ScrollbarThemeMac* macTheme = macScrollbarTheme();
1272 m_needsScrollerStyleUpdate = false;
1276 macTheme->usesOverlayScrollbarsChanged();
1278 NSScrollerStyle newStyle = [m_scrollbarPainterController scrollerStyle];
1280 if (Scrollbar* verticalScrollbar = scrollableArea().verticalScrollbar()) {
1281 verticalScrollbar->invalidate();
1283 ScrollbarPainter oldVerticalPainter = [m_scrollbarPainterController verticalScrollerImp];
1284 ScrollbarPainter newVerticalPainter = [NSClassFromString(@"NSScrollerImp") scrollerImpWithStyle:newStyle
1285 controlSize:(NSControlSize)verticalScrollbar->controlSize()
1287 replacingScrollerImp:oldVerticalPainter];
1288 [m_scrollbarPainterController setVerticalScrollerImp:newVerticalPainter];
1289 macTheme->setNewPainterForScrollbar(verticalScrollbar, newVerticalPainter);
1291 // The different scrollbar styles have different thicknesses, so we must re-set the
1292 // frameRect to the new thickness, and the re-layout below will ensure the position
1293 // and length are properly updated.
1294 int thickness = macTheme->scrollbarThickness(verticalScrollbar->controlSize());
1295 verticalScrollbar->setFrameRect(IntRect(0, 0, thickness, thickness));
1298 if (Scrollbar* horizontalScrollbar = scrollableArea().horizontalScrollbar()) {
1299 horizontalScrollbar->invalidate();
1301 ScrollbarPainter oldHorizontalPainter = [m_scrollbarPainterController horizontalScrollerImp];
1302 ScrollbarPainter newHorizontalPainter = [NSClassFromString(@"NSScrollerImp") scrollerImpWithStyle:newStyle
1303 controlSize:(NSControlSize)horizontalScrollbar->controlSize()
1305 replacingScrollerImp:oldHorizontalPainter];
1306 [m_scrollbarPainterController setHorizontalScrollerImp:newHorizontalPainter];
1307 macTheme->setNewPainterForScrollbar(horizontalScrollbar, newHorizontalPainter);
1309 // The different scrollbar styles have different thicknesses, so we must re-set the
1310 // frameRect to the new thickness, and the re-layout below will ensure the position
1311 // and length are properly updated.
1312 int thickness = macTheme->scrollbarThickness(horizontalScrollbar->controlSize());
1313 horizontalScrollbar->setFrameRect(IntRect(0, 0, thickness, thickness));
1316 // If m_needsScrollerStyleUpdate is true, then the page is restoring from the page cache, and
1317 // a relayout will happen on its own. Otherwise, we must initiate a re-layout ourselves.
1318 scrollableArea().scrollbarStyleChanged(newStyle == NSScrollerStyleOverlay ? ScrollbarStyle::Overlay : ScrollbarStyle::AlwaysVisible, !m_needsScrollerStyleUpdate);
1320 m_needsScrollerStyleUpdate = false;
1323 void ScrollAnimatorMac::startScrollbarPaintTimer()
1325 m_initialScrollbarPaintTimer.startOneShot(0.1);
1328 bool ScrollAnimatorMac::scrollbarPaintTimerIsActive() const
1330 return m_initialScrollbarPaintTimer.isActive();
1333 void ScrollAnimatorMac::stopScrollbarPaintTimer()
1335 m_initialScrollbarPaintTimer.stop();
1338 void ScrollAnimatorMac::initialScrollbarPaintTimerFired()
1340 // To force the scrollbars to flash, we have to call hide first. Otherwise, the ScrollbarPainterController
1341 // might think that the scrollbars are already showing and bail early.
1342 [m_scrollbarPainterController hideOverlayScrollers];
1343 [m_scrollbarPainterController flashScrollers];
1346 void ScrollAnimatorMac::sendContentAreaScrolledSoon(const FloatSize& delta)
1348 m_contentAreaScrolledTimerScrollDelta = delta;
1350 if (!m_sendContentAreaScrolledTimer.isActive())
1351 m_sendContentAreaScrolledTimer.startOneShot(0);
1354 void ScrollAnimatorMac::sendContentAreaScrolled(const FloatSize& delta)
1356 if (supportsContentAreaScrolledInDirection())
1357 [m_scrollbarPainterController contentAreaScrolledInDirection:NSMakePoint(delta.width(), delta.height())];
1359 [m_scrollbarPainterController contentAreaScrolled];
1362 void ScrollAnimatorMac::sendContentAreaScrolledTimerFired()
1364 sendContentAreaScrolled(m_contentAreaScrolledTimerScrollDelta);
1365 m_contentAreaScrolledTimerScrollDelta = FloatSize();
1368 void ScrollAnimatorMac::setVisibleScrollerThumbRect(const IntRect& scrollerThumb)
1370 IntRect rectInViewCoordinates = scrollerThumb;
1371 if (Scrollbar* verticalScrollbar = m_scrollableArea.verticalScrollbar())
1372 rectInViewCoordinates = verticalScrollbar->convertToContainingView(scrollerThumb);
1374 if (rectInViewCoordinates == m_visibleScrollerThumbRect)
1377 m_scrollableArea.setVisibleScrollerThumbRect(rectInViewCoordinates);
1378 m_visibleScrollerThumbRect = rectInViewCoordinates;
1381 } // namespace WebCore
1383 #endif // ENABLE(SMOOTH_SCROLLING)