APZInputBridge.h (13235B)
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_APZInputBridge_h 8 #define mozilla_layers_APZInputBridge_h 9 10 #include "Units.h" // for LayoutDeviceIntPoint 11 #include "mozilla/EventForwards.h" // for WidgetInputEvent, nsEventStatus 12 #include "mozilla/layers/APZPublicUtils.h" // for APZWheelAction, DispatchToContent 13 #include "mozilla/layers/LayersTypes.h" // for ScrollDirections 14 #include "mozilla/layers/ScrollableLayerGuid.h" // for ScrollableLayerGuid 15 16 namespace mozilla { 17 18 class InputData; 19 20 namespace layers { 21 22 class APZInputBridgeParent; 23 class AsyncPanZoomController; 24 class InputBlockState; 25 class TouchBlockState; 26 struct ScrollableLayerGuid; 27 struct TargetConfirmationFlags; 28 struct PointerEventsConsumableFlags; 29 30 enum class APZHandledPlace : uint8_t { 31 Unhandled = 0, // we know for sure that the event will not be handled 32 // by either the root APZC or others 33 HandledByRoot = 1, // we know for sure that the event will be handled 34 // by the root content APZC 35 HandledByContent = 2, // we know for sure it will be handled by a non-root 36 // APZC or by an event listener using preventDefault() 37 // in a document 38 Invalid = 3, 39 Last = Invalid 40 }; 41 42 struct APZHandledResult { 43 APZHandledPlace mPlace = APZHandledPlace::Invalid; 44 SideBits mScrollableDirections = SideBits::eNone; 45 ScrollDirections mOverscrollDirections = ScrollDirections(); 46 47 APZHandledResult() = default; 48 // A constructor for cases where we have the target of the input block this 49 // event is part of, the target might be adjusted to be the root in the 50 // ScrollingDownWillMoveDynamicToolbar case. 51 // 52 // NOTE: There's a case where |aTarget| is the APZC for the root content but 53 // |aPlace| has to be `HandledByContent`, for example, the root content has 54 // an event handler using preventDefault() in the callback, so call sites of 55 // this function should be responsible to set a proper |aPlace|. 56 APZHandledResult(APZHandledPlace aPlace, 57 const AsyncPanZoomController* aTarget, 58 bool aPopulateDirectionsForUnhandled = false); 59 APZHandledResult(APZHandledPlace aPlace, SideBits aScrollableDirections, 60 ScrollDirections aOverscrollDirections) 61 : mPlace(aPlace), 62 mScrollableDirections(aScrollableDirections), 63 mOverscrollDirections(aOverscrollDirections) {} 64 65 bool IsHandledByContent() const { 66 return mPlace == APZHandledPlace::HandledByContent; 67 } 68 bool IsHandledByRoot() const { 69 return mPlace == APZHandledPlace::HandledByRoot; 70 } 71 bool operator==(const APZHandledResult& aOther) const { 72 return mPlace == aOther.mPlace && 73 mScrollableDirections == aOther.mScrollableDirections && 74 mOverscrollDirections == aOther.mOverscrollDirections; 75 } 76 77 // Compute an initial (optional) APZHandledResult for an event. 78 // If aDispatchToContent==false, the result is guaranteed to not be empty. 79 static Maybe<APZHandledResult> Initialize( 80 const AsyncPanZoomController* aInitialTarget, 81 DispatchToContent aDispatchToContent); 82 83 // Update |aHandledResult| with information specific to touch events. 84 // If aDispatchToContent==false, the resulting value of |aHandledResult| 85 // is guarateed to not be empty. 86 static void UpdateForTouchEvent(Maybe<APZHandledResult>& aHandledResult, 87 const InputBlockState& aBlock, 88 PointerEventsConsumableFlags aConsumableFlags, 89 const AsyncPanZoomController* aTarget, 90 DispatchToContent aDispatchToContent); 91 }; 92 93 /** 94 * Represents the outcome of APZ receiving and processing an input event. 95 * This is returned from APZInputBridge::ReceiveInputEvent() and related APIs. 96 */ 97 struct APZEventResult { 98 /** 99 * Creates a default result with a status of eIgnore, no block ID, and empty 100 * target guid. 101 */ 102 APZEventResult(); 103 104 /** 105 * Creates a result with a status of eIgnore, no block ID, the guid of the 106 * given initial target, and an APZHandledResult if we are sure the event 107 * is not going to be dispatched to contents. 108 */ 109 APZEventResult(const RefPtr<AsyncPanZoomController>& aInitialTarget, 110 TargetConfirmationFlags aFlags); 111 112 void SetStatusAsConsumeNoDefault() { 113 mStatus = nsEventStatus_eConsumeNoDefault; 114 } 115 116 void SetStatusAsIgnore() { mStatus = nsEventStatus_eIgnore; } 117 118 // Set mStatus to nsEventStatus_eConsumeDoDefault and set mHandledResult 119 // depending on |aTarget|. 120 void SetStatusAsConsumeDoDefault( 121 const RefPtr<AsyncPanZoomController>& aTarget); 122 123 // Set mStatus to nsEventStatus_eConsumeDoDefault, unlike above 124 // SetStatusAsConsumeDoDefault(const RefPtr<AsyncPanZoomController>&) this 125 // function doesn't mutate mHandledResult. 126 void SetStatusAsConsumeDoDefault() { 127 mStatus = nsEventStatus_eConsumeDoDefault; 128 } 129 130 // Set mStatus to nsEventStatus_eConsumeDoDefault and set mHandledResult 131 // depending on |aBlock|'s target APZC. 132 void SetStatusAsConsumeDoDefault(const InputBlockState& aBlock); 133 // Set mStatus and mHandledResult for a touch event which is not dropped 134 // altogether (i.e. the status is not eConsumeNoDefault). 135 void SetStatusForTouchEvent(const InputBlockState& aBlock, 136 TargetConfirmationFlags aFlags, 137 PointerEventsConsumableFlags aConsumableFlags, 138 const AsyncPanZoomController* aTarget); 139 140 // Set mStatus and mHandledResult during in a stat of fast fling. 141 void SetStatusForFastFling(const TouchBlockState& aBlock, 142 TargetConfirmationFlags aFlags, 143 PointerEventsConsumableFlags aConsumableFlags, 144 const AsyncPanZoomController* aTarget); 145 146 // DO NOT USE THIS UpdateStatus DIRECTLY. THIS FUNCTION IS ONLY FOR 147 // SERIALIZATION / DESERIALIZATION OF THIS STRUCT IN IPC. 148 void UpdateStatus(nsEventStatus aStatus) { mStatus = aStatus; } 149 nsEventStatus GetStatus() const { return mStatus; }; 150 151 // DO NOT USE THIS UpdateHandledResult DIRECTLY. THIS FUNCTION IS ONLY FOR 152 // SERIALIZATION / DESERIALIZATION OF THIS STRUCT IN IPC. 153 void UpdateHandledResult(const Maybe<APZHandledResult>& aHandledResult) { 154 mHandledResult = aHandledResult; 155 } 156 const Maybe<APZHandledResult>& GetHandledResult() const { 157 return mHandledResult; 158 } 159 160 bool WillHaveDelayedResult() const { 161 return GetStatus() != nsEventStatus_eConsumeNoDefault && 162 !GetHandledResult(); 163 } 164 165 private: 166 /** 167 * A status flag indicated how APZ handled the event. 168 * The interpretation of each value is as follows: 169 * 170 * nsEventStatus_eConsumeNoDefault is returned to indicate the 171 * APZ is consuming this event and the caller should discard the event with 172 * extreme prejudice. The exact scenarios under which this is returned is 173 * implementation-dependent and may vary. 174 * nsEventStatus_eIgnore is returned to indicate that the APZ code didn't 175 * use this event. This might be because it was directed at a point on 176 * the screen where there was no APZ, or because the thing the user was 177 * trying to do was not allowed. (For example, attempting to pan a 178 * non-pannable document). 179 * nsEventStatus_eConsumeDoDefault is returned to indicate that the APZ 180 * code may have used this event to do some user-visible thing. Note that 181 * in some cases CONSUMED is returned even if the event was NOT used. This 182 * is because we cannot always know at the time of event delivery whether 183 * the event will be used or not. So we err on the side of sending 184 * CONSUMED when we are uncertain. 185 */ 186 nsEventStatus mStatus; 187 188 /** 189 * This is: 190 * - set to HandledByRoot if we know for sure that the event will be handled 191 * by the root content APZC; 192 * - set to HandledByContent if we know for sure it will not be; 193 * - left empty if we are unsure. 194 */ 195 Maybe<APZHandledResult> mHandledResult; 196 197 public: 198 /** 199 * The guid of the APZC initially targeted by this event. 200 * This will usually be the APZC that handles the event, but in cases 201 * where the event is dispatched to content, it may end up being 202 * handled by a different APZC. 203 */ 204 ScrollableLayerGuid mTargetGuid; 205 /** 206 * If this event started or was added to an input block, the id of that 207 * input block, otherwise InputBlockState::NO_BLOCK_ID. 208 */ 209 uint64_t mInputBlockId; 210 }; 211 212 /** 213 * This class lives in the main process, and is accessed via the controller 214 * thread (which is the process main thread for desktop, and the Java UI 215 * thread for Android). This class exposes a synchronous API to deliver 216 * incoming input events to APZ and modify them in-place to unapply the APZ 217 * async transform. If there is a GPU process, then this class does sync IPC 218 * calls over to the GPU process in order to accomplish this. Otherwise, 219 * APZCTreeManager overrides and implements these methods directly. 220 */ 221 class APZInputBridge { 222 public: 223 using InputBlockCallback = std::function<void( 224 uint64_t aInputBlockId, const APZHandledResult& aHandledResult)>; 225 226 /** 227 * General handler for incoming input events. Manipulates the frame metrics 228 * based on what type of input it is. For example, a PinchGestureEvent will 229 * cause scaling. This should only be called externally to this class, and 230 * must be called on the controller thread. 231 * 232 * This function transforms |aEvent| to have its coordinates in DOM space. 233 * This is so that the event can be passed through the DOM and content can 234 * handle them. The event may need to be converted to a WidgetInputEvent 235 * by the caller if it wants to do this. 236 * 237 * @param aEvent input event object; is modified in-place 238 * @param aCallback an optional callback to be invoked when the input block is 239 * ready for handling, 240 * @return The result of processing the event. Refer to the documentation of 241 * APZEventResult and its field. 242 */ 243 virtual APZEventResult ReceiveInputEvent( 244 InputData& aEvent, 245 InputBlockCallback&& aCallback = InputBlockCallback()) = 0; 246 247 /** 248 * WidgetInputEvent handler. Transforms |aEvent| (which is assumed to be an 249 * already-existing instance of an WidgetInputEvent which may be an 250 * WidgetTouchEvent) to have its coordinates in DOM space. This is so that the 251 * event can be passed through the DOM and content can handle them. 252 * 253 * NOTE: Be careful of invoking the WidgetInputEvent variant. This can only be 254 * called on the main thread. See widget/InputData.h for more information on 255 * why we have InputData and WidgetInputEvent separated. If this function is 256 * used, the controller thread must be the main thread, or undefined behaviour 257 * may occur. 258 * NOTE: On unix, mouse events are treated as touch and are forwarded 259 * to the appropriate apz as such. 260 * 261 * See documentation for other ReceiveInputEvent above. 262 */ 263 APZEventResult ReceiveInputEvent( 264 WidgetInputEvent& aEvent, 265 InputBlockCallback&& aCallback = InputBlockCallback()); 266 267 // Returns the kind of wheel event action, if any, that will be (or was) 268 // performed by APZ. If this returns true, the event must not perform a 269 // synchronous scroll. 270 // 271 // Even if this returns Nothing(), all wheel events in APZ-aware widgets must 272 // be sent through APZ so they are transformed correctly for BrowserParent. 273 static Maybe<APZWheelAction> ActionForWheelEvent(WidgetWheelEvent* aEvent); 274 275 protected: 276 friend class APZInputBridgeParent; 277 278 // Methods to help process WidgetInputEvents (or manage conversion to/from 279 // InputData) 280 281 virtual void ProcessUnhandledEvent(LayoutDeviceIntPoint* aRefPoint, 282 ScrollableLayerGuid* aOutTargetGuid, 283 uint64_t* aOutFocusSequenceNumber, 284 LayersId* aOutLayersId) = 0; 285 286 virtual void UpdateWheelTransaction( 287 LayoutDeviceIntPoint aRefPoint, EventMessage aEventMessage, 288 const Maybe<ScrollableLayerGuid>& aTargetGuid) = 0; 289 290 virtual ~APZInputBridge() = default; 291 }; 292 293 std::ostream& operator<<(std::ostream& aOut, 294 const APZHandledResult& aHandledResult); 295 296 // This enum class is used for communicating between APZ and the browser gesture 297 // support code. APZ needs to wait for the browser to send this response just 298 // like APZ waits for the content's response if there's an APZ ware event 299 // listener in the content process. 300 enum class BrowserGestureResponse : bool { 301 NotConsumed = 0, // Representing the browser doesn't consume the gesture 302 Consumed = 1, // Representing the browser has started consuming the gesture. 303 }; 304 305 } // namespace layers 306 } // namespace mozilla 307 308 #endif // mozilla_layers_APZInputBridge_h