308 lines
13 KiB
C++
308 lines
13 KiB
C++
/* -*- 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_APZInputBridge_h
|
|
#define mozilla_layers_APZInputBridge_h
|
|
|
|
#include "Units.h" // for LayoutDeviceIntPoint
|
|
#include "mozilla/EventForwards.h" // for WidgetInputEvent, nsEventStatus
|
|
#include "mozilla/layers/APZPublicUtils.h" // for APZWheelAction, DispatchToContent
|
|
#include "mozilla/layers/LayersTypes.h" // for ScrollDirections
|
|
#include "mozilla/layers/ScrollableLayerGuid.h" // for ScrollableLayerGuid
|
|
|
|
namespace mozilla {
|
|
|
|
class InputData;
|
|
|
|
namespace layers {
|
|
|
|
class APZInputBridgeParent;
|
|
class AsyncPanZoomController;
|
|
class InputBlockState;
|
|
class TouchBlockState;
|
|
struct ScrollableLayerGuid;
|
|
struct TargetConfirmationFlags;
|
|
struct PointerEventsConsumableFlags;
|
|
|
|
enum class APZHandledPlace : uint8_t {
|
|
Unhandled = 0, // we know for sure that the event will not be handled
|
|
// by either the root APZC or others
|
|
HandledByRoot = 1, // we know for sure that the event will be handled
|
|
// by the root content APZC
|
|
HandledByContent = 2, // we know for sure it will be handled by a non-root
|
|
// APZC or by an event listener using preventDefault()
|
|
// in a document
|
|
Invalid = 3,
|
|
Last = Invalid
|
|
};
|
|
|
|
struct APZHandledResult {
|
|
APZHandledPlace mPlace = APZHandledPlace::Invalid;
|
|
SideBits mScrollableDirections = SideBits::eNone;
|
|
ScrollDirections mOverscrollDirections = ScrollDirections();
|
|
|
|
APZHandledResult() = default;
|
|
// A constructor for cases where we have the target of the input block this
|
|
// event is part of, the target might be adjusted to be the root in the
|
|
// ScrollingDownWillMoveDynamicToolbar case.
|
|
//
|
|
// NOTE: There's a case where |aTarget| is the APZC for the root content but
|
|
// |aPlace| has to be `HandledByContent`, for example, the root content has
|
|
// an event handler using preventDefault() in the callback, so call sites of
|
|
// this function should be responsible to set a proper |aPlace|.
|
|
APZHandledResult(APZHandledPlace aPlace,
|
|
const AsyncPanZoomController* aTarget,
|
|
bool aPopulateDirectionsForUnhandled = false);
|
|
APZHandledResult(APZHandledPlace aPlace, SideBits aScrollableDirections,
|
|
ScrollDirections aOverscrollDirections)
|
|
: mPlace(aPlace),
|
|
mScrollableDirections(aScrollableDirections),
|
|
mOverscrollDirections(aOverscrollDirections) {}
|
|
|
|
bool IsHandledByContent() const {
|
|
return mPlace == APZHandledPlace::HandledByContent;
|
|
}
|
|
bool IsHandledByRoot() const {
|
|
return mPlace == APZHandledPlace::HandledByRoot;
|
|
}
|
|
bool operator==(const APZHandledResult& aOther) const {
|
|
return mPlace == aOther.mPlace &&
|
|
mScrollableDirections == aOther.mScrollableDirections &&
|
|
mOverscrollDirections == aOther.mOverscrollDirections;
|
|
}
|
|
|
|
// Compute an initial (optional) APZHandledResult for an event.
|
|
// If aDispatchToContent==false, the result is guaranteed to not be empty.
|
|
static Maybe<APZHandledResult> Initialize(
|
|
const AsyncPanZoomController* aInitialTarget,
|
|
DispatchToContent aDispatchToContent);
|
|
|
|
// Update |aHandledResult| with information specific to touch events.
|
|
// If aDispatchToContent==false, the resulting value of |aHandledResult|
|
|
// is guarateed to not be empty.
|
|
static void UpdateForTouchEvent(Maybe<APZHandledResult>& aHandledResult,
|
|
const InputBlockState& aBlock,
|
|
PointerEventsConsumableFlags aConsumableFlags,
|
|
const AsyncPanZoomController* aTarget,
|
|
DispatchToContent aDispatchToContent);
|
|
};
|
|
|
|
/**
|
|
* Represents the outcome of APZ receiving and processing an input event.
|
|
* This is returned from APZInputBridge::ReceiveInputEvent() and related APIs.
|
|
*/
|
|
struct APZEventResult {
|
|
/**
|
|
* Creates a default result with a status of eIgnore, no block ID, and empty
|
|
* target guid.
|
|
*/
|
|
APZEventResult();
|
|
|
|
/**
|
|
* Creates a result with a status of eIgnore, no block ID, the guid of the
|
|
* given initial target, and an APZHandledResult if we are sure the event
|
|
* is not going to be dispatched to contents.
|
|
*/
|
|
APZEventResult(const RefPtr<AsyncPanZoomController>& aInitialTarget,
|
|
TargetConfirmationFlags aFlags);
|
|
|
|
void SetStatusAsConsumeNoDefault() {
|
|
mStatus = nsEventStatus_eConsumeNoDefault;
|
|
}
|
|
|
|
void SetStatusAsIgnore() { mStatus = nsEventStatus_eIgnore; }
|
|
|
|
// Set mStatus to nsEventStatus_eConsumeDoDefault and set mHandledResult
|
|
// depending on |aTarget|.
|
|
void SetStatusAsConsumeDoDefault(
|
|
const RefPtr<AsyncPanZoomController>& aTarget);
|
|
|
|
// Set mStatus to nsEventStatus_eConsumeDoDefault, unlike above
|
|
// SetStatusAsConsumeDoDefault(const RefPtr<AsyncPanZoomController>&) this
|
|
// function doesn't mutate mHandledResult.
|
|
void SetStatusAsConsumeDoDefault() {
|
|
mStatus = nsEventStatus_eConsumeDoDefault;
|
|
}
|
|
|
|
// Set mStatus to nsEventStatus_eConsumeDoDefault and set mHandledResult
|
|
// depending on |aBlock|'s target APZC.
|
|
void SetStatusAsConsumeDoDefault(const InputBlockState& aBlock);
|
|
// Set mStatus and mHandledResult for a touch event which is not dropped
|
|
// altogether (i.e. the status is not eConsumeNoDefault).
|
|
void SetStatusForTouchEvent(const InputBlockState& aBlock,
|
|
TargetConfirmationFlags aFlags,
|
|
PointerEventsConsumableFlags aConsumableFlags,
|
|
const AsyncPanZoomController* aTarget);
|
|
|
|
// Set mStatus and mHandledResult during in a stat of fast fling.
|
|
void SetStatusForFastFling(const TouchBlockState& aBlock,
|
|
TargetConfirmationFlags aFlags,
|
|
PointerEventsConsumableFlags aConsumableFlags,
|
|
const AsyncPanZoomController* aTarget);
|
|
|
|
// DO NOT USE THIS UpdateStatus DIRECTLY. THIS FUNCTION IS ONLY FOR
|
|
// SERIALIZATION / DESERIALIZATION OF THIS STRUCT IN IPC.
|
|
void UpdateStatus(nsEventStatus aStatus) { mStatus = aStatus; }
|
|
nsEventStatus GetStatus() const { return mStatus; };
|
|
|
|
// DO NOT USE THIS UpdateHandledResult DIRECTLY. THIS FUNCTION IS ONLY FOR
|
|
// SERIALIZATION / DESERIALIZATION OF THIS STRUCT IN IPC.
|
|
void UpdateHandledResult(const Maybe<APZHandledResult>& aHandledResult) {
|
|
mHandledResult = aHandledResult;
|
|
}
|
|
const Maybe<APZHandledResult>& GetHandledResult() const {
|
|
return mHandledResult;
|
|
}
|
|
|
|
bool WillHaveDelayedResult() const {
|
|
return GetStatus() != nsEventStatus_eConsumeNoDefault &&
|
|
!GetHandledResult();
|
|
}
|
|
|
|
private:
|
|
/**
|
|
* A status flag indicated how APZ handled the event.
|
|
* The interpretation of each value is as follows:
|
|
*
|
|
* nsEventStatus_eConsumeNoDefault is returned to indicate the
|
|
* APZ is consuming this event and the caller should discard the event with
|
|
* extreme prejudice. The exact scenarios under which this is returned is
|
|
* implementation-dependent and may vary.
|
|
* nsEventStatus_eIgnore is returned to indicate that the APZ code didn't
|
|
* use this event. This might be because it was directed at a point on
|
|
* the screen where there was no APZ, or because the thing the user was
|
|
* trying to do was not allowed. (For example, attempting to pan a
|
|
* non-pannable document).
|
|
* nsEventStatus_eConsumeDoDefault is returned to indicate that the APZ
|
|
* code may have used this event to do some user-visible thing. Note that
|
|
* in some cases CONSUMED is returned even if the event was NOT used. This
|
|
* is because we cannot always know at the time of event delivery whether
|
|
* the event will be used or not. So we err on the side of sending
|
|
* CONSUMED when we are uncertain.
|
|
*/
|
|
nsEventStatus mStatus;
|
|
|
|
/**
|
|
* This is:
|
|
* - set to HandledByRoot if we know for sure that the event will be handled
|
|
* by the root content APZC;
|
|
* - set to HandledByContent if we know for sure it will not be;
|
|
* - left empty if we are unsure.
|
|
*/
|
|
Maybe<APZHandledResult> mHandledResult;
|
|
|
|
public:
|
|
/**
|
|
* The guid of the APZC initially targeted by this event.
|
|
* This will usually be the APZC that handles the event, but in cases
|
|
* where the event is dispatched to content, it may end up being
|
|
* handled by a different APZC.
|
|
*/
|
|
ScrollableLayerGuid mTargetGuid;
|
|
/**
|
|
* If this event started or was added to an input block, the id of that
|
|
* input block, otherwise InputBlockState::NO_BLOCK_ID.
|
|
*/
|
|
uint64_t mInputBlockId;
|
|
};
|
|
|
|
/**
|
|
* This class lives in the main process, and is accessed via the controller
|
|
* thread (which is the process main thread for desktop, and the Java UI
|
|
* thread for Android). This class exposes a synchronous API to deliver
|
|
* incoming input events to APZ and modify them in-place to unapply the APZ
|
|
* async transform. If there is a GPU process, then this class does sync IPC
|
|
* calls over to the GPU process in order to accomplish this. Otherwise,
|
|
* APZCTreeManager overrides and implements these methods directly.
|
|
*/
|
|
class APZInputBridge {
|
|
public:
|
|
using InputBlockCallback = std::function<void(
|
|
uint64_t aInputBlockId, const APZHandledResult& aHandledResult)>;
|
|
|
|
/**
|
|
* General handler for incoming input events. Manipulates the frame metrics
|
|
* based on what type of input it is. For example, a PinchGestureEvent will
|
|
* cause scaling. This should only be called externally to this class, and
|
|
* must be called on the controller thread.
|
|
*
|
|
* This function transforms |aEvent| to have its coordinates in DOM space.
|
|
* This is so that the event can be passed through the DOM and content can
|
|
* handle them. The event may need to be converted to a WidgetInputEvent
|
|
* by the caller if it wants to do this.
|
|
*
|
|
* @param aEvent input event object; is modified in-place
|
|
* @param aCallback an optional callback to be invoked when the input block is
|
|
* ready for handling,
|
|
* @return The result of processing the event. Refer to the documentation of
|
|
* APZEventResult and its field.
|
|
*/
|
|
virtual APZEventResult ReceiveInputEvent(
|
|
InputData& aEvent,
|
|
InputBlockCallback&& aCallback = InputBlockCallback()) = 0;
|
|
|
|
/**
|
|
* WidgetInputEvent handler. Transforms |aEvent| (which is assumed to be an
|
|
* already-existing instance of an WidgetInputEvent which may be an
|
|
* WidgetTouchEvent) to have its coordinates in DOM space. This is so that the
|
|
* event can be passed through the DOM and content can handle them.
|
|
*
|
|
* NOTE: Be careful of invoking the WidgetInputEvent variant. This can only be
|
|
* called on the main thread. See widget/InputData.h for more information on
|
|
* why we have InputData and WidgetInputEvent separated. If this function is
|
|
* used, the controller thread must be the main thread, or undefined behaviour
|
|
* may occur.
|
|
* NOTE: On unix, mouse events are treated as touch and are forwarded
|
|
* to the appropriate apz as such.
|
|
*
|
|
* See documentation for other ReceiveInputEvent above.
|
|
*/
|
|
APZEventResult ReceiveInputEvent(
|
|
WidgetInputEvent& aEvent,
|
|
InputBlockCallback&& aCallback = InputBlockCallback());
|
|
|
|
// Returns the kind of wheel event action, if any, that will be (or was)
|
|
// performed by APZ. If this returns true, the event must not perform a
|
|
// synchronous scroll.
|
|
//
|
|
// Even if this returns Nothing(), all wheel events in APZ-aware widgets must
|
|
// be sent through APZ so they are transformed correctly for BrowserParent.
|
|
static Maybe<APZWheelAction> ActionForWheelEvent(WidgetWheelEvent* aEvent);
|
|
|
|
protected:
|
|
friend class APZInputBridgeParent;
|
|
|
|
// Methods to help process WidgetInputEvents (or manage conversion to/from
|
|
// InputData)
|
|
|
|
virtual void ProcessUnhandledEvent(LayoutDeviceIntPoint* aRefPoint,
|
|
ScrollableLayerGuid* aOutTargetGuid,
|
|
uint64_t* aOutFocusSequenceNumber,
|
|
LayersId* aOutLayersId) = 0;
|
|
|
|
virtual void UpdateWheelTransaction(
|
|
LayoutDeviceIntPoint aRefPoint, EventMessage aEventMessage,
|
|
const Maybe<ScrollableLayerGuid>& aTargetGuid) = 0;
|
|
|
|
virtual ~APZInputBridge() = default;
|
|
};
|
|
|
|
std::ostream& operator<<(std::ostream& aOut,
|
|
const APZHandledResult& aHandledResult);
|
|
|
|
// This enum class is used for communicating between APZ and the browser gesture
|
|
// support code. APZ needs to wait for the browser to send this response just
|
|
// like APZ waits for the content's response if there's an APZ ware event
|
|
// listener in the content process.
|
|
enum class BrowserGestureResponse : bool {
|
|
NotConsumed = 0, // Representing the browser doesn't consume the gesture
|
|
Consumed = 1, // Representing the browser has started consuming the gesture.
|
|
};
|
|
|
|
} // namespace layers
|
|
} // namespace mozilla
|
|
|
|
#endif // mozilla_layers_APZInputBridge_h
|