summaryrefslogtreecommitdiffstats
path: root/gfx/layers/apz/src/InputQueue.h
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/layers/apz/src/InputQueue.h')
-rw-r--r--gfx/layers/apz/src/InputQueue.h290
1 files changed, 290 insertions, 0 deletions
diff --git a/gfx/layers/apz/src/InputQueue.h b/gfx/layers/apz/src/InputQueue.h
new file mode 100644
index 0000000000..62515fc49d
--- /dev/null
+++ b/gfx/layers/apz/src/InputQueue.h
@@ -0,0 +1,290 @@
+/* -*- 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_InputQueue_h
+#define mozilla_layers_InputQueue_h
+
+#include "APZUtils.h"
+#include "DragTracker.h"
+#include "InputData.h"
+#include "mozilla/EventForwards.h"
+#include "mozilla/layers/TouchCounter.h"
+#include "mozilla/RefPtr.h"
+#include "mozilla/UniquePtr.h"
+#include "nsTArray.h"
+
+#include <unordered_map>
+
+namespace mozilla {
+
+class InputData;
+class MultiTouchInput;
+class ScrollWheelInput;
+
+namespace layers {
+
+class AsyncPanZoomController;
+class InputBlockState;
+class CancelableBlockState;
+class TouchBlockState;
+class WheelBlockState;
+class DragBlockState;
+class PanGestureBlockState;
+class PinchGestureBlockState;
+class KeyboardBlockState;
+class AsyncDragMetrics;
+class QueuedInput;
+struct APZEventResult;
+struct APZHandledResult;
+enum class BrowserGestureResponse : bool;
+
+using InputBlockCallback = std::function<void(uint64_t aInputBlockId,
+ APZHandledResult aHandledResult)>;
+
+struct InputBlockCallbackInfo {
+ nsEventStatus mEagerStatus;
+ InputBlockCallback mCallback;
+};
+
+/**
+ * This class stores incoming input events, associated with "input blocks",
+ * until they are ready for handling.
+ */
+class InputQueue {
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(InputQueue)
+
+ public:
+ InputQueue();
+
+ /**
+ * Notifies the InputQueue of a new incoming input event. The APZC that the
+ * input event was targeted to should be provided in the |aTarget| parameter.
+ * See the documentation on APZCTreeManager::ReceiveInputEvent for info on
+ * return values from this function.
+ */
+ APZEventResult ReceiveInputEvent(
+ const RefPtr<AsyncPanZoomController>& aTarget,
+ TargetConfirmationFlags aFlags, InputData& aEvent,
+ const Maybe<nsTArray<TouchBehaviorFlags>>& aTouchBehaviors = Nothing());
+ /**
+ * This function should be invoked to notify the InputQueue when web content
+ * decides whether or not it wants to cancel a block of events. The block
+ * id to which this applies should be provided in |aInputBlockId|.
+ */
+ void ContentReceivedInputBlock(uint64_t aInputBlockId, bool aPreventDefault);
+ /**
+ * This function should be invoked to notify the InputQueue once the target
+ * APZC to handle an input block has been confirmed. In practice this should
+ * generally be decidable upon receipt of the input event, but in some cases
+ * we may need to query the layout engine to know for sure. The input block
+ * this applies to should be specified via the |aInputBlockId| parameter.
+ */
+ void SetConfirmedTargetApzc(
+ uint64_t aInputBlockId,
+ const RefPtr<AsyncPanZoomController>& aTargetApzc);
+ /**
+ * This function is invoked to confirm that the drag block should be handled
+ * by the APZ.
+ */
+ void ConfirmDragBlock(uint64_t aInputBlockId,
+ const RefPtr<AsyncPanZoomController>& aTargetApzc,
+ const AsyncDragMetrics& aDragMetrics);
+ /**
+ * This function should be invoked to notify the InputQueue of the touch-
+ * action properties for the different touch points in an input block. The
+ * input block this applies to should be specified by the |aInputBlockId|
+ * parameter. If touch-action is not enabled on the platform, this function
+ * does nothing and need not be called.
+ */
+ void SetAllowedTouchBehavior(uint64_t aInputBlockId,
+ const nsTArray<TouchBehaviorFlags>& aBehaviors);
+ /**
+ * Adds a new touch block at the end of the input queue that has the same
+ * allowed touch behaviour flags as the the touch block currently being
+ * processed. This should only be called when processing of a touch block
+ * triggers the creation of a new touch block. Returns the input block id
+ * of the the newly-created block.
+ */
+ uint64_t InjectNewTouchBlock(AsyncPanZoomController* aTarget);
+ /**
+ * Returns the pending input block at the head of the queue, if there is one.
+ * This may return null if there all input events have been processed.
+ */
+ InputBlockState* GetCurrentBlock() const;
+ /*
+ * Returns the current pending input block as a specific kind of block. If
+ * GetCurrentBlock() returns null, these functions additionally check the
+ * mActiveXXXBlock field of the corresponding input type to see if there is
+ * a depleted but still active input block, and returns that if found. These
+ * functions may return null if no block is found.
+ */
+ TouchBlockState* GetCurrentTouchBlock() const;
+ WheelBlockState* GetCurrentWheelBlock() const;
+ DragBlockState* GetCurrentDragBlock() const;
+ PanGestureBlockState* GetCurrentPanGestureBlock() const;
+ PinchGestureBlockState* GetCurrentPinchGestureBlock() const;
+ KeyboardBlockState* GetCurrentKeyboardBlock() const;
+ /**
+ * Returns true iff the pending block at the head of the queue is a touch
+ * block and is ready for handling.
+ */
+ bool HasReadyTouchBlock() const;
+ /**
+ * If there is an active wheel transaction, returns the WheelBlockState
+ * representing the transaction. Otherwise, returns null. "Active" in this
+ * function name is the same kind of "active" as in mActiveWheelBlock - that
+ * is, new incoming wheel events will go into the "active" block.
+ */
+ WheelBlockState* GetActiveWheelTransaction() const;
+ /**
+ * Remove all input blocks from the input queue.
+ */
+ void Clear();
+ /**
+ * Whether the current pending block allows scroll handoff.
+ */
+ bool AllowScrollHandoff() const;
+ /**
+ * If there is currently a drag in progress, return whether or not it was
+ * targeted at a scrollbar. If the drag was newly-created and doesn't know,
+ * use the provided |aOnScrollbar| to populate that information.
+ */
+ bool IsDragOnScrollbar(bool aOnScrollbar);
+
+ InputBlockState* GetBlockForId(uint64_t aInputBlockId);
+
+ void AddInputBlockCallback(uint64_t aInputBlockId,
+ InputBlockCallbackInfo&& aCallback);
+
+ void SetBrowserGestureResponse(uint64_t aInputBlockId,
+ BrowserGestureResponse aResponse);
+
+ private:
+ ~InputQueue();
+
+ // RAII class for automatically running a timeout task that may
+ // need to be run immediately after an event has been queued.
+ class AutoRunImmediateTimeout final {
+ public:
+ explicit AutoRunImmediateTimeout(InputQueue* aQueue);
+ ~AutoRunImmediateTimeout();
+
+ private:
+ InputQueue* mQueue;
+ };
+
+ TouchBlockState* StartNewTouchBlock(
+ const RefPtr<AsyncPanZoomController>& aTarget,
+ TargetConfirmationFlags aFlags);
+
+ TouchBlockState* StartNewTouchBlockForLongTap(
+ const RefPtr<AsyncPanZoomController>& aTarget);
+
+ /**
+ * If animations are present for the current pending input block, cancel
+ * them as soon as possible.
+ */
+ void CancelAnimationsForNewBlock(InputBlockState* aBlock,
+ CancelAnimationFlags aExtraFlags = Default);
+
+ /**
+ * If we need to wait for a content response, schedule that now. Returns true
+ * if the timeout was scheduled, false otherwise.
+ */
+ bool MaybeRequestContentResponse(
+ const RefPtr<AsyncPanZoomController>& aTarget,
+ CancelableBlockState* aBlock);
+
+ APZEventResult ReceiveTouchInput(
+ const RefPtr<AsyncPanZoomController>& aTarget,
+ TargetConfirmationFlags aFlags, const MultiTouchInput& aEvent,
+ const Maybe<nsTArray<TouchBehaviorFlags>>& aTouchBehaviors);
+ APZEventResult ReceiveMouseInput(
+ const RefPtr<AsyncPanZoomController>& aTarget,
+ TargetConfirmationFlags aFlags, MouseInput& aEvent);
+ APZEventResult ReceiveScrollWheelInput(
+ const RefPtr<AsyncPanZoomController>& aTarget,
+ TargetConfirmationFlags aFlags, const ScrollWheelInput& aEvent);
+ APZEventResult ReceivePanGestureInput(
+ const RefPtr<AsyncPanZoomController>& aTarget,
+ TargetConfirmationFlags aFlags, const PanGestureInput& aEvent);
+ APZEventResult ReceivePinchGestureInput(
+ const RefPtr<AsyncPanZoomController>& aTarget,
+ TargetConfirmationFlags aFlags, const PinchGestureInput& aEvent);
+ APZEventResult ReceiveKeyboardInput(
+ const RefPtr<AsyncPanZoomController>& aTarget,
+ TargetConfirmationFlags aFlags, const KeyboardInput& aEvent);
+
+ /**
+ * Helper function that searches mQueuedInputs for the first block matching
+ * the given id, and returns it. If |aOutFirstInput| is non-null, it is
+ * populated with a pointer to the first input in mQueuedInputs that
+ * corresponds to the block, or null if no such input was found. Note that
+ * even if there are no inputs in mQueuedInputs, this function can return
+ * non-null if the block id provided matches one of the depleted-but-still-
+ * active blocks (mActiveTouchBlock, mActiveWheelBlock, etc.).
+ */
+ InputBlockState* FindBlockForId(uint64_t aInputBlockId,
+ InputData** aOutFirstInput);
+ void ScheduleMainThreadTimeout(const RefPtr<AsyncPanZoomController>& aTarget,
+ CancelableBlockState* aBlock);
+ void MainThreadTimeout(uint64_t aInputBlockId);
+ void MaybeLongTapTimeout(uint64_t aInputBlockId);
+
+ // Returns true if there's one more queued event we need to process as a
+ // result of switching the active block back to the original touch block from
+ // the touch block for long-tap.
+ bool ProcessQueue();
+ bool CanDiscardBlock(InputBlockState* aBlock);
+ void UpdateActiveApzc(const RefPtr<AsyncPanZoomController>& aNewActive);
+
+ private:
+ // The queue of input events that have not yet been fully processed.
+ // This member must only be accessed on the controller/UI thread.
+ nsTArray<UniquePtr<QueuedInput>> mQueuedInputs;
+
+ // These are the most recently created blocks of each input type. They are
+ // "active" in the sense that new inputs of that type are associated with
+ // them. Note that these pointers may be null if no inputs of the type have
+ // arrived, or if the inputs for the type formed a complete block that was
+ // then discarded.
+ RefPtr<TouchBlockState> mActiveTouchBlock;
+ RefPtr<WheelBlockState> mActiveWheelBlock;
+ RefPtr<DragBlockState> mActiveDragBlock;
+ RefPtr<PanGestureBlockState> mActivePanGestureBlock;
+ RefPtr<PinchGestureBlockState> mActivePinchGestureBlock;
+ RefPtr<KeyboardBlockState> mActiveKeyboardBlock;
+
+ // In the case where a long-tap event triggered by keeping touching happens
+ // we need to keep both the touch block for the long-tap and the original
+ // touch block started with `touch-start`. This value holds the original block
+ // until the long-tap block is processed.
+ RefPtr<TouchBlockState> mPrevActiveTouchBlock;
+
+ // The APZC to which the last event was delivered
+ RefPtr<AsyncPanZoomController> mLastActiveApzc;
+
+ // Track touches so we know when to clear mLastActiveApzc
+ TouchCounter mTouchCounter;
+
+ // Track mouse inputs so we know if we're in a drag or not
+ DragTracker mDragTracker;
+
+ // Temporarily stores a timeout task that needs to be run as soon as
+ // as the event that triggered it has been queued.
+ RefPtr<Runnable> mImmediateTimeout;
+
+ // Maps input block ids to callbacks that will be invoked when the input block
+ // is ready for handling.
+ using InputBlockCallbackMap =
+ std::unordered_map<uint64_t, InputBlockCallbackInfo>;
+ InputBlockCallbackMap mInputBlockCallbacks;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif // mozilla_layers_InputQueue_h