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