InputQueue.h (12211B)
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_InputQueue_h 8 #define mozilla_layers_InputQueue_h 9 10 #include "APZUtils.h" 11 #include "DragTracker.h" 12 #include "InputData.h" 13 #include "mozilla/EventForwards.h" 14 #include "mozilla/layers/TouchCounter.h" 15 #include "mozilla/RefPtr.h" 16 #include "mozilla/UniquePtr.h" 17 #include "nsTArray.h" 18 19 #include <unordered_map> 20 21 namespace mozilla { 22 23 class InputData; 24 class MultiTouchInput; 25 class ScrollWheelInput; 26 27 namespace layers { 28 29 class AsyncPanZoomController; 30 class InputBlockState; 31 class CancelableBlockState; 32 class TouchBlockState; 33 class WheelBlockState; 34 class DragBlockState; 35 class PanGestureBlockState; 36 class PinchGestureBlockState; 37 class KeyboardBlockState; 38 class AsyncDragMetrics; 39 class QueuedInput; 40 struct APZEventResult; 41 struct APZHandledResult; 42 enum class BrowserGestureResponse : bool; 43 44 using InputBlockCallback = std::function<void(uint64_t aInputBlockId, 45 APZHandledResult aHandledResult)>; 46 47 struct InputBlockCallbackInfo { 48 nsEventStatus mEagerStatus; 49 InputBlockCallback mCallback; 50 }; 51 52 class InputQueueIterator { 53 using Iterator = nsTArray<UniquePtr<QueuedInput>>::iterator; 54 55 public: 56 InputQueueIterator() : mCurrent(), mEnd() {} // "null" iterator 57 InputQueueIterator(Iterator aCurrent, Iterator aEnd) 58 : mCurrent(aCurrent), mEnd(aEnd) {} 59 60 explicit operator bool() const { return mCurrent != mEnd; } 61 QueuedInput* operator*() const { return mCurrent->get(); } 62 QueuedInput* operator->() const { return mCurrent->get(); } 63 void operator++() { ++mCurrent; } 64 65 private: 66 Iterator mCurrent; 67 Iterator mEnd; 68 }; 69 70 /** 71 * This class stores incoming input events, associated with "input blocks", 72 * until they are ready for handling. 73 */ 74 class InputQueue { 75 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(InputQueue) 76 77 public: 78 InputQueue(); 79 80 /** 81 * Notifies the InputQueue of a new incoming input event. The APZC that the 82 * input event was targeted to should be provided in the |aTarget| parameter. 83 * See the documentation on APZCTreeManager::ReceiveInputEvent for info on 84 * return values from this function. 85 */ 86 APZEventResult ReceiveInputEvent( 87 const RefPtr<AsyncPanZoomController>& aTarget, 88 TargetConfirmationFlags aFlags, InputData& aEvent, 89 const Maybe<nsTArray<TouchBehaviorFlags>>& aTouchBehaviors = Nothing()); 90 /** 91 * This function should be invoked to notify the InputQueue when web content 92 * decides whether or not it wants to cancel a block of events. The block 93 * id to which this applies should be provided in |aInputBlockId|. 94 */ 95 void ContentReceivedInputBlock(uint64_t aInputBlockId, bool aPreventDefault); 96 /** 97 * This function should be invoked to notify the InputQueue once the target 98 * APZC to handle an input block has been confirmed. In practice this should 99 * generally be decidable upon receipt of the input event, but in some cases 100 * we may need to query the layout engine to know for sure. The input block 101 * this applies to should be specified via the |aInputBlockId| parameter. 102 */ 103 void SetConfirmedTargetApzc( 104 uint64_t aInputBlockId, 105 const RefPtr<AsyncPanZoomController>& aTargetApzc); 106 /** 107 * This function is invoked to confirm that the drag block should be handled 108 * by the APZ. 109 */ 110 void ConfirmDragBlock(uint64_t aInputBlockId, 111 const RefPtr<AsyncPanZoomController>& aTargetApzc, 112 const AsyncDragMetrics& aDragMetrics); 113 /** 114 * This function should be invoked to notify the InputQueue of the touch- 115 * action properties for the different touch points in an input block. The 116 * input block this applies to should be specified by the |aInputBlockId| 117 * parameter. If touch-action is not enabled on the platform, this function 118 * does nothing and need not be called. 119 */ 120 void SetAllowedTouchBehavior(uint64_t aInputBlockId, 121 const nsTArray<TouchBehaviorFlags>& aBehaviors); 122 /** 123 * Adds a new touch block at the end of the input queue that has the same 124 * allowed touch behaviour flags as the the touch block currently being 125 * processed. This should only be called when processing of a touch block 126 * triggers the creation of a new touch block. Returns the input block id 127 * of the the newly-created block. 128 */ 129 uint64_t InjectNewTouchBlock(AsyncPanZoomController* aTarget); 130 /** 131 * Returns the pending input block at the head of the queue, if there is one. 132 * This may return null if there all input events have been processed. 133 */ 134 InputBlockState* GetCurrentBlock() const; 135 /* 136 * Returns the current pending input block as a specific kind of block. If 137 * GetCurrentBlock() returns null, these functions additionally check the 138 * mActiveXXXBlock field of the corresponding input type to see if there is 139 * a depleted but still active input block, and returns that if found. These 140 * functions may return null if no block is found. 141 */ 142 TouchBlockState* GetCurrentTouchBlock() const; 143 WheelBlockState* GetCurrentWheelBlock() const; 144 DragBlockState* GetCurrentDragBlock() const; 145 PanGestureBlockState* GetCurrentPanGestureBlock() const; 146 PinchGestureBlockState* GetCurrentPinchGestureBlock() const; 147 KeyboardBlockState* GetCurrentKeyboardBlock() const; 148 /** 149 * Returns true iff the pending block at the head of the queue is a touch 150 * block and is ready for handling. 151 */ 152 bool HasReadyTouchBlock() const; 153 /** 154 * If there is an active wheel transaction, returns the WheelBlockState 155 * representing the transaction. Otherwise, returns null. "Active" in this 156 * function name is the same kind of "active" as in mActiveWheelBlock - that 157 * is, new incoming wheel events will go into the "active" block. 158 */ 159 WheelBlockState* GetActiveWheelTransaction() const; 160 /** 161 * Remove all input blocks from the input queue. 162 */ 163 void Clear(); 164 /** 165 * Whether the current pending block allows scroll handoff. 166 */ 167 bool AllowScrollHandoff() const; 168 /** 169 * If there is currently a drag in progress, return whether or not it was 170 * targeted at a scrollbar. If the drag was newly-created and doesn't know, 171 * use the provided |aOnScrollbar| to populate that information. 172 */ 173 bool IsDragOnScrollbar(bool aOnScrollbar); 174 175 InputBlockState* GetBlockForId(uint64_t aInputBlockId); 176 177 void AddInputBlockCallback(uint64_t aInputBlockId, 178 InputBlockCallback&& aCallback); 179 180 void SetBrowserGestureResponse(uint64_t aInputBlockId, 181 BrowserGestureResponse aResponse); 182 183 private: 184 ~InputQueue(); 185 186 // RAII class for automatically running a timeout task that may 187 // need to be run immediately after an event has been queued. 188 class AutoRunImmediateTimeout final { 189 public: 190 explicit AutoRunImmediateTimeout(InputQueue* aQueue); 191 ~AutoRunImmediateTimeout(); 192 193 private: 194 InputQueue* mQueue; 195 }; 196 197 TouchBlockState* StartNewTouchBlock( 198 const RefPtr<AsyncPanZoomController>& aTarget, 199 TargetConfirmationFlags aFlags); 200 201 TouchBlockState* StartNewTouchBlockForLongTap( 202 const RefPtr<AsyncPanZoomController>& aTarget); 203 204 /** 205 * If animations are present for the current pending input block, cancel 206 * them as soon as possible. 207 */ 208 void CancelAnimationsForNewBlock(InputBlockState* aBlock, 209 CancelAnimationFlags aExtraFlags = Default); 210 211 /** 212 * If we need to wait for a content response, schedule that now. Returns true 213 * if the timeout was scheduled, false otherwise. 214 */ 215 bool MaybeRequestContentResponse( 216 const RefPtr<AsyncPanZoomController>& aTarget, 217 CancelableBlockState* aBlock); 218 219 APZEventResult ReceiveTouchInput( 220 const RefPtr<AsyncPanZoomController>& aTarget, 221 TargetConfirmationFlags aFlags, const MultiTouchInput& aEvent, 222 const Maybe<nsTArray<TouchBehaviorFlags>>& aTouchBehaviors); 223 APZEventResult ReceiveMouseInput( 224 const RefPtr<AsyncPanZoomController>& aTarget, 225 TargetConfirmationFlags aFlags, MouseInput& aEvent); 226 APZEventResult ReceiveScrollWheelInput( 227 const RefPtr<AsyncPanZoomController>& aTarget, 228 TargetConfirmationFlags aFlags, const ScrollWheelInput& aEvent); 229 APZEventResult ReceivePanGestureInput( 230 const RefPtr<AsyncPanZoomController>& aTarget, 231 TargetConfirmationFlags aFlags, const PanGestureInput& aEvent); 232 APZEventResult ReceivePinchGestureInput( 233 const RefPtr<AsyncPanZoomController>& aTarget, 234 TargetConfirmationFlags aFlags, const PinchGestureInput& aEvent); 235 APZEventResult ReceiveKeyboardInput( 236 const RefPtr<AsyncPanZoomController>& aTarget, 237 TargetConfirmationFlags aFlags, const KeyboardInput& aEvent); 238 239 /** 240 * Helper function that searches mQueuedInputs for the first block matching 241 * the given id, and returns it. If |aOutFirstInput| is non-null, it is 242 * populated with a pointer to the first input in mQueuedInputs that 243 * corresponds to the block, or null if no such input was found. Note that 244 * even if there are no inputs in mQueuedInputs, this function can return 245 * non-null if the block id provided matches one of the depleted-but-still- 246 * active blocks (mActiveTouchBlock, mActiveWheelBlock, etc.). 247 */ 248 InputBlockState* FindBlockForId(uint64_t aInputBlockId, 249 InputQueueIterator* aOutFirstInput); 250 void ScheduleMainThreadTimeout(const RefPtr<AsyncPanZoomController>& aTarget, 251 CancelableBlockState* aBlock); 252 void MainThreadTimeout(uint64_t aInputBlockId); 253 void MaybeLongTapTimeout(uint64_t aInputBlockId); 254 255 // Returns true if there's one more queued event we need to process as a 256 // result of switching the active block back to the original touch block from 257 // the touch block for long-tap. 258 bool ProcessQueue(); 259 bool CanDiscardBlock(InputBlockState* aBlock); 260 void UpdateActiveApzc(const RefPtr<AsyncPanZoomController>& aNewActive); 261 262 private: 263 // The queue of input events that have not yet been fully processed. 264 // This member must only be accessed on the controller/UI thread. 265 nsTArray<UniquePtr<QueuedInput>> mQueuedInputs; 266 267 // These are the most recently created blocks of each input type. They are 268 // "active" in the sense that new inputs of that type are associated with 269 // them. Note that these pointers may be null if no inputs of the type have 270 // arrived, or if the inputs for the type formed a complete block that was 271 // then discarded. 272 RefPtr<TouchBlockState> mActiveTouchBlock; 273 RefPtr<WheelBlockState> mActiveWheelBlock; 274 RefPtr<DragBlockState> mActiveDragBlock; 275 RefPtr<PanGestureBlockState> mActivePanGestureBlock; 276 RefPtr<PinchGestureBlockState> mActivePinchGestureBlock; 277 RefPtr<KeyboardBlockState> mActiveKeyboardBlock; 278 279 // In the case where a long-tap event triggered by keeping touching happens 280 // we need to keep both the touch block for the long-tap and the original 281 // touch block started with `touch-start`. This value holds the original block 282 // until the long-tap block is processed. 283 RefPtr<TouchBlockState> mPrevActiveTouchBlock; 284 285 // The APZC to which the last event was delivered 286 RefPtr<AsyncPanZoomController> mLastActiveApzc; 287 288 // Track touches so we know when to clear mLastActiveApzc 289 TouchCounter mTouchCounter; 290 291 // Track mouse inputs so we know if we're in a drag or not 292 DragTracker mDragTracker; 293 294 // Temporarily stores a timeout task that needs to be run as soon as 295 // as the event that triggered it has been queued. 296 RefPtr<Runnable> mImmediateTimeout; 297 298 // Maps input block ids to callbacks that will be invoked when the input block 299 // is ready for handling. 300 using InputBlockCallbackMap = 301 std::unordered_map<uint64_t, InputBlockCallback>; 302 InputBlockCallbackMap mInputBlockCallbacks; 303 }; 304 305 } // namespace layers 306 } // namespace mozilla 307 308 #endif // mozilla_layers_InputQueue_h