Changeset 76956 in webkit


Ignore:
Timestamp:
Jan 28, 2011 11:05:43 AM (13 years ago)
Author:
weinig@apple.com
Message:

Add basic rubber banding support
<rdar://problem/8219429>
https://bugs.webkit.org/show_bug.cgi?id=53277

Reviewed by Maciej Stachowiak.

Source/JavaScriptCore:

  • wtf/Platform.h: Add ENABLE for rubber banding.

Source/WebCore:

  • page/EventHandler.cpp:

(WebCore::EventHandler::handleGestureEvent):
Pass gesture events to the FrameView.

  • platform/ScrollAnimator.cpp:

(WebCore::ScrollAnimator::handleGestureEvent):

  • platform/ScrollAnimator.h:

Add stubbed out implementation.

  • platform/ScrollView.cpp:

(WebCore::ScrollView::ScrollView):
(WebCore::ScrollView::overhangAmount):
(WebCore::ScrollView::wheelEvent):

  • platform/ScrollView.h:
  • platform/ScrollableArea.cpp:

(WebCore::ScrollableArea::ScrollableArea):
(WebCore::ScrollableArea::handleGestureEvent):

  • platform/ScrollableArea.h:

(WebCore::ScrollableArea::constrainsScrollingToContentEdge):
(WebCore::ScrollableArea::setConstrainsScrollingToContentEdge):
Move constrains scrolling bit to ScrollableArea from ScrollView.

(WebCore::ScrollableArea::contentsSize):
(WebCore::ScrollableArea::overhangAmount):
Add additional virtual functions for information needed by the animator.

  • platform/mac/ScrollAnimatorMac.h:
  • platform/mac/ScrollAnimatorMac.mm:

(WebCore::ScrollAnimatorMac::ScrollAnimatorMac):
(WebCore::ScrollAnimatorMac::immediateScrollByDeltaX):
(WebCore::ScrollAnimatorMac::immediateScrollByDeltaY):
(WebCore::elasticDeltaForTimeDelta):
(WebCore::elasticDeltaForReboundDelta):
(WebCore::reboundDeltaForElasticDelta):
(WebCore::scrollWheelMultiplier):
(WebCore::ScrollAnimatorMac::handleWheelEvent):
(WebCore::ScrollAnimatorMac::handleGestureEvent):
(WebCore::ScrollAnimatorMac::pinnedInDirection):
(WebCore::ScrollAnimatorMac::allowsVerticalStretching):
(WebCore::ScrollAnimatorMac::allowsHorizontalStretching):
(WebCore::ScrollAnimatorMac::smoothScrollWithEvent):
(WebCore::ScrollAnimatorMac::beginScrollGesture):
(WebCore::ScrollAnimatorMac::endScrollGesture):
(WebCore::ScrollAnimatorMac::snapRubberBand):
(WebCore::roundTowardZero):
(WebCore::roundToDevicePixelTowardZero):
(WebCore::ScrollAnimatorMac::snapRubberBandTimerFired):
Implement basic rubber banding.

