|
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_AsyncPanZoomController_h |
|
8 #define mozilla_layers_AsyncPanZoomController_h |
|
9 |
|
10 #include "CrossProcessMutex.h" |
|
11 #include "mozilla/layers/GeckoContentController.h" |
|
12 #include "mozilla/Attributes.h" |
|
13 #include "mozilla/EventForwards.h" |
|
14 #include "mozilla/Monitor.h" |
|
15 #include "mozilla/ReentrantMonitor.h" |
|
16 #include "mozilla/RefPtr.h" |
|
17 #include "mozilla/Atomics.h" |
|
18 #include "InputData.h" |
|
19 #include "Axis.h" |
|
20 #include "TaskThrottler.h" |
|
21 #include "gfx3DMatrix.h" |
|
22 |
|
23 #include "base/message_loop.h" |
|
24 |
|
25 namespace mozilla { |
|
26 |
|
27 namespace ipc { |
|
28 |
|
29 class SharedMemoryBasic; |
|
30 |
|
31 } |
|
32 |
|
33 namespace layers { |
|
34 |
|
35 struct ScrollableLayerGuid; |
|
36 class CompositorParent; |
|
37 class GestureEventListener; |
|
38 class ContainerLayer; |
|
39 class PCompositorParent; |
|
40 class ViewTransform; |
|
41 class APZCTreeManager; |
|
42 class AsyncPanZoomAnimation; |
|
43 class FlingAnimation; |
|
44 |
|
45 /** |
|
46 * Controller for all panning and zooming logic. Any time a user input is |
|
47 * detected and it must be processed in some way to affect what the user sees, |
|
48 * it goes through here. Listens for any input event from InputData and can |
|
49 * optionally handle WidgetGUIEvent-derived touch events, but this must be done |
|
50 * on the main thread. Note that this class completely cross-platform. |
|
51 * |
|
52 * Input events originate on the UI thread of the platform that this runs on, |
|
53 * and are then sent to this class. This class processes the event in some way; |
|
54 * for example, a touch move will usually lead to a panning of content (though |
|
55 * of course there are exceptions, such as if content preventDefaults the event, |
|
56 * or if the target frame is not scrollable). The compositor interacts with this |
|
57 * class by locking it and querying it for the current transform matrix based on |
|
58 * the panning and zooming logic that was invoked on the UI thread. |
|
59 * |
|
60 * Currently, each outer DOM window (i.e. a website in a tab, but not any |
|
61 * subframes) has its own AsyncPanZoomController. In the future, to support |
|
62 * asynchronously scrolled subframes, we want to have one AsyncPanZoomController |
|
63 * per frame. |
|
64 */ |
|
65 class AsyncPanZoomController { |
|
66 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AsyncPanZoomController) |
|
67 |
|
68 typedef mozilla::MonitorAutoLock MonitorAutoLock; |
|
69 typedef uint32_t TouchBehaviorFlags; |
|
70 |
|
71 public: |
|
72 enum GestureBehavior { |
|
73 // The platform code is responsible for forwarding gesture events here. We |
|
74 // will not attempt to generate gesture events from MultiTouchInputs. |
|
75 DEFAULT_GESTURES, |
|
76 // An instance of GestureEventListener is used to detect gestures. This is |
|
77 // handled completely internally within this class. |
|
78 USE_GESTURE_DETECTOR |
|
79 }; |
|
80 |
|
81 /** |
|
82 * Constant describing the tolerance in distance we use, multiplied by the |
|
83 * device DPI, before we start panning the screen. This is to prevent us from |
|
84 * accidentally processing taps as touch moves, and from very short/accidental |
|
85 * touches moving the screen. |
|
86 */ |
|
87 static float GetTouchStartTolerance(); |
|
88 |
|
89 AsyncPanZoomController(uint64_t aLayersId, |
|
90 APZCTreeManager* aTreeManager, |
|
91 GeckoContentController* aController, |
|
92 GestureBehavior aGestures = DEFAULT_GESTURES); |
|
93 |
|
94 // -------------------------------------------------------------------------- |
|
95 // These methods must only be called on the gecko thread. |
|
96 // |
|
97 |
|
98 /** |
|
99 * Read the various prefs and do any global initialization for all APZC instances. |
|
100 * This must be run on the gecko thread before any APZC instances are actually |
|
101 * used for anything meaningful. |
|
102 */ |
|
103 static void InitializeGlobalState(); |
|
104 |
|
105 // -------------------------------------------------------------------------- |
|
106 // These methods must only be called on the controller/UI thread. |
|
107 // |
|
108 |
|
109 /** |
|
110 * General handler for incoming input events. Manipulates the frame metrics |
|
111 * based on what type of input it is. For example, a PinchGestureEvent will |
|
112 * cause scaling. This should only be called externally to this class. |
|
113 * HandleInputEvent() should be used internally. |
|
114 */ |
|
115 nsEventStatus ReceiveInputEvent(const InputData& aEvent); |
|
116 |
|
117 /** |
|
118 * Kicks an animation to zoom to a rect. This may be either a zoom out or zoom |
|
119 * in. The actual animation is done on the compositor thread after being set |
|
120 * up. |
|
121 */ |
|
122 void ZoomToRect(CSSRect aRect); |
|
123 |
|
124 /** |
|
125 * If we have touch listeners, this should always be called when we know |
|
126 * definitively whether or not content has preventDefaulted any touch events |
|
127 * that have come in. If |aPreventDefault| is true, any touch events in the |
|
128 * queue will be discarded. |
|
129 */ |
|
130 void ContentReceivedTouch(bool aPreventDefault); |
|
131 |
|
132 /** |
|
133 * Updates any zoom constraints contained in the <meta name="viewport"> tag. |
|
134 */ |
|
135 void UpdateZoomConstraints(const ZoomConstraints& aConstraints); |
|
136 |
|
137 /** |
|
138 * Return the zoom constraints last set for this APZC (in the constructor |
|
139 * or in UpdateZoomConstraints()). |
|
140 */ |
|
141 ZoomConstraints GetZoomConstraints() const; |
|
142 |
|
143 /** |
|
144 * Schedules a runnable to run on the controller/UI thread at some time |
|
145 * in the future. |
|
146 */ |
|
147 void PostDelayedTask(Task* aTask, int aDelayMs); |
|
148 |
|
149 // -------------------------------------------------------------------------- |
|
150 // These methods must only be called on the compositor thread. |
|
151 // |
|
152 |
|
153 bool UpdateAnimation(const TimeStamp& aSampleTime); |
|
154 |
|
155 /** |
|
156 * The compositor calls this when it's about to draw pannable/zoomable content |
|
157 * and is setting up transforms for compositing the layer tree. This is not |
|
158 * idempotent. For example, a fling transform can be applied each time this is |
|
159 * called (though not necessarily). |aSampleTime| is the time that this is |
|
160 * sampled at; this is used for interpolating animations. Calling this sets a |
|
161 * new transform in |aNewTransform| which should be multiplied to the transform |
|
162 * in the shadow layer corresponding to this APZC. |
|
163 * |
|
164 * Return value indicates whether or not any currently running animation |
|
165 * should continue. That is, if true, the compositor should schedule another |
|
166 * composite. |
|
167 */ |
|
168 bool SampleContentTransformForFrame(const TimeStamp& aSampleTime, |
|
169 ViewTransform* aNewTransform, |
|
170 ScreenPoint& aScrollOffset); |
|
171 |
|
172 /** |
|
173 * A shadow layer update has arrived. |aLayerMetrics| is the new FrameMetrics |
|
174 * for the container layer corresponding to this APZC. |
|
175 * |aIsFirstPaint| is a flag passed from the shadow |
|
176 * layers code indicating that the frame metrics being sent with this call are |
|
177 * the initial metrics and the initial paint of the frame has just happened. |
|
178 */ |
|
179 void NotifyLayersUpdated(const FrameMetrics& aLayerMetrics, bool aIsFirstPaint); |
|
180 |
|
181 /** |
|
182 * The platform implementation must set the compositor parent so that we can |
|
183 * request composites. |
|
184 */ |
|
185 void SetCompositorParent(CompositorParent* aCompositorParent); |
|
186 |
|
187 /** |
|
188 * The platform implementation must set the cross process compositor if |
|
189 * there is one associated with the layer tree. The cross process compositor |
|
190 * allows the APZC to share its FrameMetrics with the content process. |
|
191 * The shared FrameMetrics is used in progressive paint updates. |
|
192 */ |
|
193 void SetCrossProcessCompositorParent(PCompositorParent* aCrossProcessCompositorParent); |
|
194 |
|
195 // -------------------------------------------------------------------------- |
|
196 // These methods can be called from any thread. |
|
197 // |
|
198 |
|
199 /** |
|
200 * Shut down the controller/UI thread state and prepare to be |
|
201 * deleted (which may happen from any thread). |
|
202 */ |
|
203 void Destroy(); |
|
204 |
|
205 /** |
|
206 * Returns true if Destroy() has already been called on this APZC instance. |
|
207 */ |
|
208 bool IsDestroyed(); |
|
209 |
|
210 /** |
|
211 * Returns the incremental transformation corresponding to the async pan/zoom |
|
212 * in progress. That is, when this transform is multiplied with the layer's |
|
213 * existing transform, it will make the layer appear with the desired pan/zoom |
|
214 * amount. |
|
215 */ |
|
216 ViewTransform GetCurrentAsyncTransform(); |
|
217 |
|
218 /** |
|
219 * Returns the part of the async transform that will remain once Gecko does a |
|
220 * repaint at the desired metrics. That is, in the steady state: |
|
221 * gfx3DMatrix(GetCurrentAsyncTransform()) === GetNontransientAsyncTransform() |
|
222 */ |
|
223 gfx3DMatrix GetNontransientAsyncTransform(); |
|
224 |
|
225 /** |
|
226 * Returns the transform to take something from the coordinate space of the |
|
227 * last thing we know gecko painted, to the coordinate space of the last thing |
|
228 * we asked gecko to paint. In cases where that last request has not yet been |
|
229 * processed, this is needed to transform input events properly into a space |
|
230 * gecko will understand. |
|
231 */ |
|
232 gfx3DMatrix GetTransformToLastDispatchedPaint(); |
|
233 |
|
234 /** |
|
235 * Recalculates the displayport. Ideally, this should paint an area bigger |
|
236 * than the composite-to dimensions so that when you scroll down, you don't |
|
237 * checkerboard immediately. This includes a bunch of logic, including |
|
238 * algorithms to bias painting in the direction of the velocity. |
|
239 */ |
|
240 static const LayerMargin CalculatePendingDisplayPort( |
|
241 const FrameMetrics& aFrameMetrics, |
|
242 const ScreenPoint& aVelocity, |
|
243 double aEstimatedPaintDuration); |
|
244 |
|
245 /** |
|
246 * Send an mozbrowserasyncscroll event. |
|
247 * *** The monitor must be held while calling this. |
|
248 */ |
|
249 void SendAsyncScrollEvent(); |
|
250 |
|
251 /** |
|
252 * Handler for events which should not be intercepted by the touch listener. |
|
253 * Does the work for ReceiveInputEvent(). |
|
254 */ |
|
255 nsEventStatus HandleInputEvent(const InputData& aEvent); |
|
256 |
|
257 /** |
|
258 * Handler for gesture events. |
|
259 * Currently some gestures are detected in GestureEventListener that calls |
|
260 * APZC back through this handler in order to avoid recursive calls to |
|
261 * APZC::HandleInputEvent() which is supposed to do the work for |
|
262 * ReceiveInputEvent(). |
|
263 */ |
|
264 nsEventStatus HandleGestureEvent(const InputData& aEvent); |
|
265 |
|
266 /** |
|
267 * Populates the provided object (if non-null) with the scrollable guid of this apzc. |
|
268 */ |
|
269 void GetGuid(ScrollableLayerGuid* aGuidOut); |
|
270 |
|
271 /** |
|
272 * Returns the scrollable guid of this apzc. |
|
273 */ |
|
274 ScrollableLayerGuid GetGuid(); |
|
275 |
|
276 /** |
|
277 * Returns true if this APZC instance is for the layer identified by the guid. |
|
278 */ |
|
279 bool Matches(const ScrollableLayerGuid& aGuid); |
|
280 |
|
281 /** |
|
282 * Sync panning and zooming animation using a fixed frame time. |
|
283 * This will ensure that we animate the APZC correctly with other external |
|
284 * animations to the same timestamp. |
|
285 */ |
|
286 static void SetFrameTime(const TimeStamp& aMilliseconds); |
|
287 |
|
288 void StartAnimation(AsyncPanZoomAnimation* aAnimation); |
|
289 |
|
290 /** |
|
291 * Cancels any currently running animation. Note that all this does is set the |
|
292 * state of the AsyncPanZoomController back to NOTHING, but it is the |
|
293 * animation's responsibility to check this before advancing. |
|
294 */ |
|
295 void CancelAnimation(); |
|
296 |
|
297 /** |
|
298 * Take over a fling with the given velocity from another APZC. Used for |
|
299 * during overscroll handoff for a fling. |
|
300 */ |
|
301 void TakeOverFling(ScreenPoint aVelocity); |
|
302 |
|
303 /** |
|
304 * Returns allowed touch behavior for the given point on the scrollable layer. |
|
305 * Internally performs a kind of hit testing based on the regions constructed |
|
306 * on the main thread and attached to the current scrollable layer. Each of such regions |
|
307 * contains info about allowed touch behavior. If regions info isn't enough it returns |
|
308 * UNKNOWN value and we should switch to the fallback approach - asking content. |
|
309 * TODO: for now it's only a stub and returns hardcoded magic value. As soon as bug 928833 |
|
310 * is done we should integrate its logic here. |
|
311 */ |
|
312 TouchBehaviorFlags GetAllowedTouchBehavior(ScreenIntPoint& aPoint); |
|
313 |
|
314 /** |
|
315 * Sets allowed touch behavior for current touch session. |
|
316 * This method is invoked by the APZCTreeManager which in its turn invoked by |
|
317 * the widget after performing touch-action values retrieving. |
|
318 * Must be called after receiving the TOUCH_START even that started the |
|
319 * touch session. |
|
320 */ |
|
321 void SetAllowedTouchBehavior(const nsTArray<TouchBehaviorFlags>& aBehaviors); |
|
322 |
|
323 /** |
|
324 * Returns whether this APZC is for an element marked with the 'scrollgrab' |
|
325 * attribute. |
|
326 */ |
|
327 bool HasScrollgrab() const { return mFrameMetrics.mHasScrollgrab; } |
|
328 |
|
329 /** |
|
330 * Set an extra offset for testing async scrolling. |
|
331 */ |
|
332 void SetTestAsyncScrollOffset(const CSSPoint& aPoint) |
|
333 { |
|
334 mTestAsyncScrollOffset = aPoint; |
|
335 } |
|
336 |
|
337 /** |
|
338 * Returns whether this APZC has room to be panned (in any direction). |
|
339 */ |
|
340 bool IsPannable() const; |
|
341 |
|
342 protected: |
|
343 // Protected destructor, to discourage deletion outside of Release(): |
|
344 ~AsyncPanZoomController(); |
|
345 |
|
346 /** |
|
347 * Helper method for touches beginning. Sets everything up for panning and any |
|
348 * multitouch gestures. |
|
349 */ |
|
350 nsEventStatus OnTouchStart(const MultiTouchInput& aEvent); |
|
351 |
|
352 /** |
|
353 * Helper method for touches moving. Does any transforms needed when panning. |
|
354 */ |
|
355 nsEventStatus OnTouchMove(const MultiTouchInput& aEvent); |
|
356 |
|
357 /** |
|
358 * Helper method for touches ending. Redraws the screen if necessary and does |
|
359 * any cleanup after a touch has ended. |
|
360 */ |
|
361 nsEventStatus OnTouchEnd(const MultiTouchInput& aEvent); |
|
362 |
|
363 /** |
|
364 * Helper method for touches being cancelled. Treated roughly the same as a |
|
365 * touch ending (OnTouchEnd()). |
|
366 */ |
|
367 nsEventStatus OnTouchCancel(const MultiTouchInput& aEvent); |
|
368 |
|
369 /** |
|
370 * Helper method for scales beginning. Distinct from the OnTouch* handlers in |
|
371 * that this implies some outside implementation has determined that the user |
|
372 * is pinching. |
|
373 */ |
|
374 nsEventStatus OnScaleBegin(const PinchGestureInput& aEvent); |
|
375 |
|
376 /** |
|
377 * Helper method for scaling. As the user moves their fingers when pinching, |
|
378 * this changes the scale of the page. |
|
379 */ |
|
380 nsEventStatus OnScale(const PinchGestureInput& aEvent); |
|
381 |
|
382 /** |
|
383 * Helper method for scales ending. Redraws the screen if necessary and does |
|
384 * any cleanup after a scale has ended. |
|
385 */ |
|
386 nsEventStatus OnScaleEnd(const PinchGestureInput& aEvent); |
|
387 |
|
388 /** |
|
389 * Helper methods for long press gestures. |
|
390 */ |
|
391 nsEventStatus OnLongPress(const TapGestureInput& aEvent); |
|
392 nsEventStatus OnLongPressUp(const TapGestureInput& aEvent); |
|
393 |
|
394 /** |
|
395 * Helper method for single tap gestures. |
|
396 */ |
|
397 nsEventStatus OnSingleTapUp(const TapGestureInput& aEvent); |
|
398 |
|
399 /** |
|
400 * Helper method for a single tap confirmed. |
|
401 */ |
|
402 nsEventStatus OnSingleTapConfirmed(const TapGestureInput& aEvent); |
|
403 |
|
404 /** |
|
405 * Helper method for double taps. |
|
406 */ |
|
407 nsEventStatus OnDoubleTap(const TapGestureInput& aEvent); |
|
408 |
|
409 /** |
|
410 * Helper method to cancel any gesture currently going to Gecko. Used |
|
411 * primarily when a user taps the screen over some clickable content but then |
|
412 * pans down instead of letting go (i.e. to cancel a previous touch so that a |
|
413 * new one can properly take effect. |
|
414 */ |
|
415 nsEventStatus OnCancelTap(const TapGestureInput& aEvent); |
|
416 |
|
417 /** |
|
418 * Scrolls the viewport by an X,Y offset. |
|
419 */ |
|
420 void ScrollBy(const CSSPoint& aOffset); |
|
421 |
|
422 /** |
|
423 * Scales the viewport by an amount (note that it multiplies this scale in to |
|
424 * the current scale, it doesn't set it to |aScale|). Also considers a focus |
|
425 * point so that the page zooms inward/outward from that point. |
|
426 */ |
|
427 void ScaleWithFocus(float aScale, |
|
428 const CSSPoint& aFocus); |
|
429 |
|
430 /** |
|
431 * Schedules a composite on the compositor thread. Wrapper for |
|
432 * CompositorParent::ScheduleRenderOnCompositorThread(). |
|
433 */ |
|
434 void ScheduleComposite(); |
|
435 |
|
436 /** |
|
437 * Gets the displacement of the current touch since it began. That is, it is |
|
438 * the distance between the current position and the initial position of the |
|
439 * current touch (this only makes sense if a touch is currently happening and |
|
440 * OnTouchMove() is being invoked). |
|
441 */ |
|
442 float PanDistance(); |
|
443 |
|
444 /** |
|
445 * Gets a vector of the velocities of each axis. |
|
446 */ |
|
447 const ScreenPoint GetVelocityVector(); |
|
448 |
|
449 /** |
|
450 * Gets a reference to the first touch point from a MultiTouchInput. This |
|
451 * gets only the first one and assumes the rest are either missing or not |
|
452 * relevant. |
|
453 */ |
|
454 ScreenIntPoint& GetFirstTouchScreenPoint(const MultiTouchInput& aEvent); |
|
455 |
|
456 /** |
|
457 * Sets the panning state basing on the pan direction angle and current touch-action value. |
|
458 */ |
|
459 void HandlePanningWithTouchAction(double angle, TouchBehaviorFlags value); |
|
460 |
|
461 /** |
|
462 * Sets the panning state ignoring the touch action value. |
|
463 */ |
|
464 void HandlePanning(double angle); |
|
465 |
|
466 /** |
|
467 * Sets up anything needed for panning. This takes us out of the "TOUCHING" |
|
468 * state and starts actually panning us. |
|
469 */ |
|
470 nsEventStatus StartPanning(const MultiTouchInput& aStartPoint); |
|
471 |
|
472 /** |
|
473 * Wrapper for Axis::UpdateWithTouchAtDevicePoint(). Calls this function for |
|
474 * both axes and factors in the time delta from the last update. |
|
475 */ |
|
476 void UpdateWithTouchAtDevicePoint(const MultiTouchInput& aEvent); |
|
477 |
|
478 /** |
|
479 * Does any panning required due to a new touch event. |
|
480 */ |
|
481 void TrackTouch(const MultiTouchInput& aEvent); |
|
482 |
|
483 /** |
|
484 * Utility function to send updated FrameMetrics to Gecko so that it can paint |
|
485 * the displayport area. Calls into GeckoContentController to do the actual |
|
486 * work. Note that only one paint request can be active at a time. If a paint |
|
487 * request is made while a paint is currently happening, it gets queued up. If |
|
488 * a new paint request arrives before a paint is completed, the old request |
|
489 * gets discarded. |
|
490 */ |
|
491 void RequestContentRepaint(); |
|
492 |
|
493 /** |
|
494 * Tell the paint throttler to request a content repaint with the given |
|
495 * metrics. (Helper function used by RequestContentRepaint.) |
|
496 */ |
|
497 void RequestContentRepaint(FrameMetrics& aFrameMetrics); |
|
498 |
|
499 /** |
|
500 * Actually send the next pending paint request to gecko. |
|
501 */ |
|
502 void DispatchRepaintRequest(const FrameMetrics& aFrameMetrics); |
|
503 |
|
504 /** |
|
505 * Advances a fling by an interpolated amount based on the passed in |aDelta|. |
|
506 * This should be called whenever sampling the content transform for this |
|
507 * frame. Returns true if the fling animation should be advanced by one frame, |
|
508 * or false if there is no fling or the fling has ended. |
|
509 */ |
|
510 bool DoFling(const TimeDuration& aDelta); |
|
511 |
|
512 /** |
|
513 * Gets the current frame metrics. This is *not* the Gecko copy stored in the |
|
514 * layers code. |
|
515 */ |
|
516 const FrameMetrics& GetFrameMetrics(); |
|
517 |
|
518 /** |
|
519 * Sets the timer for content response to a series of touch events, if it |
|
520 * hasn't been already. This is to prevent us from batching up touch events |
|
521 * indefinitely in the case that content doesn't respond with whether or not |
|
522 * it wants to preventDefault. When the timer is fired, the touch event queue |
|
523 * will be flushed. |
|
524 */ |
|
525 void SetContentResponseTimer(); |
|
526 |
|
527 /** |
|
528 * Timeout function for content response. This should be called on a timer |
|
529 * after we get our first touch event in a batch, under the condition that we |
|
530 * waiting for response from content. If a notification comes indicating whether or not |
|
531 * content preventDefaulted a series of touch events and touch behavior values are |
|
532 * set before the timeout, the timeout should be cancelled. |
|
533 */ |
|
534 void TimeoutContentResponse(); |
|
535 |
|
536 /** |
|
537 * Timeout function for mozbrowserasyncscroll event. Because we throttle |
|
538 * mozbrowserasyncscroll events in some conditions, this function ensures |
|
539 * that the last mozbrowserasyncscroll event will be fired after a period of |
|
540 * time. |
|
541 */ |
|
542 void FireAsyncScrollOnTimeout(); |
|
543 |
|
544 private: |
|
545 enum PanZoomState { |
|
546 NOTHING, /* no touch-start events received */ |
|
547 FLING, /* all touches removed, but we're still scrolling page */ |
|
548 TOUCHING, /* one touch-start event received */ |
|
549 |
|
550 PANNING, /* panning the frame */ |
|
551 PANNING_LOCKED_X, /* touch-start followed by move (i.e. panning with axis lock) X axis */ |
|
552 PANNING_LOCKED_Y, /* as above for Y axis */ |
|
553 |
|
554 CROSS_SLIDING_X, /* Panning disabled while user does a horizontal gesture |
|
555 on a vertically-scrollable view. This used for the |
|
556 Windows Metro "cross-slide" gesture. */ |
|
557 CROSS_SLIDING_Y, /* as above for Y axis */ |
|
558 |
|
559 PINCHING, /* nth touch-start, where n > 1. this mode allows pan and zoom */ |
|
560 ANIMATING_ZOOM, /* animated zoom to a new rect */ |
|
561 WAITING_CONTENT_RESPONSE, /* a state halfway between NOTHING and TOUCHING - the user has |
|
562 put a finger down, but we don't yet know if a touch listener has |
|
563 prevented the default actions yet and the allowed touch behavior |
|
564 was not set yet. we still need to abort animations. */ |
|
565 }; |
|
566 |
|
567 // State related to a single touch block. Does not persist across touch blocks. |
|
568 struct TouchBlockState { |
|
569 |
|
570 TouchBlockState() |
|
571 : mAllowedTouchBehaviorSet(false), |
|
572 mPreventDefault(false), |
|
573 mPreventDefaultSet(false), |
|
574 mSingleTapOccurred(false) |
|
575 {} |
|
576 |
|
577 // Values of allowed touch behavior for touch points of this touch block. |
|
578 // Since there are maybe a few current active touch points per time (multitouch case) |
|
579 // and each touch point should have its own value of allowed touch behavior- we're |
|
580 // keeping an array of allowed touch behavior values, not the single value. |
|
581 nsTArray<TouchBehaviorFlags> mAllowedTouchBehaviors; |
|
582 |
|
583 // Specifies whether mAllowedTouchBehaviors is set for this touch events block. |
|
584 bool mAllowedTouchBehaviorSet; |
|
585 |
|
586 // Flag used to specify that content prevented the default behavior of this |
|
587 // touch events block. |
|
588 bool mPreventDefault; |
|
589 |
|
590 // Specifies whether mPreventDefault property is set for this touch events block. |
|
591 bool mPreventDefaultSet; |
|
592 |
|
593 // Specifies whether a single tap event was generated during this touch block. |
|
594 bool mSingleTapOccurred; |
|
595 }; |
|
596 |
|
597 /* |
|
598 * Returns whether current touch behavior values allow pinch-zooming. |
|
599 */ |
|
600 bool TouchActionAllowPinchZoom(); |
|
601 |
|
602 /* |
|
603 * Returns whether current touch behavior values allow double-tap-zooming. |
|
604 */ |
|
605 bool TouchActionAllowDoubleTapZoom(); |
|
606 |
|
607 /* |
|
608 * Returns allowed touch behavior from the mAllowedTouchBehavior array. |
|
609 * In case apzc didn't receive touch behavior values within the timeout |
|
610 * it returns default value. |
|
611 */ |
|
612 TouchBehaviorFlags GetTouchBehavior(uint32_t touchIndex); |
|
613 |
|
614 /** |
|
615 * To move from the WAITING_CONTENT_RESPONSE state to TOUCHING one we need two |
|
616 * conditions set: get content listeners response (whether they called preventDefault) |
|
617 * and get allowed touch behaviors. |
|
618 * This method checks both conditions and changes (or not changes) state |
|
619 * appropriately. |
|
620 */ |
|
621 void CheckContentResponse(); |
|
622 |
|
623 /** |
|
624 * Helper to set the current state. Holds the monitor before actually setting |
|
625 * it and fires content controller events based on state changes. Always set |
|
626 * the state using this call, do not set it directly. |
|
627 */ |
|
628 void SetState(PanZoomState aState); |
|
629 |
|
630 /** |
|
631 * Convert ScreenPoint relative to this APZC to CSSPoint relative |
|
632 * to the parent document. This excludes the transient compositor transform. |
|
633 * NOTE: This must be converted to CSSPoint relative to the child |
|
634 * document before sending over IPC. |
|
635 */ |
|
636 bool ConvertToGecko(const ScreenPoint& aPoint, CSSPoint* aOut); |
|
637 |
|
638 /** |
|
639 * Internal helpers for checking general state of this apzc. |
|
640 */ |
|
641 bool IsTransformingState(PanZoomState aState); |
|
642 bool IsPanningState(PanZoomState mState); |
|
643 |
|
644 enum AxisLockMode { |
|
645 FREE, /* No locking at all */ |
|
646 STANDARD, /* Default axis locking mode that remains locked until pan ends*/ |
|
647 STICKY, /* Allow lock to be broken, with hysteresis */ |
|
648 }; |
|
649 |
|
650 static AxisLockMode GetAxisLockMode(); |
|
651 |
|
652 // Convert a point from local screen coordinates to parent layer coordinates. |
|
653 // This is a common operation as inputs from the tree manager are in screen |
|
654 // coordinates but the composition bounds is in parent layer coordinates. |
|
655 ParentLayerPoint ToParentLayerCoords(const ScreenPoint& aPoint); |
|
656 |
|
657 // Update mFrameMetrics.mTransformScale. This should be called whenever |
|
658 // our CSS transform or the non-transient part of our async transform |
|
659 // changes, as it corresponds to the scale portion of those transforms. |
|
660 void UpdateTransformScale(); |
|
661 |
|
662 // Helper function for OnSingleTapUp() and OnSingleTapConfirmed(). |
|
663 nsEventStatus GenerateSingleTap(const ScreenIntPoint& aPoint, mozilla::Modifiers aModifiers); |
|
664 |
|
665 // Common processing at the end of a touch block. |
|
666 void OnTouchEndOrCancel(); |
|
667 |
|
668 uint64_t mLayersId; |
|
669 nsRefPtr<CompositorParent> mCompositorParent; |
|
670 PCompositorParent* mCrossProcessCompositorParent; |
|
671 TaskThrottler mPaintThrottler; |
|
672 |
|
673 /* Access to the following two fields is protected by the mRefPtrMonitor, |
|
674 since they are accessed on the UI thread but can be cleared on the |
|
675 compositor thread. */ |
|
676 nsRefPtr<GeckoContentController> mGeckoContentController; |
|
677 nsRefPtr<GestureEventListener> mGestureEventListener; |
|
678 Monitor mRefPtrMonitor; |
|
679 |
|
680 /* Utility functions that return a addrefed pointer to the corresponding fields. */ |
|
681 already_AddRefed<GeckoContentController> GetGeckoContentController(); |
|
682 already_AddRefed<GestureEventListener> GetGestureEventListener(); |
|
683 |
|
684 protected: |
|
685 // Both |mFrameMetrics| and |mLastContentPaintMetrics| are protected by the |
|
686 // monitor. Do not read from or modify either of them without locking. |
|
687 FrameMetrics mFrameMetrics; |
|
688 |
|
689 // Protects |mFrameMetrics|, |mLastContentPaintMetrics|, and |mState|. |
|
690 // Before manipulating |mFrameMetrics| or |mLastContentPaintMetrics|, the |
|
691 // monitor should be held. When setting |mState|, either the SetState() |
|
692 // function can be used, or the monitor can be held and then |mState| updated. |
|
693 // IMPORTANT: See the note about lock ordering at the top of APZCTreeManager.h. |
|
694 // This is mutable to allow entering it from 'const' methods; doing otherwise |
|
695 // would significantly limit what methods could be 'const'. |
|
696 mutable ReentrantMonitor mMonitor; |
|
697 |
|
698 // Specifies whether we should use touch-action css property. Initialized from |
|
699 // the preferences. This property (in comparison with the global one) simplifies |
|
700 // testing apzc with (and without) touch-action property enabled concurrently |
|
701 // (e.g. with the gtest framework). |
|
702 bool mTouchActionPropertyEnabled; |
|
703 |
|
704 private: |
|
705 // Metrics of the container layer corresponding to this APZC. This is |
|
706 // stored here so that it is accessible from the UI/controller thread. |
|
707 // These are the metrics at last content paint, the most recent |
|
708 // values we were notified of in NotifyLayersUpdate(). Since it represents |
|
709 // the Gecko state, it should be used as a basis for untransformation when |
|
710 // sending messages back to Gecko. |
|
711 FrameMetrics mLastContentPaintMetrics; |
|
712 // The last metrics that we requested a paint for. These are used to make sure |
|
713 // that we're not requesting a paint of the same thing that's already drawn. |
|
714 // If we don't do this check, we don't get a ShadowLayersUpdated back. |
|
715 FrameMetrics mLastPaintRequestMetrics; |
|
716 // The last metrics that we actually sent to Gecko. This allows us to transform |
|
717 // inputs into a coordinate space that Gecko knows about. This assumes the pipe |
|
718 // through which input events and repaint requests are sent to Gecko operates |
|
719 // in a FIFO manner. |
|
720 FrameMetrics mLastDispatchedPaintMetrics; |
|
721 |
|
722 nsTArray<MultiTouchInput> mTouchQueue; |
|
723 |
|
724 CancelableTask* mContentResponseTimeoutTask; |
|
725 |
|
726 AxisX mX; |
|
727 AxisY mY; |
|
728 |
|
729 // This flag is set to true when we are in a axis-locked pan as a result of |
|
730 // the touch-action CSS property. |
|
731 bool mPanDirRestricted; |
|
732 |
|
733 // Most up-to-date constraints on zooming. These should always be reasonable |
|
734 // values; for example, allowing a min zoom of 0.0 can cause very bad things |
|
735 // to happen. |
|
736 ZoomConstraints mZoomConstraints; |
|
737 |
|
738 // The last time the compositor has sampled the content transform for this |
|
739 // frame. |
|
740 TimeStamp mLastSampleTime; |
|
741 // The last time a touch event came through on the UI thread. |
|
742 uint32_t mLastEventTime; |
|
743 |
|
744 // Stores the previous focus point if there is a pinch gesture happening. Used |
|
745 // to allow panning by moving multiple fingers (thus moving the focus point). |
|
746 ParentLayerPoint mLastZoomFocus; |
|
747 |
|
748 // Stores the state of panning and zooming this frame. This is protected by |
|
749 // |mMonitor|; that is, it should be held whenever this is updated. |
|
750 PanZoomState mState; |
|
751 |
|
752 // The last time and offset we fire the mozbrowserasyncscroll event when |
|
753 // compositor has sampled the content transform for this frame. |
|
754 TimeStamp mLastAsyncScrollTime; |
|
755 CSSPoint mLastAsyncScrollOffset; |
|
756 |
|
757 // The current offset drawn on the screen, it may not be sent since we have |
|
758 // throttling policy for mozbrowserasyncscroll event. |
|
759 CSSPoint mCurrentAsyncScrollOffset; |
|
760 |
|
761 // The delay task triggered by the throttling mozbrowserasyncscroll event |
|
762 // ensures the last mozbrowserasyncscroll event is always been fired. |
|
763 CancelableTask* mAsyncScrollTimeoutTask; |
|
764 |
|
765 // Flag used to determine whether or not we should try to enter the |
|
766 // WAITING_LISTENERS state. This is used in the case that we are processing a |
|
767 // queued up event block. If set, this means that we are handling this queue |
|
768 // and we don't want to queue the events back up again. |
|
769 bool mHandlingTouchQueue; |
|
770 |
|
771 // Stores information about the current touch block. |
|
772 TouchBlockState mTouchBlockState; |
|
773 |
|
774 // Extra offset to add in SampleContentTransformForFrame for testing |
|
775 CSSPoint mTestAsyncScrollOffset; |
|
776 |
|
777 RefPtr<AsyncPanZoomAnimation> mAnimation; |
|
778 |
|
779 friend class Axis; |
|
780 friend class FlingAnimation; |
|
781 |
|
782 |
|
783 /* =================================================================== |
|
784 * The functions and members in this section are used to build a tree |
|
785 * structure out of APZC instances. This tree can only be walked or |
|
786 * manipulated while holding the lock in the associated APZCTreeManager |
|
787 * instance. |
|
788 */ |
|
789 public: |
|
790 void SetLastChild(AsyncPanZoomController* child) { |
|
791 mLastChild = child; |
|
792 if (child) { |
|
793 child->mParent = this; |
|
794 } |
|
795 } |
|
796 |
|
797 void SetPrevSibling(AsyncPanZoomController* sibling) { |
|
798 mPrevSibling = sibling; |
|
799 if (sibling) { |
|
800 sibling->mParent = mParent; |
|
801 } |
|
802 } |
|
803 |
|
804 AsyncPanZoomController* GetLastChild() const { return mLastChild; } |
|
805 AsyncPanZoomController* GetPrevSibling() const { return mPrevSibling; } |
|
806 AsyncPanZoomController* GetParent() const { return mParent; } |
|
807 |
|
808 /* Returns true if there is no APZC higher in the tree with the same |
|
809 * layers id. |
|
810 */ |
|
811 bool IsRootForLayersId() const { |
|
812 return !mParent || (mParent->mLayersId != mLayersId); |
|
813 } |
|
814 |
|
815 bool IsRootForLayersId(const uint64_t& aLayersId) const { |
|
816 return (mLayersId == aLayersId) && IsRootForLayersId(); |
|
817 } |
|
818 |
|
819 private: |
|
820 // This is a raw pointer to avoid introducing a reference cycle between |
|
821 // AsyncPanZoomController and APZCTreeManager. Since these objects don't |
|
822 // live on the main thread, we can't use the cycle collector with them. |
|
823 // The APZCTreeManager owns the lifetime of the APZCs, so nulling this |
|
824 // pointer out in Destroy() will prevent accessing deleted memory. |
|
825 Atomic<APZCTreeManager*> mTreeManager; |
|
826 |
|
827 nsRefPtr<AsyncPanZoomController> mLastChild; |
|
828 nsRefPtr<AsyncPanZoomController> mPrevSibling; |
|
829 nsRefPtr<AsyncPanZoomController> mParent; |
|
830 |
|
831 |
|
832 /* =================================================================== |
|
833 * The functions and members in this section are used in building the |
|
834 * scroll handoff chain, so that we can have seamless scrolling continue |
|
835 * across APZC instances. |
|
836 */ |
|
837 public: |
|
838 void SetScrollHandoffParentId(FrameMetrics::ViewID aScrollParentId) { |
|
839 mScrollParentId = aScrollParentId; |
|
840 } |
|
841 |
|
842 FrameMetrics::ViewID GetScrollHandoffParentId() const { |
|
843 return mScrollParentId; |
|
844 } |
|
845 |
|
846 /** |
|
847 * Attempt to scroll in response to a touch-move from |aStartPoint| to |
|
848 * |aEndPoint|, which are in our (transformed) screen coordinates. |
|
849 * Due to overscroll handling, there may not actually have been a touch-move |
|
850 * at these points, but this function will scroll as if there had been. |
|
851 * If this attempt causes overscroll (i.e. the layer cannot be scrolled |
|
852 * by the entire amount requested), the overscroll is passed back to the |
|
853 * tree manager via APZCTreeManager::DispatchScroll(). |
|
854 * |aOverscrollHandoffChainIndex| is used by the tree manager to keep track |
|
855 * of which APZC to hand off the overscroll to; this function increments it |
|
856 * and passes it on to APZCTreeManager::DispatchScroll() in the event of |
|
857 * overscroll. |
|
858 */ |
|
859 void AttemptScroll(const ScreenPoint& aStartPoint, const ScreenPoint& aEndPoint, |
|
860 uint32_t aOverscrollHandoffChainIndex = 0); |
|
861 |
|
862 void FlushRepaintForOverscrollHandoff(); |
|
863 |
|
864 private: |
|
865 FrameMetrics::ViewID mScrollParentId; |
|
866 |
|
867 /** |
|
868 * A helper function for calling APZCTreeManager::DispatchScroll(). |
|
869 * Guards against the case where the APZC is being concurrently destroyed |
|
870 * (and thus mTreeManager is being nulled out). |
|
871 */ |
|
872 void CallDispatchScroll(const ScreenPoint& aStartPoint, const ScreenPoint& aEndPoint, |
|
873 uint32_t aOverscrollHandoffChainIndex); |
|
874 |
|
875 |
|
876 /* =================================================================== |
|
877 * The functions and members in this section are used to maintain the |
|
878 * area that this APZC instance is responsible for. This is used when |
|
879 * hit-testing to see which APZC instance should handle touch events. |
|
880 */ |
|
881 public: |
|
882 void SetLayerHitTestData(const ParentLayerRect& aRect, const gfx3DMatrix& aTransformToLayer, |
|
883 const gfx3DMatrix& aTransformForLayer) { |
|
884 mVisibleRect = aRect; |
|
885 mAncestorTransform = aTransformToLayer; |
|
886 mCSSTransform = aTransformForLayer; |
|
887 UpdateTransformScale(); |
|
888 } |
|
889 |
|
890 gfx3DMatrix GetAncestorTransform() const { |
|
891 return mAncestorTransform; |
|
892 } |
|
893 |
|
894 gfx3DMatrix GetCSSTransform() const { |
|
895 return mCSSTransform; |
|
896 } |
|
897 |
|
898 bool VisibleRegionContains(const ParentLayerPoint& aPoint) const { |
|
899 return mVisibleRect.Contains(aPoint); |
|
900 } |
|
901 |
|
902 private: |
|
903 /* This is the visible region of the layer that this APZC corresponds to, in |
|
904 * that layer's screen pixels (the same coordinate system in which this APZC |
|
905 * receives events in ReceiveInputEvent()). */ |
|
906 ParentLayerRect mVisibleRect; |
|
907 /* This is the cumulative CSS transform for all the layers between the parent |
|
908 * APZC and this one (not inclusive) */ |
|
909 gfx3DMatrix mAncestorTransform; |
|
910 /* This is the CSS transform for this APZC's layer. */ |
|
911 gfx3DMatrix mCSSTransform; |
|
912 |
|
913 |
|
914 /* =================================================================== |
|
915 * The functions and members in this section are used for sharing the |
|
916 * FrameMetrics across processes for the progressive tiling code. |
|
917 */ |
|
918 private: |
|
919 /* Unique id assigned to each APZC. Used with ViewID to uniquely identify |
|
920 * shared FrameMeterics used in progressive tile painting. */ |
|
921 const uint32_t mAPZCId; |
|
922 |
|
923 ipc::SharedMemoryBasic* mSharedFrameMetricsBuffer; |
|
924 CrossProcessMutex* mSharedLock; |
|
925 /** |
|
926 * Called when ever mFrameMetrics is updated so that if it is being |
|
927 * shared with the content process the shared FrameMetrics may be updated. |
|
928 */ |
|
929 void UpdateSharedCompositorFrameMetrics(); |
|
930 /** |
|
931 * Create a shared memory buffer for containing the FrameMetrics and |
|
932 * a CrossProcessMutex that may be shared with the content process |
|
933 * for use in progressive tiled update calculations. |
|
934 */ |
|
935 void ShareCompositorFrameMetrics(); |
|
936 }; |
|
937 |
|
938 class AsyncPanZoomAnimation { |
|
939 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AsyncPanZoomAnimation) |
|
940 |
|
941 public: |
|
942 AsyncPanZoomAnimation(const TimeDuration& aRepaintInterval = |
|
943 TimeDuration::Forever()) |
|
944 : mRepaintInterval(aRepaintInterval) |
|
945 { } |
|
946 |
|
947 virtual bool Sample(FrameMetrics& aFrameMetrics, |
|
948 const TimeDuration& aDelta) = 0; |
|
949 |
|
950 /** |
|
951 * Get the deferred tasks in |mDeferredTasks|. See |mDeferredTasks| |
|
952 * for more information. |
|
953 * Clears |mDeferredTasks|. |
|
954 */ |
|
955 Vector<Task*> TakeDeferredTasks() { |
|
956 Vector<Task*> result; |
|
957 mDeferredTasks.swap(result); |
|
958 return result; |
|
959 } |
|
960 |
|
961 /** |
|
962 * Specifies how frequently (at most) we want to do repaints during the |
|
963 * animation sequence. TimeDuration::Forever() will cause it to only repaint |
|
964 * at the end of the animation. |
|
965 */ |
|
966 TimeDuration mRepaintInterval; |
|
967 |
|
968 protected: |
|
969 // Protected destructor, to discourage deletion outside of Release(): |
|
970 virtual ~AsyncPanZoomAnimation() |
|
971 { } |
|
972 |
|
973 /** |
|
974 * Tasks scheduled for execution after the APZC's mMonitor is released. |
|
975 * Derived classes can add tasks here in Sample(), and the APZC can call |
|
976 * ExecuteDeferredTasks() to execute them. |
|
977 */ |
|
978 Vector<Task*> mDeferredTasks; |
|
979 }; |
|
980 |
|
981 } |
|
982 } |
|
983 |
|
984 #endif // mozilla_layers_PanZoomController_h |