tor-browser

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

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