Location:
trunk/Source
Files:
12 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r76925 r76956  
     12011-01-28  Sam Weinig  <sam@webkit.org>
     2
     3        Reviewed by Maciej Stachowiak.
     4
     5        Add basic rubber banding support
     6        <rdar://problem/8219429>
     7        https://bugs.webkit.org/show_bug.cgi?id=53277
     8
     9        * wtf/Platform.h: Add ENABLE for rubber banding.
     10
    1112011-01-28  Sheriff Bot  <webkit.review.bot@gmail.com>
    212
  • trunk/Source/JavaScriptCore/wtf/Platform.h

    r76745 r76956  
    606606#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
    607607#define ENABLE_GESTURE_EVENTS 1
     608#define ENABLE_RUBBER_BANDING 1
    608609#endif
    609610#if !defined(ENABLE_JAVA_BRIDGE)
  • trunk/Source/WebCore/ChangeLog

    r76954 r76956  
     12011-01-28  Sam Weinig  <sam@webkit.org>
     2
     3        Reviewed by Maciej Stachowiak.
     4
     5        Add basic rubber banding support
     6        <rdar://problem/8219429>
     7        https://bugs.webkit.org/show_bug.cgi?id=53277
     8
     9        * page/EventHandler.cpp:
     10        (WebCore::EventHandler::handleGestureEvent):
     11        Pass gesture events to the FrameView.
     12
     13        * platform/ScrollAnimator.cpp:
     14        (WebCore::ScrollAnimator::handleGestureEvent):
     15        * platform/ScrollAnimator.h:
     16        Add stubbed out implementation.
     17
     18        * platform/ScrollView.cpp:
     19        (WebCore::ScrollView::ScrollView):
     20        (WebCore::ScrollView::overhangAmount):
     21        (WebCore::ScrollView::wheelEvent):
     22        * platform/ScrollView.h:
     23        * platform/ScrollableArea.cpp:
     24        (WebCore::ScrollableArea::ScrollableArea):
     25        (WebCore::ScrollableArea::handleGestureEvent):
     26        * platform/ScrollableArea.h:
     27        (WebCore::ScrollableArea::constrainsScrollingToContentEdge):
     28        (WebCore::ScrollableArea::setConstrainsScrollingToContentEdge):
     29        Move constrains scrolling bit to ScrollableArea from ScrollView.
     30
     31        (WebCore::ScrollableArea::contentsSize):
     32        (WebCore::ScrollableArea::overhangAmount):
     33        Add additional virtual functions for information needed by the animator.
     34
     35        * platform/mac/ScrollAnimatorMac.h:
     36        * platform/mac/ScrollAnimatorMac.mm:
     37        (WebCore::ScrollAnimatorMac::ScrollAnimatorMac):
     38        (WebCore::ScrollAnimatorMac::immediateScrollByDeltaX):
     39        (WebCore::ScrollAnimatorMac::immediateScrollByDeltaY):
     40        (WebCore::elasticDeltaForTimeDelta):
     41        (WebCore::elasticDeltaForReboundDelta):
     42        (WebCore::reboundDeltaForElasticDelta):
     43        (WebCore::scrollWheelMultiplier):
     44        (WebCore::ScrollAnimatorMac::handleWheelEvent):
     45        (WebCore::ScrollAnimatorMac::handleGestureEvent):
     46        (WebCore::ScrollAnimatorMac::pinnedInDirection):
     47        (WebCore::ScrollAnimatorMac::allowsVerticalStretching):
     48        (WebCore::ScrollAnimatorMac::allowsHorizontalStretching):
     49        (WebCore::ScrollAnimatorMac::smoothScrollWithEvent):
     50        (WebCore::ScrollAnimatorMac::beginScrollGesture):
     51        (WebCore::ScrollAnimatorMac::endScrollGesture):
     52        (WebCore::ScrollAnimatorMac::snapRubberBand):
     53        (WebCore::roundTowardZero):
     54        (WebCore::roundToDevicePixelTowardZero):
     55        (WebCore::ScrollAnimatorMac::snapRubberBandTimerFired):
     56        Implement basic rubber banding.
     57
    1582011-01-28  Dan Bernstein  <mitz@apple.com>
    259
  • trunk/Source/WebCore/page/EventHandler.cpp

    r76912 r76956  
    20412041
    20422042#if ENABLE(GESTURE_EVENTS)
    2043 bool EventHandler::handleGestureEvent(const PlatformGestureEvent&)
    2044 {
    2045     // FIXME: Handle gesture events.
     2043bool EventHandler::handleGestureEvent(const PlatformGestureEvent& gestureEvent)
     2044{
     2045    // FIXME: This should hit test and go to the correct subframe rather than
     2046    // always sending gestures to the main frame only. We should also ensure
     2047    // that if a frame gets a gesture begin gesture, it gets the corresponding
     2048    // end gesture as well.
     2049
     2050    FrameView* view = m_frame->view();
     2051    if (!view)
     2052        return false;
     2053
     2054    view->handleGestureEvent(gestureEvent);
    20462055    return true;
    20472056}
  • trunk/Source/WebCore/platform/ScrollAnimator.cpp

    r76757 r76956  
    114114}
    115115
     116#if ENABLE(GESTURE_EVENTS)
     117void ScrollAnimator::handleGestureEvent(const PlatformGestureEvent&)
     118{
     119}
     120#endif
     121
    116122FloatPoint ScrollAnimator::currentPosition() const
    117123{
  • trunk/Source/WebCore/platform/ScrollAnimator.h

    r76757 r76956  
    4141class ScrollableArea;
    4242
     43#if ENABLE(GESTURE_EVENTS)
     44class PlatformGestureEvent;
     45#endif
     46
    4347class ScrollAnimator {
    4448public:
     
    5660
    5761    virtual void handleWheelEvent(PlatformWheelEvent&);
     62#if ENABLE(GESTURE_EVENTS)
     63    virtual void handleGestureEvent(const PlatformGestureEvent&);
     64#endif
    5865
    5966    FloatPoint currentPosition() const;
  • trunk/Source/WebCore/platform/ScrollView.cpp

    r76832 r76956  
    5656    , m_clipsRepaints(true)
    5757    , m_delegatesScrolling(false)
    58     , m_constrainsScrollingToContentEdge(true)
    5958{
    6059    platformInit();
     
    398397{
    399398    return scroll(logicalToPhysical(direction, isVerticalDocument(), isFlippedDocument()), granularity);
     399}
     400
     401IntSize ScrollView::overhangAmount() const
     402{
     403    IntSize stretch;
     404    if (scrollY() < 0)
     405        stretch.setHeight(scrollY());
     406    else if (scrollY() > contentsHeight() - visibleContentRect().height())
     407        stretch.setHeight(scrollY() - (contentsHeight() - visibleContentRect().height()));
     408
     409    if (scrollX() < 0)
     410        stretch.setWidth(scrollX());
     411    else if (scrollX() > contentsWidth() - visibleContentRect().width())
     412        stretch.setWidth(scrollX() - (contentsWidth() - visibleContentRect().width()));
     413
     414    return stretch;
    400415}
    401416
     
    738753    ScrollableArea::handleWheelEvent(e);
    739754}
     755
     756#if ENABLE(GESTURE_EVENTS)
     757void ScrollView::gestureEvent(const PlatformGestureEvent& gestureEvent)
     758{
     759    if (platformWidget())
     760        return;
     761
     762    ScrollableArea::handleGestureEvent(gestureEvent);
     763}
     764#endif
    740765
    741766void ScrollView::setFrameRect(const IntRect& newRect)
  • trunk/Source/WebCore/platform/ScrollView.h

    r76831 r76956  
    5252
    5353class HostWindow;
    54 class PlatformWheelEvent;
    5554class Scrollbar;
    5655
     
    164163    virtual void setContentsSize(const IntSize&);
    165164
    166     // Functions for controlling if you can scroll past the end of the document.
    167     bool constrainsScrollingToContentEdge() const { return m_constrainsScrollingToContentEdge; }
    168     void setConstrainsScrollingToContentEdge(bool constrainsScrollingToContentEdge) { m_constrainsScrollingToContentEdge = constrainsScrollingToContentEdge; }
    169 
    170165    // Functions for querying the current scrolled position (both as a point, a size, or as individual X and Y values).
    171166    IntPoint scrollPosition() const { return visibleContentRect().location(); }
     
    177172    int scrollX() const { return scrollPosition().x(); }
    178173    int scrollY() const { return scrollPosition().y(); }
    179    
     174
     175    IntSize overhangAmount() const;
     176
    180177    // Functions for scrolling the view.
    181178    void setScrollPosition(const IntPoint&);
     
    233230    // (like Windows), we need this function in order to do the scroll ourselves.
    234231    void wheelEvent(PlatformWheelEvent&);
     232#if ENABLE(GESTURE_EVENTS)
     233    void gestureEvent(const PlatformGestureEvent&);
     234#endif
    235235
    236236    IntPoint convertChildToSelf(const Widget* child, const IntPoint& point) const
     
    339339    bool m_clipsRepaints;
    340340    bool m_delegatesScrolling;
    341 
    342     bool m_constrainsScrollingToContentEdge;
    343341
    344342    // There are 8 possible combinations of writing mode and direction.  Scroll origin will be non-zero in the x or y axis
  • trunk/Source/WebCore/platform/ScrollableArea.cpp

    r76757 r76956  
    4242ScrollableArea::ScrollableArea()
    4343    : m_scrollAnimator(ScrollAnimator::create(this))
     44    , m_constrainsScrollingToContentEdge(true)
    4445{
    4546}
     
    114115}
    115116
     117#if ENABLE(GESTURE_EVENTS)
     118void ScrollableArea::handleGestureEvent(const PlatformGestureEvent& gestureEvent)
     119{
     120    m_scrollAnimator->handleGestureEvent(gestureEvent);
     121}
     122#endif
     123
    116124void ScrollableArea::setScrollOffsetFromAnimation(const IntPoint& offset)
    117125{
  • trunk/Source/WebCore/platform/ScrollableArea.h

    r76757 r76956  
    3737class ScrollAnimator;
    3838
     39#if ENABLE(GESTURE_EVENTS)
     40class PlatformGestureEvent;
     41#endif
     42
    3943class ScrollableArea {
    4044public:
     
    4953
    5054    void handleWheelEvent(PlatformWheelEvent&);
     55#if ENABLE(GESTURE_EVENTS)
     56    void handleGestureEvent(const PlatformGestureEvent&);
     57#endif
     58
     59    // Functions for controlling if you can scroll past the end of the document.
     60    bool constrainsScrollingToContentEdge() const { return m_constrainsScrollingToContentEdge; }
     61    void setConstrainsScrollingToContentEdge(bool constrainsScrollingToContentEdge) { m_constrainsScrollingToContentEdge = constrainsScrollingToContentEdge; }
    5162
    5263    virtual int scrollSize(ScrollbarOrientation) const = 0;
     
    93104    virtual int visibleWidth() const { ASSERT_NOT_REACHED(); return 0; }
    94105
     106    virtual IntSize contentsSize() const { ASSERT_NOT_REACHED(); return IntSize(); }
     107
     108    virtual IntSize overhangAmount() const { ASSERT_NOT_REACHED(); return IntSize(); }
     109
    95110private:
    96111    // NOTE: Only called from the ScrollAnimator.
     
    99114
    100115    OwnPtr<ScrollAnimator> m_scrollAnimator;
     116    bool m_constrainsScrollingToContentEdge;
    101117};
    102118
  • trunk/Source/WebCore/platform/mac/ScrollAnimatorMac.h

    r76378 r76956  
    11/*
    2  * Copyright (C) 2010 Apple Inc. All rights reserved.
     2 * Copyright (C) 2010, 2011 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    2929#if ENABLE(SMOOTH_SCROLLING)
    3030
     31#include "FloatPoint.h"
     32#include "FloatSize.h"
    3133#include "ScrollAnimator.h"
     34#include "Timer.h"
    3235#include <wtf/RetainPtr.h>
    3336
     
    4851    virtual void scrollToOffsetWithoutAnimation(const FloatPoint&);
    4952
    50     // Called by the ScrollAnimationHelperDelegate.
     53#if ENABLE(RUBBER_BANDING)
     54    virtual void handleWheelEvent(PlatformWheelEvent&);
     55#if ENABLE(GESTURE_EVENTS)
     56    virtual void handleGestureEvent(const PlatformGestureEvent&);
     57#endif
     58#endif
     59
    5160    void immediateScrollToPoint(const FloatPoint& newPosition);
     61    void immediateScrollByDeltaX(float deltaX);
     62    void immediateScrollByDeltaY(float deltaY);
    5263
    5364private:
    5465    RetainPtr<id> m_scrollAnimationHelper;
    5566    RetainPtr<ScrollAnimationHelperDelegate> m_scrollAnimationHelperDelegate;
     67
     68#if ENABLE(RUBBER_BANDING)
     69    bool allowsVerticalStretching() const;
     70    bool allowsHorizontalStretching() const;
     71    bool pinnedInDirection(float deltaX, float deltaY);
     72    void snapRubberBand();
     73    void snapRubberBandTimerFired(Timer<ScrollAnimatorMac>*);
     74    void smoothScrollWithEvent(PlatformWheelEvent&);
     75    void beginScrollGesture();
     76    void endScrollGesture();
     77
     78    bool m_inScrollGesture;
     79    bool m_momentumScrollInProgress;
     80    bool m_ignoreMomentumScrolls;
     81    CFTimeInterval m_lastMomemtumScrollTimestamp;
     82    FloatSize m_overflowScrollDelta;
     83    FloatSize m_stretchScrollForce;
     84    FloatSize m_momentumVelocity;
     85
     86    // Rubber band state.
     87    CFTimeInterval m_startTime;
     88    FloatSize m_startStretch;
     89    FloatPoint m_origOrigin;
     90    FloatSize m_origVelocity;
     91    Timer<ScrollAnimatorMac> m_snapRubberBandTimer;
     92#endif
    5693};
    5794
  • trunk/Source/WebCore/platform/mac/ScrollAnimatorMac.mm

    r76378 r76956  
    11/*
    2  * Copyright (C) 2010 Apple Inc. All rights reserved.
     2 * Copyright (C) 2010, 2011 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    3131
    3232#include "FloatPoint.h"
     33#include "PlatformWheelEvent.h"
     34#include "PlatformGestureEvent.h"
    3335#include "ScrollableArea.h"
    3436#include <wtf/PassOwnPtr.h>
     
    123125@end
    124126
     127
    125128namespace WebCore {
    126129
     
    132135ScrollAnimatorMac::ScrollAnimatorMac(ScrollableArea* scrollableArea)
    133136    : ScrollAnimator(scrollableArea)
     137#if ENABLE(RUBBER_BANDING)
     138    , m_inScrollGesture(false)
     139    , m_momentumScrollInProgress(false)
     140    , m_ignoreMomentumScrolls(false)
     141    , m_lastMomemtumScrollTimestamp(0)
     142    , m_startTime(0)
     143    , m_snapRubberBandTimer(this, &ScrollAnimatorMac::snapRubberBandTimerFired)
     144#endif
    134145{
    135146    m_scrollAnimationHelperDelegate.adoptNS([[ScrollAnimationHelperDelegate alloc] initWithScrollAnimator:this]);
     
    178189}
    179190
     191void ScrollAnimatorMac::immediateScrollByDeltaX(float deltaX)
     192{
     193    m_currentPosX += deltaX;
     194    notityPositionChanged();
     195}
     196
     197void ScrollAnimatorMac::immediateScrollByDeltaY(float deltaY)
     198{
     199    m_currentPosY += deltaY;
     200    notityPositionChanged();
     201}
     202
     203#if ENABLE(RUBBER_BANDING)
     204
     205static const double scrollVelocityZeroingTimeout = 0.10;
     206static const double rubberbandStiffness = 20.0;
     207static const double rubberbandDirectionLockStretchRatio = 1.0;
     208static const double rubberbandMinimumRequiredDeltaBeforeStretch = 10.0;
     209static const double rubberbandAmplitude = 0.31;
     210static const double rubberbandPeriod = 1.6;
     211
     212static float elasticDeltaForTimeDelta(float initialPosition, float initialVelocity, float elapsedTime)
     213{
     214    float amplitude = rubberbandAmplitude;
     215    float period = rubberbandPeriod;
     216    float criticalDampeningFactor = exp((-elapsedTime * rubberbandStiffness) / period);
     217             
     218    return (initialPosition + (-initialVelocity * elapsedTime * amplitude)) * criticalDampeningFactor;
     219}
     220
     221static float elasticDeltaForReboundDelta(float delta)
     222{
     223    float stiffness = std::max(rubberbandStiffness, 1.0);
     224    return delta / stiffness;
     225}
     226
     227static float reboundDeltaForElasticDelta(float delta)
     228{
     229    return delta * rubberbandStiffness;
     230}
     231
     232static float scrollWheelMultiplier()
     233{
     234    static float multiplier = -1.0;
     235    if (multiplier < 0) {
     236        multiplier = [[NSUserDefaults standardUserDefaults] floatForKey:@"NSScrollWheelMultiplier"];
     237        if (multiplier <= 0)
     238            multiplier = 1;
     239    }
     240    return multiplier;
     241}
     242
     243void ScrollAnimatorMac::handleWheelEvent(PlatformWheelEvent& wheelEvent)
     244{
     245    if (!wheelEvent.hasPreciseScrollingDeltas()) {
     246        ScrollAnimator::handleWheelEvent(wheelEvent);
     247        return;
     248    }
     249
     250    wheelEvent.accept();
     251
     252    bool isMometumScrollEvent = (wheelEvent.phase() != PlatformWheelEventPhaseNone);
     253    if (m_ignoreMomentumScrolls && (isMometumScrollEvent || m_snapRubberBandTimer.isActive())) {
     254        if (wheelEvent.phase() == PlatformWheelEventPhaseEnded)
     255            m_ignoreMomentumScrolls = false;
     256        return;
     257    }
     258
     259    smoothScrollWithEvent(wheelEvent);
     260}
     261
     262void ScrollAnimatorMac::handleGestureEvent(const PlatformGestureEvent& gestureEvent)
     263{
     264    if (gestureEvent.type() == PlatformGestureEvent::ScrollBeginType)
     265        beginScrollGesture();
     266    else
     267        endScrollGesture();
     268}
     269
     270bool ScrollAnimatorMac::pinnedInDirection(float deltaX, float deltaY)
     271{
     272    FloatSize limitDelta;
     273    if (fabsf(deltaY) >= fabsf(deltaX)) {
     274        if (deltaY < 0) {
     275            // We are trying to scroll up.  Make sure we are not pinned to the top
     276            limitDelta.setHeight(m_scrollableArea->visibleContentRect().y());
     277        } else {
     278            // We are trying to scroll down.  Make sure we are not pinned to the bottom
     279            limitDelta.setHeight(m_scrollableArea->contentsSize().height() - m_scrollableArea->visibleContentRect().bottom());
     280        }
     281    } else if (deltaX != 0) {
     282        if (deltaX < 0) {
     283            // We are trying to scroll left.  Make sure we are not pinned to the left
     284            limitDelta.setWidth(m_scrollableArea->visibleContentRect().x());
     285        } else {
     286            // We are trying to scroll right.  Make sure we are not pinned to the right
     287            limitDelta.setWidth(m_scrollableArea->contentsSize().width() - m_scrollableArea->visibleContentRect().right());
     288        }
     289    }
     290   
     291    if ((deltaX != 0 || deltaY != 0) && (limitDelta.width() < 1 && limitDelta.height() < 1))
     292        return true;
     293    return false;
     294}
     295
     296bool ScrollAnimatorMac::allowsVerticalStretching() const
     297{
     298    Scrollbar* hScroller = m_scrollableArea->horizontalScrollbar();
     299    Scrollbar* vScroller = m_scrollableArea->verticalScrollbar();
     300    if (((vScroller && vScroller->enabled()) || (!hScroller || !hScroller->enabled())))
     301        return true;
     302
     303    return false;
     304}
     305
     306bool ScrollAnimatorMac::allowsHorizontalStretching() const
     307{
     308    Scrollbar* hScroller = m_scrollableArea->horizontalScrollbar();
     309    Scrollbar* vScroller = m_scrollableArea->verticalScrollbar();
     310    if (((hScroller && hScroller->enabled()) || (!vScroller || !vScroller->enabled())))
     311        return true;
     312
     313    return false;
     314}
     315
     316void ScrollAnimatorMac::smoothScrollWithEvent(PlatformWheelEvent& wheelEvent)
     317{
     318    float deltaX = m_overflowScrollDelta.width();
     319    float deltaY = m_overflowScrollDelta.height();
     320
     321    // Reset overflow values because we may decide to remove delta at various points and put it into overflow.
     322    m_overflowScrollDelta = FloatSize();
     323
     324    float eventCoallescedDeltaX = -wheelEvent.deltaX();
     325    float eventCoallescedDeltaY = -wheelEvent.deltaY();
     326
     327    deltaX += eventCoallescedDeltaX;
     328    deltaY += eventCoallescedDeltaY;
     329
     330    // Slightly prefer scrolling vertically by applying the = case to deltaY
     331    if (fabsf(deltaY) >= fabsf(deltaX))
     332        deltaX = 0.0;
     333    else
     334        deltaY = 0.0;
     335   
     336    bool isVerticallyStretched = false;
     337    bool isHorizontallyStretched = false;
     338    bool shouldStretch = false;
     339   
     340    IntSize stretchAmount = m_scrollableArea->overhangAmount();
     341
     342    isHorizontallyStretched = (stretchAmount.width() == 0.0) ? false : true;
     343    isVerticallyStretched = (stretchAmount.height() == 0.0) ? false : true;
     344
     345    PlatformWheelEventPhase phase = wheelEvent.phase();
     346
     347    // If we are starting momentum scrolling then do some setup.
     348    if (!m_momentumScrollInProgress && (phase == PlatformWheelEventPhaseBegan || phase == PlatformWheelEventPhaseChanged))
     349        m_momentumScrollInProgress = true;
     350
     351    CFTimeInterval timeDelta = wheelEvent.timestamp() - m_lastMomemtumScrollTimestamp;
     352    if (m_inScrollGesture || m_momentumScrollInProgress) {
     353        if (m_lastMomemtumScrollTimestamp && timeDelta > 0.0 && timeDelta < scrollVelocityZeroingTimeout) {
     354            m_momentumVelocity.setWidth(eventCoallescedDeltaX / timeDelta);
     355            m_momentumVelocity.setHeight(eventCoallescedDeltaY / timeDelta);
     356            m_lastMomemtumScrollTimestamp = wheelEvent.timestamp();
     357        } else {
     358            m_lastMomemtumScrollTimestamp = wheelEvent.timestamp();
     359            m_momentumVelocity = FloatSize();
     360        }
     361
     362        if (isVerticallyStretched) {
     363            if (!isHorizontallyStretched && pinnedInDirection(deltaX, 0)) {               
     364                // Stretching only in the vertical.
     365                if (deltaY != 0.0 && (fabsf(deltaX / deltaY) < rubberbandDirectionLockStretchRatio))
     366                    deltaX = 0.0;
     367                else if (fabsf(deltaX) < rubberbandMinimumRequiredDeltaBeforeStretch) {
     368                    m_overflowScrollDelta.setWidth(m_overflowScrollDelta.width() + deltaX);
     369                    deltaX = 0.0;
     370                } else
     371                    m_overflowScrollDelta.setWidth(m_overflowScrollDelta.width() + deltaX);
     372            }
     373        } else if (isHorizontallyStretched) {
     374            // Stretching only in the horizontal.
     375            if (pinnedInDirection(0, deltaY)) {
     376                if (deltaX != 0.0 && (fabsf(deltaY / deltaX) < rubberbandDirectionLockStretchRatio))
     377                    deltaY = 0.0;
     378                else if (fabsf(deltaY) < rubberbandMinimumRequiredDeltaBeforeStretch) {
     379                    m_overflowScrollDelta.setHeight(m_overflowScrollDelta.height() + deltaY);
     380                    deltaY = 0.0;
     381                } else
     382                    m_overflowScrollDelta.setHeight(m_overflowScrollDelta.height() + deltaY);
     383            }
     384        } else {
     385            // Not stretching at all yet.
     386            if (pinnedInDirection(deltaX, deltaY)) {
     387                if (fabsf(deltaY) >= fabsf(deltaX)) {
     388                    if (fabsf(deltaX) < rubberbandMinimumRequiredDeltaBeforeStretch) {
     389                        m_overflowScrollDelta.setWidth(m_overflowScrollDelta.width() + deltaX);
     390                        deltaX = 0.0;
     391                    } else
     392                        m_overflowScrollDelta.setWidth(m_overflowScrollDelta.width() + deltaX);
     393                }
     394                shouldStretch = true;
     395            }
     396        }
     397    }
     398
     399    if (deltaX != 0.0 || deltaY != 0.0) {
     400        if (!(shouldStretch || isVerticallyStretched || isHorizontallyStretched)) {
     401            if (deltaY != 0) {
     402                deltaY *= scrollWheelMultiplier();
     403                immediateScrollByDeltaY(deltaY);
     404            }
     405            if (deltaX != 0) {
     406                deltaX *= scrollWheelMultiplier();
     407                immediateScrollByDeltaX(deltaX);
     408            }
     409        } else {
     410            if (!allowsHorizontalStretching()) {
     411                deltaX = 0.0;
     412                eventCoallescedDeltaX = 0.0;
     413            } else if ((deltaX != 0) && !isHorizontallyStretched && !pinnedInDirection(deltaX, 0)) {
     414                deltaX *= scrollWheelMultiplier();
     415
     416                m_scrollableArea->setConstrainsScrollingToContentEdge(false);
     417                immediateScrollByDeltaX(deltaX);
     418                m_scrollableArea->setConstrainsScrollingToContentEdge(true);
     419
     420                deltaX = 0.0;
     421            }
     422           
     423            if (!allowsVerticalStretching()) {
     424                deltaY = 0.0;
     425                eventCoallescedDeltaY = 0.0;
     426            } else if ((deltaY != 0) && !isVerticallyStretched && !pinnedInDirection(0, deltaY)) {
     427                deltaY *= scrollWheelMultiplier();
     428
     429                m_scrollableArea->setConstrainsScrollingToContentEdge(false);
     430                immediateScrollByDeltaY(deltaY);
     431                m_scrollableArea->setConstrainsScrollingToContentEdge(true);
     432
     433                deltaY = 0.0;
     434            }
     435           
     436            IntSize stretchAmount = m_scrollableArea->overhangAmount();
     437       
     438            if (m_momentumScrollInProgress) {
     439                if ((pinnedInDirection(eventCoallescedDeltaX, eventCoallescedDeltaY) || (fabsf(eventCoallescedDeltaX) + fabsf(eventCoallescedDeltaY) <= 0)) && m_lastMomemtumScrollTimestamp) {
     440                    m_ignoreMomentumScrolls = true;
     441                    m_momentumScrollInProgress = false;
     442                    snapRubberBand();
     443                }
     444            }
     445
     446            m_stretchScrollForce.setWidth(m_stretchScrollForce.width() + deltaX);
     447            m_stretchScrollForce.setHeight(m_stretchScrollForce.height() + deltaY);
     448
     449            FloatSize dampedDelta(ceil(elasticDeltaForReboundDelta(m_stretchScrollForce.width())), ceil(elasticDeltaForReboundDelta(m_stretchScrollForce.height())));
     450            FloatPoint origOrigin = m_scrollableArea->visibleContentRect().location() - stretchAmount;
     451            FloatPoint newOrigin = origOrigin + dampedDelta;
     452
     453            if (origOrigin != newOrigin) {
     454                m_scrollableArea->setConstrainsScrollingToContentEdge(false);
     455                immediateScrollToPoint(newOrigin);
     456                m_scrollableArea->setConstrainsScrollingToContentEdge(true);
     457            }
     458        }
     459    }
     460
     461    if (m_momentumScrollInProgress && phase == PlatformWheelEventPhaseEnded) {
     462        m_momentumScrollInProgress = false;
     463        m_ignoreMomentumScrolls = false;
     464        m_lastMomemtumScrollTimestamp = 0.0;
     465    }
     466}
     467
     468void ScrollAnimatorMac::beginScrollGesture()
     469{
     470    m_inScrollGesture = true;
     471    m_momentumScrollInProgress = false;
     472    m_ignoreMomentumScrolls = false;
     473    m_lastMomemtumScrollTimestamp = 0.0;
     474    m_momentumVelocity = FloatSize();
     475
     476    IntSize stretchAmount = m_scrollableArea->overhangAmount();
     477    m_stretchScrollForce.setWidth(reboundDeltaForElasticDelta(stretchAmount.width()));
     478    m_stretchScrollForce.setHeight(reboundDeltaForElasticDelta(stretchAmount.height()));
     479
     480    m_overflowScrollDelta = FloatSize();
     481   
     482    if (m_snapRubberBandTimer.isActive())
     483        m_snapRubberBandTimer.stop();
     484}
     485
     486void ScrollAnimatorMac::endScrollGesture()
     487{
     488    snapRubberBand();
     489}
     490
     491void ScrollAnimatorMac::snapRubberBand()
     492{
     493    CFTimeInterval timeDelta = [[NSProcessInfo processInfo] systemUptime] - m_lastMomemtumScrollTimestamp;
     494    if (m_lastMomemtumScrollTimestamp && timeDelta >= scrollVelocityZeroingTimeout)
     495        m_momentumVelocity = FloatSize();
     496
     497    m_inScrollGesture = false;
     498
     499    if (m_snapRubberBandTimer.isActive())
     500        return;
     501
     502    m_startTime = [NSDate timeIntervalSinceReferenceDate];
     503    m_startStretch = FloatSize();
     504    m_origOrigin = FloatPoint();
     505    m_origVelocity = FloatSize();
     506
     507    m_snapRubberBandTimer.startRepeating(1.0/60.0);
     508}
     509
     510static inline double roundTowardZero(double num)
     511{
     512    return num > 0.0 ? ceil(num - 0.5) : floor(num + 0.5);
     513}
     514
     515static inline double roundToDevicePixelTowardZero(double num)
     516{
     517    double roundedNum = round(num);
     518    if (fabs(num - roundedNum) < 0.125) {
     519        num = roundedNum;
     520    }
     521
     522    return roundTowardZero(num);
     523}
     524
     525void ScrollAnimatorMac::snapRubberBandTimerFired(Timer<ScrollAnimatorMac>*)
     526{
     527    if (!m_momentumScrollInProgress || m_ignoreMomentumScrolls) {
     528        CFTimeInterval timeDelta = [NSDate timeIntervalSinceReferenceDate] - m_startTime;
     529
     530        if (m_startStretch == FloatSize()) {
     531            m_startStretch = m_scrollableArea->overhangAmount();
     532            if (m_startStretch == FloatSize()) {   
     533                m_snapRubberBandTimer.stop();
     534                m_stretchScrollForce = FloatSize();
     535                m_startTime = 0;
     536                m_startStretch = FloatSize();
     537                m_origOrigin = FloatPoint();
     538                m_origVelocity = FloatSize();
     539
     540                return;
     541            }
     542
     543            m_origOrigin = m_scrollableArea->visibleContentRect().location() - m_startStretch;
     544            m_origVelocity = m_momentumVelocity;
     545
     546            // Just like normal scrolling, prefer vertical rubberbanding
     547            if (fabsf(m_origVelocity.height()) >= fabsf(m_origVelocity.width()))
     548                m_origVelocity.setWidth(0);
     549           
     550            // Don't rubber-band horizontally if it's not possible to scroll horizontally
     551            Scrollbar* hScroller = m_scrollableArea->horizontalScrollbar();
     552            if (!hScroller || !hScroller->enabled())
     553                m_origVelocity.setWidth(0);
     554           
     555            // Don't rubber-band vertically if it's not possible to scroll horizontally
     556            Scrollbar* vScroller = m_scrollableArea->verticalScrollbar();
     557            if (!vScroller || !vScroller->enabled())
     558                m_origVelocity.setHeight(0);
     559        }
     560
     561        FloatPoint delta(roundToDevicePixelTowardZero(elasticDeltaForTimeDelta(m_startStretch.width(), -m_origVelocity.width(), timeDelta)),
     562                         roundToDevicePixelTowardZero(elasticDeltaForTimeDelta(m_startStretch.height(), -m_origVelocity.height(), timeDelta)));
     563
     564        if (fabs(delta.x()) >= 1.0 || fabs(delta.y()) >= 1.0) {
     565            FloatPoint newOrigin = m_origOrigin + delta;
     566
     567            m_scrollableArea->setConstrainsScrollingToContentEdge(false);
     568            immediateScrollToPoint(newOrigin);
     569            m_scrollableArea->setConstrainsScrollingToContentEdge(true);
     570
     571            FloatSize newStretch = m_scrollableArea->overhangAmount();
     572           
     573            m_stretchScrollForce.setWidth(reboundDeltaForElasticDelta(newStretch.width()));
     574            m_stretchScrollForce.setHeight(reboundDeltaForElasticDelta(newStretch.height()));
     575        } else {
     576            immediateScrollToPoint(m_origOrigin);
     577
     578            m_snapRubberBandTimer.stop();
     579            m_stretchScrollForce = FloatSize();
     580           
     581            m_startTime = 0;
     582            m_startStretch = FloatSize();
     583            m_origOrigin = FloatPoint();
     584            m_origVelocity = FloatSize();
     585        }
     586    } else {
     587        m_startTime = [NSDate timeIntervalSinceReferenceDate];
     588        m_startStretch = FloatSize();
     589    }
     590}
     591#endif
     592
    180593} // namespace WebCore
    181594
Note: See TracChangeset for help on using the changeset viewer.