summaryrefslogtreecommitdiffstats
path: root/gfx/layers/apz/src/OverscrollHandoffState.h
blob: 28c89edd7448b35aa9377e297eb86c59c03e8ad6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef mozilla_layers_OverscrollHandoffChain_h
#define mozilla_layers_OverscrollHandoffChain_h

#include <vector>
#include "mozilla/RefPtr.h"   // for RefPtr
#include "nsISupportsImpl.h"  // for NS_INLINE_DECL_THREADSAFE_REFCOUNTING
#include "APZUtils.h"         // for CancelAnimationFlags
#include "mozilla/layers/LayersTypes.h"  // for Layer::ScrollDirection
#include "Units.h"                       // for ScreenPoint

namespace mozilla {

class InputData;

namespace layers {

class AsyncPanZoomController;

/**
 * This class represents the chain of APZCs along which overscroll is handed
 * off. It is created by APZCTreeManager by starting from an initial APZC which
 * is the target for input events, and following the scroll parent ID links
 * (often but not always corresponding to parent pointers in the APZC tree),
 * then adjusting for scrollgrab.
 */
class OverscrollHandoffChain {
 protected:
  // Reference-counted classes cannot have public destructors.
  ~OverscrollHandoffChain();

 public:
  // Threadsafe so that the controller and sampler threads can both maintain
  // nsRefPtrs to the same handoff chain.
  // Mutable so that we can pass around the class by
  // RefPtr<const OverscrollHandoffChain> and thus enforce that, once built,
  // the chain is not modified.
  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(OverscrollHandoffChain)

  /*
   * Methods for building the handoff chain.
   * These should be used only by
   * AsyncPanZoomController::BuildOverscrollHandoffChain().
   */
  void Add(AsyncPanZoomController* aApzc);
  void SortByScrollPriority();

  /*
   * Methods for accessing the handoff chain.
   */
  uint32_t Length() const { return mChain.size(); }
  const RefPtr<AsyncPanZoomController>& GetApzcAtIndex(uint32_t aIndex) const;
  // Returns Length() if |aApzc| is not on this chain.
  uint32_t IndexOf(const AsyncPanZoomController* aApzc) const;

  /*
   * Convenience methods for performing operations on APZCs in the chain.
   */

  // Flush repaints all the way up the chain.
  void FlushRepaints() const;

  // Cancel animations all the way up the chain.
  void CancelAnimations(CancelAnimationFlags aFlags = Default) const;

  // Clear overscroll all the way up the chain.
  void ClearOverscroll() const;

  // Snap back the APZC that is overscrolled on the subset of the chain from
  // |aStart| onwards, if any.
  void SnapBackOverscrolledApzc(const AsyncPanZoomController* aStart) const;

  // Similar to above SnapbackOverscrolledApzc but for pan gestures with
  // momentum events, this function doesn't end up calling each APZC's
  // ScrollSnap.
  // |aVelocity| is the initial velocity of |aStart|.
  void SnapBackOverscrolledApzcForMomentum(
      const AsyncPanZoomController* aStart,
      const ParentLayerPoint& aVelocity) const;

  // Determine whether the given APZC, or any APZC further in the chain,
  // has room to be panned.
  bool CanBePanned(const AsyncPanZoomController* aApzc) const;

  // Determine whether the given APZC, or any APZC further in the chain,
  // can scroll in the given direction.
  bool CanScrollInDirection(const AsyncPanZoomController* aApzc,
                            ScrollDirection aDirection) const;

  // Determine whether any APZC along this handoff chain is overscrolled.
  bool HasOverscrolledApzc() const;

  // Determine whether any APZC along this handoff chain has been flung fast.
  bool HasFastFlungApzc() const;

  // Determine whether any APZC along this handoff chain is autoscroll.
  bool HasAutoscrollApzc() const;

