tor-browser

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

Axis.h (17587B)


      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_Axis_h
      8 #define mozilla_layers_Axis_h
      9 
     10 #include <sys/types.h>  // for int32_t
     11 
     12 #include "APZUtils.h"
     13 #include "AxisPhysicsMSDModel.h"
     14 #include "mozilla/DataMutex.h"  // for DataMutex
     15 #include "mozilla/gfx/Types.h"  // for Side
     16 #include "mozilla/TimeStamp.h"  // for TimeDuration
     17 #include "nsTArray.h"           // for nsTArray
     18 #include "Units.h"
     19 
     20 namespace mozilla {
     21 namespace layers {
     22 
     23 const float EPSILON = 0.0001f;
     24 
     25 /**
     26 * Compare two coordinates for equality, accounting for rounding error.
     27 * Use both FuzzyEqualsAdditive() with COORDINATE_EPISLON, which accounts for
     28 * things like the error introduced by rounding during a round-trip to app
     29 * units, and FuzzyEqualsMultiplicative(), which accounts for accumulated error
     30 * due to floating-point operations (which can be larger than COORDINATE_EPISLON
     31 * for sufficiently large coordinate values).
     32 */
     33 bool FuzzyEqualsCoordinate(CSSCoord aValue1, CSSCoord aValue2);
     34 
     35 struct FrameMetrics;
     36 class AsyncPanZoomController;
     37 
     38 /**
     39 * Interface for computing velocities along the axis based on
     40 * position samples.
     41 */
     42 class VelocityTracker {
     43 public:
     44  virtual ~VelocityTracker() = default;
     45 
     46  /**
     47   * Start tracking velocity along this axis, starting with the given
     48   * initial position and corresponding timestamp.
     49   */
     50  virtual void StartTracking(ParentLayerCoord aPos, TimeStamp aTimestamp) = 0;
     51  /**
     52   * Record a new position along this axis, at the given timestamp.
     53   * Returns the average velocity between the last sample and this one, or
     54   * or Nothing() if a reasonable average cannot be computed.
     55   */
     56  virtual Maybe<float> AddPosition(ParentLayerCoord aPos,
     57                                   TimeStamp aTimestamp) = 0;
     58  /**
     59   * Compute an estimate of the axis's current velocity, based on recent
     60   * position samples. It's up to implementation how many samples to consider
     61   * and how to perform the computation.
     62   * If the tracker doesn't have enough samples to compute a result, it
     63   * may return Nothing{}.
     64   */
     65  virtual Maybe<float> ComputeVelocity(TimeStamp aTimestamp) = 0;
     66  /**
     67   * Clear all state in the velocity tracker.
     68   */
     69  virtual void Clear() = 0;
     70 };
     71 
     72 /**
     73 * Helper class to maintain each axis of movement (X,Y) for panning and zooming.
     74 * Note that everything here is specific to one axis; that is, the X axis knows
     75 * nothing about the Y axis and vice versa.
     76 */
     77 class Axis {
     78 public:
     79  explicit Axis(AsyncPanZoomController* aAsyncPanZoomController);
     80 
     81  /**
     82   * Notify this Axis that a new touch has been received, including a timestamp
     83   * for when the touch was received. This triggers a recalculation of velocity.
     84   * This can also used for pan gesture events. For those events, |aPos| is
     85   * an invented position corresponding to the mouse position plus any
     86   * accumulated displacements over the course of the pan gesture.
     87   */
     88  void UpdateWithTouchAtDevicePoint(ParentLayerCoord aPos,
     89                                    TimeStamp aTimestamp);
     90 
     91 public:
     92  /**
     93   * Notify this Axis that a touch has begun, i.e. the user has put their finger
     94   * on the screen but has not yet tried to pan.
     95   */
     96  void StartTouch(ParentLayerCoord aPos, TimeStamp aTimestamp);
     97 
     98  /**
     99   * Helper enum class for specifying if EndTouch() should clear the axis lock.
    100   */
    101  enum class ClearAxisLock { Yes, No };
    102 
    103  /**
    104   * Notify this Axis that a touch has ended gracefully. This may perform
    105   * recalculations of the axis velocity.
    106   */
    107  void EndTouch(TimeStamp aTimestamp, ClearAxisLock aClearAxisLock);
    108 
    109  /**
    110   * Notify this Axis that the gesture has ended forcefully. Useful for stopping
    111   * flings when a user puts their finger down in the middle of one (i.e. to
    112   * stop a previous touch including its fling so that a new one can take its
    113   * place).
    114   */
    115  void CancelGesture();
    116 
    117  /**
    118   * Takes a requested displacement to the position of this axis, and adjusts it
    119   * to account for overscroll (which might decrease the displacement; this is
    120   * to prevent the viewport from overscrolling the page rect), and axis locking
    121   * (which might prevent any displacement from happening). If overscroll
    122   * ocurred, its amount is written to |aOverscrollAmountOut|.
    123   * The |aDisplacementOut| parameter is set to the adjusted displacement, and
    124   * the function returns true if and only if internal overscroll amounts were
    125   * changed.
    126   */
    127  bool AdjustDisplacement(ParentLayerCoord aDisplacement,
    128                          ParentLayerCoord& aDisplacementOut,
    129                          ParentLayerCoord& aOverscrollAmountOut,
    130                          bool aForceOverscroll = false);
    131 
    132  /**
    133   * Overscrolls this axis by the requested amount in the requested direction.
    134   * The axis must be at the end of its scroll range in this direction.
    135   */
    136  void OverscrollBy(ParentLayerCoord aOverscroll);
    137 
    138  /**
    139   * Return the amount of overscroll on this axis, in ParentLayer pixels.
    140   *
    141   * If this amount is nonzero, the relevant component of
    142   * mAsyncPanZoomController->Metrics().mScrollOffset must be at its
    143   * extreme allowed value in the relevant direction (that is, it must be at
    144   * its maximum value if we are overscrolled at our composition length, and
    145   * at its minimum value if we are overscrolled at the origin).
    146   */
    147  ParentLayerCoord GetOverscroll() const;
    148 
    149  /**
    150   * Restore the amount by which this axis is overscrolled to the specified
    151   * amount. This is for test-related use; overscrolling as a result of user
    152   * input should happen via OverscrollBy().
    153   */
    154  void RestoreOverscroll(ParentLayerCoord aOverscroll);
    155 
    156  /**
    157   * Start an overscroll animation with the given initial velocity.
    158   */
    159  void StartOverscrollAnimation(float aVelocity);
    160 
    161  /**
    162   * Sample the snap-back animation to relieve overscroll.
    163   * |aDelta| is the time since the last sample, |aOverscrollSideBits| is
    164   * the direction where the overscroll happens on this axis.
    165   */
    166  bool SampleOverscrollAnimation(const TimeDuration& aDelta,
    167                                 SideBits aOverscrollSideBits);
    168 
    169  /**
    170   * Stop an overscroll animation.
    171   */
    172  void EndOverscrollAnimation();
    173 
    174  /**
    175   * Return whether this axis is overscrolled in either direction.
    176   */
    177  bool IsOverscrolled() const;
    178 
    179  /**
    180   * Return true if this axis is overscrolled but its scroll offset
    181   * has changed in a way that makes the oversrolled state no longer
    182   * valid (for example, it is overscrolled at the top but the
    183   * scroll offset is no longer zero).
    184   */
    185  bool IsInInvalidOverscroll() const;
    186 
    187  /**
    188   * Clear any overscroll amount on this axis.
    189   */
    190  void ClearOverscroll();
    191 
    192  /**
    193   * Returns whether the overscroll animation is alive.
    194   */
    195  bool IsOverscrollAnimationAlive() const;
    196 
    197  /**
    198   * Returns whether the overscroll animation is running.
    199   * Note that unlike the above IsOverscrollAnimationAlive, this function
    200   * returns false even if the animation is still there but is very close to
    201   * the destination position and its velocity is quite low, i.e. it's time to
    202   * finish.
    203   */
    204  bool IsOverscrollAnimationRunning() const;
    205 
    206  /**
    207   * Gets the starting position of the touch supplied in StartTouch().
    208   */
    209  ParentLayerCoord PanStart() const;
    210 
    211  /**
    212   * Gets the distance between the starting position of the touch supplied in
    213   * StartTouch() and the current touch from the last
    214   * UpdateWithTouchAtDevicePoint().
    215   */
    216  ParentLayerCoord PanDistance() const;
    217 
    218  /**
    219   * Gets the distance between the starting position of the touch supplied in
    220   * StartTouch() and the supplied position.
    221   */
    222  ParentLayerCoord PanDistance(ParentLayerCoord aPos) const;
    223 
    224  /**
    225   * Returns true if the page has room to be scrolled along this axis.
    226   */
    227  bool CanScroll() const;
    228 
    229  /**
    230   * Returns whether this axis can scroll any more in a particular direction.
    231   */
    232  bool CanScroll(CSSCoord aDelta) const;
    233  bool CanScroll(ParentLayerCoord aDelta) const;
    234 
    235  /**
    236   * Returns true if the page has room to be scrolled along this axis
    237   * and this axis is not scroll-locked.
    238   */
    239  bool CanScrollNow() const;
    240 
    241  /**
    242   * Clamp a point to the page's scrollable bounds. That is, a scroll
    243   * destination to the returned point will not contain any overscroll.
    244   */
    245  CSSCoord ClampOriginToScrollableRect(CSSCoord aOrigin) const;
    246 
    247  /**
    248   * Gets the raw velocity of this axis at this moment.
    249   */
    250  float GetVelocity() const;
    251 
    252  /**
    253   * Sets the raw velocity of this axis at this moment.
    254   * Intended to be called only when the axis "takes over" a velocity from
    255   * another APZC, in which case there are no touch points available to call
    256   * UpdateWithTouchAtDevicePoint. In other circumstances,
    257   * UpdateWithTouchAtDevicePoint should be used and the velocity calculated
    258   * there.
    259   */
    260  void SetVelocity(float aVelocity);
    261 
    262  /**
    263   * If a displacement will overscroll the axis, this returns the amount and in
    264   * what direction.
    265   */
    266  ParentLayerCoord DisplacementWillOverscrollAmount(
    267      ParentLayerCoord aDisplacement) const;
    268 
    269  /**
    270   * If a scale will overscroll the axis, this returns the amount and in what
    271   * direction.
    272   *
    273   * |aFocus| is the point at which the scale is focused at. We will offset the
    274   * scroll offset in such a way that it remains in the same place on the page
    275   * relative.
    276   *
    277   * Note: Unlike most other functions in Axis, this functions operates in
    278   *       CSS coordinates so there is no confusion as to whether the
    279   *       ParentLayer coordinates it operates in are before or after the scale
    280   *       is applied.
    281   */
    282  CSSCoord ScaleWillOverscrollAmount(float aScale, CSSCoord aFocus) const;
    283 
    284  /**
    285   * Checks if an axis will overscroll in both directions by computing the
    286   * content rect and checking that its height/width (depending on the axis)
    287   * does not overextend past the viewport.
    288   *
    289   * This gets called by ScaleWillOverscroll().
    290   */
    291  bool ScaleWillOverscrollBothSides(float aScale) const;
    292 
    293  /**
    294   * Returns true if movement on this axis is locked.
    295   */
    296  bool IsAxisLocked() const;
    297 
    298  /**
    299   * Set whether or not the axis is locked.
    300   */
    301  void SetAxisLocked(bool aAxisLocked);
    302 
    303  ParentLayerCoord GetOrigin() const;
    304  ParentLayerCoord GetCompositionLength() const;
    305  ParentLayerCoord GetPageStart() const;
    306  ParentLayerCoord GetPageLength() const;
    307  ParentLayerCoord GetCompositionEnd() const;
    308  ParentLayerCoord GetPageEnd() const;
    309  ParentLayerCoord GetScrollRangeEnd() const;
    310 
    311  bool IsScrolledToStart() const;
    312  bool IsScrolledToEnd() const;
    313 
    314  ParentLayerCoord GetPos() const { return mPos; }
    315 
    316  bool OverscrollBehaviorAllowsHandoff() const;
    317  bool OverscrollBehaviorAllowsOverscrollEffect() const;
    318 
    319  virtual CSSToParentLayerScale GetAxisScale(
    320      const CSSToParentLayerScale2D& aScale) const = 0;
    321  virtual CSSCoord GetPointOffset(const CSSPoint& aPoint) const = 0;
    322  virtual OuterCSSCoord GetPointOffset(const OuterCSSPoint& aPoint) const = 0;
    323  virtual ParentLayerCoord GetPointOffset(
    324      const ParentLayerPoint& aPoint) const = 0;
    325  virtual ParentLayerCoord GetRectLength(
    326      const ParentLayerRect& aRect) const = 0;
    327  virtual CSSCoord GetRectLength(const CSSRect& aRect) const = 0;
    328  virtual ParentLayerCoord GetRectOffset(
    329      const ParentLayerRect& aRect) const = 0;
    330  virtual CSSCoord GetRectOffset(const CSSRect& aRect) const = 0;
    331  virtual float GetTransformScale(
    332      const AsyncTransformComponentMatrix& aMatrix) const = 0;
    333  virtual ParentLayerCoord GetTransformTranslation(
    334      const AsyncTransformComponentMatrix& aMatrix) const = 0;
    335  virtual void PostScale(AsyncTransformComponentMatrix& aMatrix,
    336                         float aScale) const = 0;
    337  virtual void PostTranslate(AsyncTransformComponentMatrix& aMatrix,
    338                             ParentLayerCoord aTranslation) const = 0;
    339 
    340  virtual ScreenPoint MakePoint(ScreenCoord aCoord) const = 0;
    341 
    342  const void* OpaqueApzcPointer() const { return mAsyncPanZoomController; }
    343 
    344  virtual const char* Name() const = 0;
    345 
    346  // Convert a velocity from global inches/ms into ParentLayerCoords/ms.
    347  float ToLocalVelocity(float aVelocityInchesPerMs) const;
    348 
    349 protected:
    350  // A position along the axis, used during input event processing to
    351  // track velocities (and for touch gestures, to track the length of
    352  // the gesture). For touch events, this represents the position of
    353  // the finger (or in the case of two-finger scrolling, the midpoint
    354  // of the two fingers). For pan gesture events, this represents an
    355  // invented position corresponding to the mouse position at the start
    356  // of the pan, plus deltas representing the displacement of the pan.
    357  ParentLayerCoord mPos;
    358 
    359  ParentLayerCoord mStartPos;
    360  // The velocity can be accessed from multiple threads (e.g. APZ
    361  // controller thread and APZ sampler thread), so needs to be
    362  // protected by a mutex.
    363  // Units: ParentLayerCoords per millisecond
    364  mutable DataMutex<float> mVelocity;
    365  // Whether movement on this axis is locked.
    366  mutable DataMutex<bool> mAxisLocked;
    367  AsyncPanZoomController* mAsyncPanZoomController;
    368 
    369  // The amount by which we are overscrolled; see GetOverscroll().
    370  ParentLayerCoord mOverscroll;
    371 
    372  // The mass-spring-damper model for overscroll physics.
    373  AxisPhysicsMSDModel mMSDModel;
    374 
    375  // Used to track velocity over a series of input events and compute
    376  // a resulting velocity to use for e.g. starting a fling animation.
    377  // This member can only be accessed on the controller/UI thread.
    378  UniquePtr<VelocityTracker> mVelocityTracker;
    379 
    380  float DoGetVelocity() const;
    381  void DoSetVelocity(float aVelocity);
    382 
    383  const FrameMetrics& GetFrameMetrics() const;
    384  const ScrollMetadata& GetScrollMetadata() const;
    385 
    386  // Do not use this function directly, use
    387  // AsyncPanZoomController::GetAllowedHandoffDirections instead.
    388  virtual OverscrollBehavior GetOverscrollBehavior() const = 0;
    389 
    390  // Adjust a requested overscroll amount for resistance, yielding a smaller
    391  // actual overscroll amount.
    392  ParentLayerCoord ApplyResistance(ParentLayerCoord aOverscroll) const;
    393 
    394  // Helper function for SampleOverscrollAnimation().
    395  void StepOverscrollAnimation(double aStepDurationMilliseconds);
    396 };
    397 
    398 class AxisX : public Axis {
    399 public:
    400  explicit AxisX(AsyncPanZoomController* mAsyncPanZoomController);
    401  CSSToParentLayerScale GetAxisScale(
    402      const CSSToParentLayerScale2D& aScale) const override;
    403  CSSCoord GetPointOffset(const CSSPoint& aPoint) const override;
    404  OuterCSSCoord GetPointOffset(const OuterCSSPoint& aPoint) const override;
    405  ParentLayerCoord GetPointOffset(
    406      const ParentLayerPoint& aPoint) const override;
    407  ParentLayerCoord GetRectLength(const ParentLayerRect& aRect) const override;
    408  CSSCoord GetRectLength(const CSSRect& aRect) const override;
    409  ParentLayerCoord GetRectOffset(const ParentLayerRect& aRect) const override;
    410  CSSCoord GetRectOffset(const CSSRect& aRect) const override;
    411  float GetTransformScale(
    412      const AsyncTransformComponentMatrix& aMatrix) const override;
    413  ParentLayerCoord GetTransformTranslation(
    414      const AsyncTransformComponentMatrix& aMatrix) const override;
    415  void PostScale(AsyncTransformComponentMatrix& aMatrix,
    416                 float aScale) const override;
    417  void PostTranslate(AsyncTransformComponentMatrix& aMatrix,
    418                     ParentLayerCoord aTranslation) const override;
    419  ScreenPoint MakePoint(ScreenCoord aCoord) const override;
    420  const char* Name() const override;
    421  bool CanScrollTo(Side aSide) const;
    422  SideBits ScrollableDirections() const;
    423 
    424 private:
    425  OverscrollBehavior GetOverscrollBehavior() const override;
    426 };
    427 
    428 class AxisY : public Axis {
    429 public:
    430  explicit AxisY(AsyncPanZoomController* mAsyncPanZoomController);
    431  CSSCoord GetPointOffset(const CSSPoint& aPoint) const override;
    432  OuterCSSCoord GetPointOffset(const OuterCSSPoint& aPoint) const override;
    433  ParentLayerCoord GetPointOffset(
    434      const ParentLayerPoint& aPoint) const override;
    435  CSSToParentLayerScale GetAxisScale(
    436      const CSSToParentLayerScale2D& aScale) const override;
    437  ParentLayerCoord GetRectLength(const ParentLayerRect& aRect) const override;
    438  CSSCoord GetRectLength(const CSSRect& aRect) const override;
    439  ParentLayerCoord GetRectOffset(const ParentLayerRect& aRect) const override;
    440  CSSCoord GetRectOffset(const CSSRect& aRect) const override;
    441  float GetTransformScale(
    442      const AsyncTransformComponentMatrix& aMatrix) const override;
    443  ParentLayerCoord GetTransformTranslation(
    444      const AsyncTransformComponentMatrix& aMatrix) const override;
    445  void PostScale(AsyncTransformComponentMatrix& aMatrix,
    446                 float aScale) const override;
    447  void PostTranslate(AsyncTransformComponentMatrix& aMatrix,
    448                     ParentLayerCoord aTranslation) const override;
    449  ScreenPoint MakePoint(ScreenCoord aCoord) const override;
    450  const char* Name() const override;
    451  bool CanScrollTo(Side aSide) const;
    452  bool CanVerticalScrollWithDynamicToolbar() const;
    453  SideBits ScrollableDirections() const;
    454  SideBits ScrollableDirectionsWithDynamicToolbar(
    455      const ScreenMargin& aFixedLayerMargins) const;
    456 
    457 private:
    458  OverscrollBehavior GetOverscrollBehavior() const override;
    459  ParentLayerCoord GetCompositionLengthWithoutDynamicToolbar() const;
    460  bool HasDynamicToolbar() const;
    461 };
    462 
    463 }  // namespace layers
    464 }  // namespace mozilla
    465 
    466 #endif