tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

GenericFlingAnimation.h (8915B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #ifndef mozilla_layers_GenericFlingAnimation_h_
      8 #define mozilla_layers_GenericFlingAnimation_h_
      9 
     10 #include "APZUtils.h"
     11 #include "AsyncPanZoomAnimation.h"
     12 #include "AsyncPanZoomController.h"
     13 #include "FrameMetrics.h"
     14 #include "Units.h"
     15 #include "OverscrollHandoffState.h"
     16 #include "mozilla/Assertions.h"
     17 #include "mozilla/Monitor.h"
     18 #include "mozilla/RefPtr.h"
     19 #include "mozilla/StaticPrefs_apz.h"
     20 #include "mozilla/TimeStamp.h"
     21 #include "mozilla/ToString.h"
     22 #include "nsThreadUtils.h"
     23 
     24 static mozilla::LazyLogModule sApzFlgLog("apz.fling");
     25 #define FLING_LOG(...) MOZ_LOG(sApzFlgLog, LogLevel::Debug, (__VA_ARGS__))
     26 
     27 namespace mozilla {
     28 namespace layers {
     29 
     30 /**
     31 * The FlingPhysics template parameter determines the physics model
     32 * that the fling animation follows. It must have the following methods:
     33 *
     34 *   - Default constructor.
     35 *
     36 *   - Init(const ParentLayerPoint& aStartingVelocity, float aPLPPI).
     37 *     Called at the beginning of the fling, with the fling's starting velocity,
     38 *     and the number of ParentLayer pixels per (Screen) inch at the point of
     39 *     the fling's start in the fling's direction.
     40 *
     41 *   - Sample(const TimeDuration& aDelta,
     42 *            ParentLayerPoint* aOutVelocity,
     43 *            ParentLayerPoint* aOutOffset);
     44 *     Called on each sample of the fling.
     45 *     |aDelta| is the time elapsed since the last sample.
     46 *     |aOutVelocity| should be the desired velocity after the current sample,
     47 *                    in ParentLayer pixels per millisecond.
     48 *     |aOutOffset| should be the desired _delta_ to the scroll offset after
     49 *     the current sample. |aOutOffset| should _not_ be clamped to the APZC's
     50 *     scrollable bounds; the caller will do the clamping, and it needs to
     51 *     know the unclamped value to handle handoff/overscroll correctly.
     52 */
     53 template <typename FlingPhysics>
     54 class GenericFlingAnimation : public AsyncPanZoomAnimation,
     55                              public FlingPhysics {
     56 public:
     57  GenericFlingAnimation(AsyncPanZoomController& aApzc,
     58                        const FlingHandoffState& aHandoffState, float aPLPPI)
     59      : mApzc(aApzc),
     60        mOverscrollHandoffChain(aHandoffState.mChain),
     61        mScrolledApzc(aHandoffState.mScrolledApzc) {
     62    MOZ_ASSERT(mOverscrollHandoffChain);
     63 
     64    // Drop any velocity on axes where we don't have room to scroll anyways
     65    // (in this APZC, or an APZC further in the handoff chain).
     66    // This ensures that we don't take the 'overscroll' path in Sample()
     67    // on account of one axis which can't scroll having a velocity.
     68    if (!mOverscrollHandoffChain->CanScrollInDirection(
     69            &mApzc, ScrollDirection::eHorizontal)) {
     70      RecursiveMutexAutoLock lock(mApzc.mRecursiveMutex);
     71      mApzc.mX.SetVelocity(0);
     72    }
     73    if (!mOverscrollHandoffChain->CanScrollInDirection(
     74            &mApzc, ScrollDirection::eVertical)) {
     75      RecursiveMutexAutoLock lock(mApzc.mRecursiveMutex);
     76      mApzc.mY.SetVelocity(0);
     77    }
     78 
     79    if (aHandoffState.mIsHandoff) {
     80      // Only apply acceleration in the APZC that originated the fling, not in
     81      // APZCs further down the handoff chain during handoff.
     82      mApzc.mFlingAccelerator.Reset();
     83    }
     84 
     85    ParentLayerPoint velocity =
     86        mApzc.mFlingAccelerator.GetFlingStartingVelocity(
     87            aApzc.GetFrameTime(), mApzc.GetVelocityVector(), aHandoffState);
     88 
     89    mApzc.SetVelocityVector(velocity);
     90 
     91    FlingPhysics::Init(mApzc.GetVelocityVector(), aPLPPI);
     92  }
     93 
     94  /**
     95   * Advances a fling by an interpolated amount based on the passed in |aDelta|.
     96   * This should be called whenever sampling the content transform for this
     97   * frame. Returns true if the fling animation should be advanced by one frame,
     98   * or false if there is no fling or the fling has ended.
     99   */
    100  virtual bool DoSample(FrameMetrics& aFrameMetrics,
    101                        const TimeDuration& aDelta) override {
    102    CSSToParentLayerScale zoom(aFrameMetrics.GetZoom());
    103    if (zoom == CSSToParentLayerScale(0)) {
    104      return false;
    105    }
    106 
    107    ParentLayerPoint velocity;
    108    ParentLayerPoint offset;
    109    FlingPhysics::Sample(aDelta, &velocity, &offset);
    110 
    111    mApzc.SetVelocityVector(velocity);
    112 
    113    // If we shouldn't continue the fling, let's just stop and repaint.
    114    if (IsZero(velocity / zoom)) {
    115      FLING_LOG("%p ending fling animation. overscrolled=%d\n", &mApzc,
    116                mApzc.IsOverscrolled());
    117      // This APZC or an APZC further down the handoff chain may be be
    118      // overscrolled. Start a snap-back animation on the overscrolled APZC.
    119      // Note:
    120      //   This needs to be a deferred task even though it can safely run
    121      //   while holding mRecursiveMutex, because otherwise, if the overscrolled
    122      //   APZC is this one, then the SetState(NOTHING) in UpdateAnimation will
    123      //   stomp on the SetState(SNAP_BACK) it does.
    124      mDeferredTasks.AppendElement(NewRunnableMethod<AsyncPanZoomController*>(
    125          "layers::OverscrollHandoffChain::SnapBackOverscrolledApzc",
    126          mOverscrollHandoffChain.get(),
    127          &OverscrollHandoffChain::SnapBackOverscrolledApzc, &mApzc));
    128      return false;
    129    }
    130 
    131    // Ordinarily we might need to do a ScheduleComposite if either of
    132    // the following AdjustDisplacement calls returns true, but this
    133    // is already running as part of a FlingAnimation, so we'll be compositing
    134    // per frame of animation anyway.
    135    ParentLayerPoint overscroll;
    136    ParentLayerPoint adjustedOffset;
    137    mApzc.mX.AdjustDisplacement(offset.x, adjustedOffset.x, overscroll.x);
    138    mApzc.mY.AdjustDisplacement(offset.y, adjustedOffset.y, overscroll.y);
    139    if (aFrameMetrics.GetZoom() != CSSToParentLayerScale(0)) {
    140      mApzc.ScrollBy(adjustedOffset / aFrameMetrics.GetZoom());
    141    }
    142 
    143    // The fling may have caused us to reach the end of our scroll range.
    144    if (!IsZero(overscroll / zoom)) {
    145      // Hand off the fling to the next APZC in the overscroll handoff chain.
    146 
    147      // We may have reached the end of the scroll range along one axis but
    148      // not the other. In such a case we only want to hand off the relevant
    149      // component of the fling.
    150      if (mApzc.IsZero(overscroll.x)) {
    151        velocity.x = 0;
    152      } else if (mApzc.IsZero(overscroll.y)) {
    153        velocity.y = 0;
    154      }
    155 
    156      // To hand off the fling, we attempt to find a target APZC and start a new
    157      // fling with the same velocity on that APZC. For simplicity, the actual
    158      // overscroll of the current sample is discarded rather than being handed
    159      // off. The compositor should sample animations sufficiently frequently
    160      // that this is not noticeable. The target APZC is chosen by seeing if
    161      // there is an APZC further in the handoff chain which is pannable; if
    162      // there isn't, we take the new fling ourselves, entering an overscrolled
    163      // state.
    164      // Note: APZC is holding mRecursiveMutex, so directly calling
    165      // HandleFlingOverscroll() (which acquires the tree lock) would violate
    166      // the lock ordering. Instead we schedule HandleFlingOverscroll() to be
    167      // called after mRecursiveMutex is released.
    168      FLING_LOG("%p fling went into overscroll, handing off with velocity %s\n",
    169                &mApzc, ToString(velocity).c_str());
    170      mDeferredTasks.AppendElement(
    171          NewRunnableMethod<ParentLayerPoint, SideBits,
    172                            RefPtr<const OverscrollHandoffChain>,
    173                            RefPtr<const AsyncPanZoomController>>(
    174              "layers::AsyncPanZoomController::HandleFlingOverscroll", &mApzc,
    175              &AsyncPanZoomController::HandleFlingOverscroll, velocity,
    176              apz::GetOverscrollSideBits(overscroll), mOverscrollHandoffChain,
    177              mScrolledApzc));
    178 
    179      // If there is a remaining velocity on this APZC, continue this fling
    180      // as well. (This fling and the handed-off fling will run concurrently.)
    181      // Note that AdjustDisplacement() will have zeroed out the velocity
    182      // along the axes where we're overscrolled.
    183      return !IsZero(mApzc.GetVelocityVector() / zoom);
    184    }
    185 
    186    return true;
    187  }
    188 
    189  void Cancel(CancelAnimationFlags aFlags) override {
    190    mApzc.mFlingAccelerator.ObserveFlingCanceled(mApzc.GetVelocityVector());
    191  }
    192 
    193  virtual bool HandleScrollOffsetUpdate(
    194      const Maybe<CSSPoint>& aRelativeDelta) override {
    195    return true;
    196  }
    197 
    198 private:
    199  AsyncPanZoomController& mApzc;
    200  RefPtr<const OverscrollHandoffChain> mOverscrollHandoffChain;
    201  RefPtr<const AsyncPanZoomController> mScrolledApzc;
    202 };
    203 
    204 }  // namespace layers
    205 }  // namespace mozilla
    206 
    207 #endif  // mozilla_layers_GenericFlingAnimation_h_