  // Find the first APZC in this handoff chain that can be scrolled by |aInput|.
  // Since overscroll-behavior can restrict handoff in some directions,
  // |aOutAllowedScrollDirections| is populated with the scroll directions
  // in which scrolling of the returned APZC is allowed.
  // |aIncludeOverscroll| is an optional flag whether to consider overscrollable
  // as scrollable or not.
  enum class IncludeOverscroll : bool { No, Yes };
  RefPtr<AsyncPanZoomController> FindFirstScrollable(
      const InputData& aInput, ScrollDirections* aOutAllowedScrollDirections,
      IncludeOverscroll aIncludeOverscroll = IncludeOverscroll::Yes) const;

  // Return a pair of true and the root content APZC if all non-root APZCs in
  // this handoff chain starting from |aApzc| are not able to scroll downwards
  // (i.e. there is no room to scroll downwards in each APZC respectively) and
  // there is any contents covered by the dynamic toolbar, otherwise return a
  // pair of false and nullptr.
  std::tuple<bool, const AsyncPanZoomController*>
  ScrollingDownWillMoveDynamicToolbar(
      const AsyncPanZoomController* aApzc) const;

  bool ScrollingUpWillTriggerPullToRefresh(
      const AsyncPanZoomController* aApzc) const;

 private:
  std::vector<RefPtr<AsyncPanZoomController>> mChain;

  typedef void (AsyncPanZoomController::*APZCMethod)();
  typedef bool (AsyncPanZoomController::*APZCPredicate)() const;
  void ForEachApzc(APZCMethod aMethod) const;
  bool AnyApzc(APZCPredicate aPredicate) const;
};

/**
 * This class groups the state maintained during overscroll handoff.
 */
struct OverscrollHandoffState {
  OverscrollHandoffState(const OverscrollHandoffChain& aChain,
                         const ScreenPoint& aPanDistance,
                         ScrollSource aScrollSource)
      : mChain(aChain),
        mChainIndex(0),
        mPanDistance(aPanDistance),
        mScrollSource(aScrollSource) {}

  // The chain of APZCs along which we hand off scroll.
  // This is const to indicate that the chain does not change over the
  // course of handoff.
  const OverscrollHandoffChain& mChain;

  // The index of the APZC in the chain that we are currently giving scroll to.
  // This is non-const to indicate that this changes over the course of handoff.
  uint32_t mChainIndex;

  // The total distance since touch-start of the pan that triggered the
  // handoff. This is const to indicate that it does not change over the
  // course of handoff.
  // The x/y components of this are non-negative.
  const ScreenPoint mPanDistance;

  ScrollSource mScrollSource;

  // The total amount of actual movement that this scroll caused, including
  // scrolling and changes to overscroll. This starts at zero and is accumulated
  // over the course of the handoff.
  ScreenPoint mTotalMovement;
};

/*
 * This class groups the state maintained during fling handoff.
 */
struct FlingHandoffState {
  // The velocity of the fling being handed off.
  ParentLayerPoint mVelocity;

  // The chain of APZCs along which we hand off the fling.
  // Unlike in OverscrollHandoffState, this is stored by RefPtr because
  // otherwise it may not stay alive for the entire handoff.
  RefPtr<const OverscrollHandoffChain> mChain;

  // The time duration between the touch start and the touch move that started
  // the pan gesture which triggered this fling. In other words, the time it
  // took for the finger to move enough to cross the touch slop threshold.
  // Nothing if this fling was not immediately caused by a touch pan.
  Maybe<TimeDuration> mTouchStartRestingTime;

  // The slowest panning velocity encountered during the pan that triggered this
  // fling.
  ParentLayerCoord mMinPanVelocity;

  // Whether handoff has happened by this point, or we're still process
  // the original fling.
  bool mIsHandoff;

  // The single APZC that was scrolled by the pan that started this fling.
  // The fling is only allowed to scroll this APZC, too.
  // Used only if immediate scroll handoff is disallowed.
  RefPtr<const AsyncPanZoomController> mScrolledApzc;
};

}  // namespace layers
}  // namespace mozilla

#endif /* mozilla_layers_OverscrollHandoffChain_h */