summaryrefslogtreecommitdiffstats
path: root/gfx/layers/apz/public/APZInputBridge.h
blob: 117e4b7bb27bf7f2359af73d0f6118a333fefb4a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
/* -*- 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
#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;
  }
};

/**
 * 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:
  void UpdateHandledResult(const InputBlockState& aBlock,
                           PointerEventsConsumableFlags aConsumableFlags,
                           const AsyncPanZoomController* aTarget,
                           bool aDispatchToContent);

  /**
   * 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