Source code

Revision control

Other Tools

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_InputBlockState_h
8
#define mozilla_layers_InputBlockState_h
9
10
#include "InputData.h" // for MultiTouchInput
11
#include "mozilla/RefCounted.h" // for RefCounted
12
#include "mozilla/RefPtr.h" // for RefPtr
13
#include "mozilla/StaticPrefs_apz.h"
14
#include "mozilla/gfx/Matrix.h" // for Matrix4x4
15
#include "mozilla/layers/APZUtils.h"
16
#include "mozilla/layers/LayersTypes.h" // for TouchBehaviorFlags
17
#include "mozilla/layers/AsyncDragMetrics.h"
18
#include "mozilla/layers/TouchCounter.h"
19
#include "mozilla/TimeStamp.h" // for TimeStamp
20
#include "nsTArray.h" // for nsTArray
21
22
namespace mozilla {
23
namespace layers {
24
25
class AsyncPanZoomController;
26
class OverscrollHandoffChain;
27
class CancelableBlockState;
28
class TouchBlockState;
29
class WheelBlockState;
30
class DragBlockState;
31
class PanGestureBlockState;
32
class KeyboardBlockState;
33
34
/**
35
* A base class that stores state common to various input blocks.
36
* Note that the InputBlockState constructor acquires the tree lock, so callers
37
* from inside AsyncPanZoomController should ensure that the APZC lock is not
38
* held.
39
*/
40
class InputBlockState : public RefCounted<InputBlockState> {
41
public:
42
MOZ_DECLARE_REFCOUNTED_TYPENAME(InputBlockState)
43
44
static const uint64_t NO_BLOCK_ID = 0;
45
46
enum class TargetConfirmationState : uint8_t {
47
eUnconfirmed,
48
eTimedOut,
49
eTimedOutAndMainThreadResponded,
50
eConfirmed
51
};
52
53
InputBlockState(const RefPtr<AsyncPanZoomController>& aTargetApzc,
54
TargetConfirmationFlags aFlags);
55
virtual ~InputBlockState() = default;
56
57
virtual CancelableBlockState* AsCancelableBlock() { return nullptr; }
58
virtual TouchBlockState* AsTouchBlock() { return nullptr; }
59
virtual WheelBlockState* AsWheelBlock() { return nullptr; }
60
virtual DragBlockState* AsDragBlock() { return nullptr; }
61
virtual PanGestureBlockState* AsPanGestureBlock() { return nullptr; }
62
virtual KeyboardBlockState* AsKeyboardBlock() { return nullptr; }
63
64
virtual bool SetConfirmedTargetApzc(
65
const RefPtr<AsyncPanZoomController>& aTargetApzc,
66
TargetConfirmationState aState, InputData* aFirstInput,
67
bool aForScrollbarDrag);
68
const RefPtr<AsyncPanZoomController>& GetTargetApzc() const;
69
const RefPtr<const OverscrollHandoffChain>& GetOverscrollHandoffChain() const;
70
uint64_t GetBlockId() const;
71
72
bool IsTargetConfirmed() const;
73
bool HasReceivedRealConfirmedTarget() const;
74
75
virtual bool ShouldDropEvents() const;
76
77
void SetScrolledApzc(AsyncPanZoomController* aApzc);
78
AsyncPanZoomController* GetScrolledApzc() const;
79
bool IsDownchainOfScrolledApzc(AsyncPanZoomController* aApzc) const;
80
81
/**
82
* Dispatch the event to the target APZC. Mostly this is a hook for
83
* subclasses to do any per-event processing they need to.
84
*/
85
virtual void DispatchEvent(const InputData& aEvent) const;
86
87
/**
88
* Return true if this input block must stay active if it would otherwise
89
* be removed as the last item in the pending queue.
90
*/
91
virtual bool MustStayActive() = 0;
92
93
protected:
94
virtual void UpdateTargetApzc(
95
const RefPtr<AsyncPanZoomController>& aTargetApzc);
96
97
private:
98
// Checks whether |aA| is an ancestor of |aB| (or the same as |aB|) in
99
// |mOverscrollHandoffChain|.
100
bool IsDownchainOf(AsyncPanZoomController* aA,
101
AsyncPanZoomController* aB) const;
102
103
private:
104
RefPtr<AsyncPanZoomController> mTargetApzc;
105
TargetConfirmationState mTargetConfirmed;
106
bool mRequiresTargetConfirmation;
107
const uint64_t mBlockId;
108
109
// The APZC that was actually scrolled by events in this input block.
110
// This is used in configurations where a single input block is only
111
// allowed to scroll a single APZC (configurations where
112
// StaticPrefs::apz_allow_immediate_handoff() is false). Set the first time an
113
// input event in this block scrolls an APZC.
114
RefPtr<AsyncPanZoomController> mScrolledApzc;
115
116
protected:
117
RefPtr<const OverscrollHandoffChain> mOverscrollHandoffChain;
118
119
// Used to transform events from global screen space to |mTargetApzc|'s
120
// screen space. It's cached at the beginning of the input block so that
121
// all events in the block are in the same coordinate space.
122
ScreenToParentLayerMatrix4x4 mTransformToApzc;
123
};
124
125
/**
126
* This class represents a set of events that can be cancelled by web content
127
* via event listeners.
128
*
129
* Each cancelable input block can be cancelled by web content, and
130
* this information is stored in the mPreventDefault flag. Because web
131
* content runs on the Gecko main thread, we cannot always wait for web
132
* content's response. Instead, there is a timeout that sets this flag in the
133
* case where web content doesn't respond in time. The mContentResponded and
134
* mContentResponseTimerExpired flags indicate which of these scenarios
135
* occurred.
136
*/
137
class CancelableBlockState : public InputBlockState {
138
public:
139
CancelableBlockState(const RefPtr<AsyncPanZoomController>& aTargetApzc,
140
TargetConfirmationFlags aFlags);
141
142
CancelableBlockState* AsCancelableBlock() override { return this; }
143
144
/**
145
* Record whether or not content cancelled this block of events.
146
* @param aPreventDefault true iff the block is cancelled.
147
* @return false if this block has already received a response from
148
* web content, true if not.
149
*/
150
virtual bool SetContentResponse(bool aPreventDefault);
151
152
/**
153
* This should be called when this block is starting to wait for the
154
* necessary content response notifications. It is used to gather data
155
* on how long the content response notifications take.
156
*/
157
void StartContentResponseTimer();
158
159
/**
160
* This should be called when a content response notification has been
161
* delivered to this block. If all the notifications have arrived, this
162
* will report the total time take to telemetry.
163
*/
164
void RecordContentResponseTime();
165
166
/**
167
* Record that content didn't respond in time.
168
* @return false if this block already timed out, true if not.
169
*/
170
bool TimeoutContentResponse();
171
172
/**
173
* Checks if the content response timer has already expired.
174
*/
175
bool IsContentResponseTimerExpired() const;
176
177
/**
178
* @return true iff web content cancelled this block of events.
179
*/
180
bool IsDefaultPrevented() const;
181
182
/**
183
* @return true iff this block has received all the information it could
184
* have gotten from the content thread.
185
*/
186
virtual bool HasReceivedAllContentNotifications() const;
187
188
/**
189
* @return true iff this block has received all the information needed
190
* to properly dispatch the events in the block.
191
*/
192
virtual bool IsReadyForHandling() const;
193
194
/**
195
* Return a descriptive name for the block kind.
196
*/
197
virtual const char* Type() = 0;
198
199
bool ShouldDropEvents() const override;
200
201
private:
202
TimeStamp mContentResponseTimer;
203
bool mPreventDefault;
204
bool mContentResponded;
205
bool mContentResponseTimerExpired;
206
};
207
208
/**
209
* A single block of wheel events.
210
*/
211
class WheelBlockState : public CancelableBlockState {
212
public:
213
WheelBlockState(const RefPtr<AsyncPanZoomController>& aTargetApzc,
214
TargetConfirmationFlags aFlags,
215
const ScrollWheelInput& aEvent);
216
217
bool SetContentResponse(bool aPreventDefault) override;
218
bool MustStayActive() override;
219
const char* Type() override;
220
bool SetConfirmedTargetApzc(const RefPtr<AsyncPanZoomController>& aTargetApzc,
221
TargetConfirmationState aState,
222
InputData* aFirstInput,
223
bool aForScrollbarDrag) override;
224
225
WheelBlockState* AsWheelBlock() override { return this; }
226
227
/**
228
* Determine whether this wheel block is accepting new events.
229
*/
230
bool ShouldAcceptNewEvent() const;
231
232
/**
233
* Call to check whether a wheel event will cause the current transaction to
234
* timeout.
235
*/
236
bool MaybeTimeout(const ScrollWheelInput& aEvent);
237
238
/**
239
* Called from APZCTM when a mouse move or drag+drop event occurs, before
240
* the event has been processed.
241
*/
242
void OnMouseMove(const ScreenIntPoint& aPoint);
243
244
/**
245
* Returns whether or not the block is participating in a wheel transaction.
246
* This means that the block is the most recent input block to be created,
247
* and no events have occurred that would require scrolling a different
248
* frame.
249
*
250
* @return True if in a transaction, false otherwise.
251
*/
252
bool InTransaction() const;
253
254
/**
255
* Mark the block as no longer participating in a wheel transaction. This
256
* will force future wheel events to begin a new input block.
257
*/
258
void EndTransaction();
259
260
/**
261
* @return Whether or not overscrolling is prevented for this wheel block.
262
*/
263
bool AllowScrollHandoff() const;
264
265
/**
266
* Called to check and possibly end the transaction due to a timeout.
267
*
268
* @return True if the transaction ended, false otherwise.
269
*/
270
bool MaybeTimeout(const TimeStamp& aTimeStamp);
271
272
/**
273
* Update the wheel transaction state for a new event.
274
*/
275
void Update(ScrollWheelInput& aEvent);
276
277
ScrollDirections GetAllowedScrollDirections() const {
278
return mAllowedScrollDirections;
279
}
280
281
protected:
282
void UpdateTargetApzc(
283
const RefPtr<AsyncPanZoomController>& aTargetApzc) override;
284
285
private:
286
TimeStamp mLastEventTime;
287
TimeStamp mLastMouseMove;
288
uint32_t mScrollSeriesCounter;
289
bool mTransactionEnded;
290
ScrollDirections mAllowedScrollDirections;
291
};
292
293
/**
294
* A block of mouse events that are part of a drag
295
*/
296
class DragBlockState : public CancelableBlockState {
297
public:
298
DragBlockState(const RefPtr<AsyncPanZoomController>& aTargetApzc,
299
TargetConfirmationFlags aFlags, const MouseInput& aEvent);
300
301
bool MustStayActive() override;
302
const char* Type() override;
303
304
bool HasReceivedMouseUp();
305
void MarkMouseUpReceived();
306
307
DragBlockState* AsDragBlock() override { return this; }
308
309
void SetInitialThumbPos(CSSCoord aThumbPos);
310
void SetDragMetrics(const AsyncDragMetrics& aDragMetrics);
311
312
void DispatchEvent(const InputData& aEvent) const override;
313
314
private:
315
AsyncDragMetrics mDragMetrics;
316
CSSCoord mInitialThumbPos;
317
bool mReceivedMouseUp;
318
};
319
320
/**
321
* A single block of pan gesture events.
322
*/
323
class PanGestureBlockState : public CancelableBlockState {
324
public:
325
PanGestureBlockState(const RefPtr<AsyncPanZoomController>& aTargetApzc,
326
TargetConfirmationFlags aFlags,
327
const PanGestureInput& aEvent);
328
329
bool SetContentResponse(bool aPreventDefault) override;
330
bool HasReceivedAllContentNotifications() const override;
331
bool IsReadyForHandling() const override;
332
bool MustStayActive() override;
333
const char* Type() override;
334
bool SetConfirmedTargetApzc(const RefPtr<AsyncPanZoomController>& aTargetApzc,
335
TargetConfirmationState aState,
336
InputData* aFirstInput,
337
bool aForScrollbarDrag) override;
338
339
PanGestureBlockState* AsPanGestureBlock() override { return this; }
340
341
/**
342
* @return Whether or not overscrolling is prevented for this block.
343
*/
344
bool AllowScrollHandoff() const;
345
346
bool WasInterrupted() const { return mInterrupted; }
347
348
void SetNeedsToWaitForContentResponse(bool aWaitForContentResponse);
349
350
ScrollDirections GetAllowedScrollDirections() const {
351
return mAllowedScrollDirections;
352
}
353
354
private:
355
bool mInterrupted;
356
bool mWaitingForContentResponse;
357
ScrollDirections mAllowedScrollDirections;
358
};
359
360
/**
361
* This class represents a single touch block. A touch block is
362
* a set of touch events that can be cancelled by web content via
363
* touch event listeners.
364
*
365
* Every touch-start event creates a new touch block. In this case, the
366
* touch block consists of the touch-start, followed by all touch events
367
* up to but not including the next touch-start (except in the case where
368
* a long-tap happens, see below). Note that in particular we cannot know
369
* when a touch block ends until the next one is started. Most touch
370
* blocks are created by receipt of a touch-start event.
371
*
372
* Every long-tap event also creates a new touch block, since it can also
373
* be consumed by web content. In this case, when the long-tap event is
374
* dispatched to web content, a new touch block is started to hold the remaining
375
* touch events, up to but not including the next touch start (or long-tap).
376
*
377
* Additionally, if touch-action is enabled, each touch block should
378
* have a set of allowed touch behavior flags; one for each touch point.
379
* This also requires running code on the Gecko main thread, and so may
380
* be populated with some latency. The mAllowedTouchBehaviorSet and
381
* mAllowedTouchBehaviors variables track this information.
382
*/
383
class TouchBlockState : public CancelableBlockState {
384
public:
385
explicit TouchBlockState(const RefPtr<AsyncPanZoomController>& aTargetApzc,
386
TargetConfirmationFlags aFlags,
387
TouchCounter& aTouchCounter);
388
389
TouchBlockState* AsTouchBlock() override { return this; }
390
391
/**
392
* Set the allowed touch behavior flags for this block.
393
* @return false if this block already has these flags set, true if not.
394
*/
395
bool SetAllowedTouchBehaviors(const nsTArray<TouchBehaviorFlags>& aBehaviors);
396
/**
397
* If the allowed touch behaviors have been set, populate them into
398
* |aOutBehaviors| and return true. Else, return false.
399
*/
400
bool GetAllowedTouchBehaviors(
401
nsTArray<TouchBehaviorFlags>& aOutBehaviors) const;
402
403
/**
404
* Returns true if the allowed touch behaviours have been set, or if touch
405
* action is disabled.
406
*/
407
bool HasAllowedTouchBehaviors() const;
408
409
/**
410
* Copy various properties from another block.
411
*/
412
void CopyPropertiesFrom(const TouchBlockState& aOther);
413
414
/*
415
* @return true iff this block has received all the information it could
416
* have gotten from the content thread.
417
*/
418
bool HasReceivedAllContentNotifications() const override;
419
420
/**
421
* @return true iff this block has received all the information needed
422
* to properly dispatch the events in the block.
423
*/
424
bool IsReadyForHandling() const override;
425
426
/**
427
* Sets a flag that indicates this input block occurred while the APZ was
428
* in a state of fast flinging. This affects gestures that may be produced
429
* from input events in this block.
430
*/
431
void SetDuringFastFling();
432
/**
433
* @return true iff SetDuringFastFling was called on this block.
434
*/
435
bool IsDuringFastFling() const;
436
/**
437
* Set the single-tap-occurred flag that indicates that this touch block
438
* triggered a single tap event.
439
*/
440
void SetSingleTapOccurred();
441
/**
442
* @return true iff the single-tap-occurred flag is set on this block.
443
*/
444
bool SingleTapOccurred() const;
445
446
/**
447
* @return false iff touch-action is enabled and the allowed touch behaviors
448
* for this touch block do not allow pinch-zooming.
449
*/
450
bool TouchActionAllowsPinchZoom() const;
451
/**
452
* @return false iff touch-action is enabled and the allowed touch behaviors
453
* for this touch block do not allow double-tap zooming.
454
*/
455
bool TouchActionAllowsDoubleTapZoom() const;
456
/**
457
* @return false iff touch-action is enabled and the allowed touch behaviors
458
* for the first touch point do not allow panning in the specified
459
* direction(s).
460
*/
461
bool TouchActionAllowsPanningX() const;
462
bool TouchActionAllowsPanningY() const;
463
bool TouchActionAllowsPanningXY() const;
464
465
/**
466
* Notifies the input block of an incoming touch event so that the block can
467
* update its internal slop state. "Slop" refers to the area around the
468
* initial touchstart where we drop touchmove events so that content doesn't
469
* see them. The |aApzcCanConsumeEvents| parameter is factored into how large
470
* the slop area is - if this is true the slop area is larger.
471
* @return true iff the provided event is a touchmove in the slop area and
472
* so should not be sent to content.
473
*/
474
bool UpdateSlopState(const MultiTouchInput& aInput,
475
bool aApzcCanConsumeEvents);
476
477
/**
478
* Based on the slop origin and the given input event, return a best guess
479
* as to the pan direction of this touch block. Returns Nothing() if no guess
480
* can be made.
481
*/
482
Maybe<ScrollDirection> GetBestGuessPanDirection(
483
const MultiTouchInput& aInput);
484
485
/**
486
* Returns the number of touch points currently active.
487
*/
488
uint32_t GetActiveTouchCount() const;
489
490
void DispatchEvent(const InputData& aEvent) const override;
491
bool MustStayActive() override;
492
const char* Type() override;
493
494
private:
495
nsTArray<TouchBehaviorFlags> mAllowedTouchBehaviors;
496
bool mAllowedTouchBehaviorSet;
497
bool mDuringFastFling;
498
bool mSingleTapOccurred;
499
bool mInSlop;
500
ScreenIntPoint mSlopOrigin;
501
// A reference to the InputQueue's touch counter
502
TouchCounter& mTouchCounter;
503
};
504
505
/**
506
* This class represents a set of keyboard inputs targeted at the same Apzc.
507
*/
508
class KeyboardBlockState : public InputBlockState {
509
public:
510
explicit KeyboardBlockState(
511
const RefPtr<AsyncPanZoomController>& aTargetApzc);
512
513
KeyboardBlockState* AsKeyboardBlock() override { return this; }
514
515
bool MustStayActive() override { return false; }
516
517
/**
518
* @return Whether or not overscrolling is prevented for this keyboard block.
519
*/
520
bool AllowScrollHandoff() const { return false; }
521
};
522
523
} // namespace layers
524
} // namespace mozilla
525
526
#endif // mozilla_layers_InputBlockState_h