1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/layers/apz/src/AsyncPanZoomController.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,984 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set sw=2 ts=8 et tw=80 : */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#ifndef mozilla_layers_AsyncPanZoomController_h 1.11 +#define mozilla_layers_AsyncPanZoomController_h 1.12 + 1.13 +#include "CrossProcessMutex.h" 1.14 +#include "mozilla/layers/GeckoContentController.h" 1.15 +#include "mozilla/Attributes.h" 1.16 +#include "mozilla/EventForwards.h" 1.17 +#include "mozilla/Monitor.h" 1.18 +#include "mozilla/ReentrantMonitor.h" 1.19 +#include "mozilla/RefPtr.h" 1.20 +#include "mozilla/Atomics.h" 1.21 +#include "InputData.h" 1.22 +#include "Axis.h" 1.23 +#include "TaskThrottler.h" 1.24 +#include "gfx3DMatrix.h" 1.25 + 1.26 +#include "base/message_loop.h" 1.27 + 1.28 +namespace mozilla { 1.29 + 1.30 +namespace ipc { 1.31 + 1.32 +class SharedMemoryBasic; 1.33 + 1.34 +} 1.35 + 1.36 +namespace layers { 1.37 + 1.38 +struct ScrollableLayerGuid; 1.39 +class CompositorParent; 1.40 +class GestureEventListener; 1.41 +class ContainerLayer; 1.42 +class PCompositorParent; 1.43 +class ViewTransform; 1.44 +class APZCTreeManager; 1.45 +class AsyncPanZoomAnimation; 1.46 +class FlingAnimation; 1.47 + 1.48 +/** 1.49 + * Controller for all panning and zooming logic. Any time a user input is 1.50 + * detected and it must be processed in some way to affect what the user sees, 1.51 + * it goes through here. Listens for any input event from InputData and can 1.52 + * optionally handle WidgetGUIEvent-derived touch events, but this must be done 1.53 + * on the main thread. Note that this class completely cross-platform. 1.54 + * 1.55 + * Input events originate on the UI thread of the platform that this runs on, 1.56 + * and are then sent to this class. This class processes the event in some way; 1.57 + * for example, a touch move will usually lead to a panning of content (though 1.58 + * of course there are exceptions, such as if content preventDefaults the event, 1.59 + * or if the target frame is not scrollable). The compositor interacts with this 1.60 + * class by locking it and querying it for the current transform matrix based on 1.61 + * the panning and zooming logic that was invoked on the UI thread. 1.62 + * 1.63 + * Currently, each outer DOM window (i.e. a website in a tab, but not any 1.64 + * subframes) has its own AsyncPanZoomController. In the future, to support 1.65 + * asynchronously scrolled subframes, we want to have one AsyncPanZoomController 1.66 + * per frame. 1.67 + */ 1.68 +class AsyncPanZoomController { 1.69 + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AsyncPanZoomController) 1.70 + 1.71 + typedef mozilla::MonitorAutoLock MonitorAutoLock; 1.72 + typedef uint32_t TouchBehaviorFlags; 1.73 + 1.74 +public: 1.75 + enum GestureBehavior { 1.76 + // The platform code is responsible for forwarding gesture events here. We 1.77 + // will not attempt to generate gesture events from MultiTouchInputs. 1.78 + DEFAULT_GESTURES, 1.79 + // An instance of GestureEventListener is used to detect gestures. This is 1.80 + // handled completely internally within this class. 1.81 + USE_GESTURE_DETECTOR 1.82 + }; 1.83 + 1.84 + /** 1.85 + * Constant describing the tolerance in distance we use, multiplied by the 1.86 + * device DPI, before we start panning the screen. This is to prevent us from 1.87 + * accidentally processing taps as touch moves, and from very short/accidental 1.88 + * touches moving the screen. 1.89 + */ 1.90 + static float GetTouchStartTolerance(); 1.91 + 1.92 + AsyncPanZoomController(uint64_t aLayersId, 1.93 + APZCTreeManager* aTreeManager, 1.94 + GeckoContentController* aController, 1.95 + GestureBehavior aGestures = DEFAULT_GESTURES); 1.96 + 1.97 + // -------------------------------------------------------------------------- 1.98 + // These methods must only be called on the gecko thread. 1.99 + // 1.100 + 1.101 + /** 1.102 + * Read the various prefs and do any global initialization for all APZC instances. 1.103 + * This must be run on the gecko thread before any APZC instances are actually 1.104 + * used for anything meaningful. 1.105 + */ 1.106 + static void InitializeGlobalState(); 1.107 + 1.108 + // -------------------------------------------------------------------------- 1.109 + // These methods must only be called on the controller/UI thread. 1.110 + // 1.111 + 1.112 + /** 1.113 + * General handler for incoming input events. Manipulates the frame metrics 1.114 + * based on what type of input it is. For example, a PinchGestureEvent will 1.115 + * cause scaling. This should only be called externally to this class. 1.116 + * HandleInputEvent() should be used internally. 1.117 + */ 1.118 + nsEventStatus ReceiveInputEvent(const InputData& aEvent); 1.119 + 1.120 + /** 1.121 + * Kicks an animation to zoom to a rect. This may be either a zoom out or zoom 1.122 + * in. The actual animation is done on the compositor thread after being set 1.123 + * up. 1.124 + */ 1.125 + void ZoomToRect(CSSRect aRect); 1.126 + 1.127 + /** 1.128 + * If we have touch listeners, this should always be called when we know 1.129 + * definitively whether or not content has preventDefaulted any touch events 1.130 + * that have come in. If |aPreventDefault| is true, any touch events in the 1.131 + * queue will be discarded. 1.132 + */ 1.133 + void ContentReceivedTouch(bool aPreventDefault); 1.134 + 1.135 + /** 1.136 + * Updates any zoom constraints contained in the <meta name="viewport"> tag. 1.137 + */ 1.138 + void UpdateZoomConstraints(const ZoomConstraints& aConstraints); 1.139 + 1.140 + /** 1.141 + * Return the zoom constraints last set for this APZC (in the constructor 1.142 + * or in UpdateZoomConstraints()). 1.143 + */ 1.144 + ZoomConstraints GetZoomConstraints() const; 1.145 + 1.146 + /** 1.147 + * Schedules a runnable to run on the controller/UI thread at some time 1.148 + * in the future. 1.149 + */ 1.150 + void PostDelayedTask(Task* aTask, int aDelayMs); 1.151 + 1.152 + // -------------------------------------------------------------------------- 1.153 + // These methods must only be called on the compositor thread. 1.154 + // 1.155 + 1.156 + bool UpdateAnimation(const TimeStamp& aSampleTime); 1.157 + 1.158 + /** 1.159 + * The compositor calls this when it's about to draw pannable/zoomable content 1.160 + * and is setting up transforms for compositing the layer tree. This is not 1.161 + * idempotent. For example, a fling transform can be applied each time this is 1.162 + * called (though not necessarily). |aSampleTime| is the time that this is 1.163 + * sampled at; this is used for interpolating animations. Calling this sets a 1.164 + * new transform in |aNewTransform| which should be multiplied to the transform 1.165 + * in the shadow layer corresponding to this APZC. 1.166 + * 1.167 + * Return value indicates whether or not any currently running animation 1.168 + * should continue. That is, if true, the compositor should schedule another 1.169 + * composite. 1.170 + */ 1.171 + bool SampleContentTransformForFrame(const TimeStamp& aSampleTime, 1.172 + ViewTransform* aNewTransform, 1.173 + ScreenPoint& aScrollOffset); 1.174 + 1.175 + /** 1.176 + * A shadow layer update has arrived. |aLayerMetrics| is the new FrameMetrics 1.177 + * for the container layer corresponding to this APZC. 1.178 + * |aIsFirstPaint| is a flag passed from the shadow 1.179 + * layers code indicating that the frame metrics being sent with this call are 1.180 + * the initial metrics and the initial paint of the frame has just happened. 1.181 + */ 1.182 + void NotifyLayersUpdated(const FrameMetrics& aLayerMetrics, bool aIsFirstPaint); 1.183 + 1.184 + /** 1.185 + * The platform implementation must set the compositor parent so that we can 1.186 + * request composites. 1.187 + */ 1.188 + void SetCompositorParent(CompositorParent* aCompositorParent); 1.189 + 1.190 + /** 1.191 + * The platform implementation must set the cross process compositor if 1.192 + * there is one associated with the layer tree. The cross process compositor 1.193 + * allows the APZC to share its FrameMetrics with the content process. 1.194 + * The shared FrameMetrics is used in progressive paint updates. 1.195 + */ 1.196 + void SetCrossProcessCompositorParent(PCompositorParent* aCrossProcessCompositorParent); 1.197 + 1.198 + // -------------------------------------------------------------------------- 1.199 + // These methods can be called from any thread. 1.200 + // 1.201 + 1.202 + /** 1.203 + * Shut down the controller/UI thread state and prepare to be 1.204 + * deleted (which may happen from any thread). 1.205 + */ 1.206 + void Destroy(); 1.207 + 1.208 + /** 1.209 + * Returns true if Destroy() has already been called on this APZC instance. 1.210 + */ 1.211 + bool IsDestroyed(); 1.212 + 1.213 + /** 1.214 + * Returns the incremental transformation corresponding to the async pan/zoom 1.215 + * in progress. That is, when this transform is multiplied with the layer's 1.216 + * existing transform, it will make the layer appear with the desired pan/zoom 1.217 + * amount. 1.218 + */ 1.219 + ViewTransform GetCurrentAsyncTransform(); 1.220 + 1.221 + /** 1.222 + * Returns the part of the async transform that will remain once Gecko does a 1.223 + * repaint at the desired metrics. That is, in the steady state: 1.224 + * gfx3DMatrix(GetCurrentAsyncTransform()) === GetNontransientAsyncTransform() 1.225 + */ 1.226 + gfx3DMatrix GetNontransientAsyncTransform(); 1.227 + 1.228 + /** 1.229 + * Returns the transform to take something from the coordinate space of the 1.230 + * last thing we know gecko painted, to the coordinate space of the last thing 1.231 + * we asked gecko to paint. In cases where that last request has not yet been 1.232 + * processed, this is needed to transform input events properly into a space 1.233 + * gecko will understand. 1.234 + */ 1.235 + gfx3DMatrix GetTransformToLastDispatchedPaint(); 1.236 + 1.237 + /** 1.238 + * Recalculates the displayport. Ideally, this should paint an area bigger 1.239 + * than the composite-to dimensions so that when you scroll down, you don't 1.240 + * checkerboard immediately. This includes a bunch of logic, including 1.241 + * algorithms to bias painting in the direction of the velocity. 1.242 + */ 1.243 + static const LayerMargin CalculatePendingDisplayPort( 1.244 + const FrameMetrics& aFrameMetrics, 1.245 + const ScreenPoint& aVelocity, 1.246 + double aEstimatedPaintDuration); 1.247 + 1.248 + /** 1.249 + * Send an mozbrowserasyncscroll event. 1.250 + * *** The monitor must be held while calling this. 1.251 + */ 1.252 + void SendAsyncScrollEvent(); 1.253 + 1.254 + /** 1.255 + * Handler for events which should not be intercepted by the touch listener. 1.256 + * Does the work for ReceiveInputEvent(). 1.257 + */ 1.258 + nsEventStatus HandleInputEvent(const InputData& aEvent); 1.259 + 1.260 + /** 1.261 + * Handler for gesture events. 1.262 + * Currently some gestures are detected in GestureEventListener that calls 1.263 + * APZC back through this handler in order to avoid recursive calls to 1.264 + * APZC::HandleInputEvent() which is supposed to do the work for 1.265 + * ReceiveInputEvent(). 1.266 + */ 1.267 + nsEventStatus HandleGestureEvent(const InputData& aEvent); 1.268 + 1.269 + /** 1.270 + * Populates the provided object (if non-null) with the scrollable guid of this apzc. 1.271 + */ 1.272 + void GetGuid(ScrollableLayerGuid* aGuidOut); 1.273 + 1.274 + /** 1.275 + * Returns the scrollable guid of this apzc. 1.276 + */ 1.277 + ScrollableLayerGuid GetGuid(); 1.278 + 1.279 + /** 1.280 + * Returns true if this APZC instance is for the layer identified by the guid. 1.281 + */ 1.282 + bool Matches(const ScrollableLayerGuid& aGuid); 1.283 + 1.284 + /** 1.285 + * Sync panning and zooming animation using a fixed frame time. 1.286 + * This will ensure that we animate the APZC correctly with other external 1.287 + * animations to the same timestamp. 1.288 + */ 1.289 + static void SetFrameTime(const TimeStamp& aMilliseconds); 1.290 + 1.291 + void StartAnimation(AsyncPanZoomAnimation* aAnimation); 1.292 + 1.293 + /** 1.294 + * Cancels any currently running animation. Note that all this does is set the 1.295 + * state of the AsyncPanZoomController back to NOTHING, but it is the 1.296 + * animation's responsibility to check this before advancing. 1.297 + */ 1.298 + void CancelAnimation(); 1.299 + 1.300 + /** 1.301 + * Take over a fling with the given velocity from another APZC. Used for 1.302 + * during overscroll handoff for a fling. 1.303 + */ 1.304 + void TakeOverFling(ScreenPoint aVelocity); 1.305 + 1.306 + /** 1.307 + * Returns allowed touch behavior for the given point on the scrollable layer. 1.308 + * Internally performs a kind of hit testing based on the regions constructed 1.309 + * on the main thread and attached to the current scrollable layer. Each of such regions 1.310 + * contains info about allowed touch behavior. If regions info isn't enough it returns 1.311 + * UNKNOWN value and we should switch to the fallback approach - asking content. 1.312 + * TODO: for now it's only a stub and returns hardcoded magic value. As soon as bug 928833 1.313 + * is done we should integrate its logic here. 1.314 + */ 1.315 + TouchBehaviorFlags GetAllowedTouchBehavior(ScreenIntPoint& aPoint); 1.316 + 1.317 + /** 1.318 + * Sets allowed touch behavior for current touch session. 1.319 + * This method is invoked by the APZCTreeManager which in its turn invoked by 1.320 + * the widget after performing touch-action values retrieving. 1.321 + * Must be called after receiving the TOUCH_START even that started the 1.322 + * touch session. 1.323 + */ 1.324 + void SetAllowedTouchBehavior(const nsTArray<TouchBehaviorFlags>& aBehaviors); 1.325 + 1.326 + /** 1.327 + * Returns whether this APZC is for an element marked with the 'scrollgrab' 1.328 + * attribute. 1.329 + */ 1.330 + bool HasScrollgrab() const { return mFrameMetrics.mHasScrollgrab; } 1.331 + 1.332 + /** 1.333 + * Set an extra offset for testing async scrolling. 1.334 + */ 1.335 + void SetTestAsyncScrollOffset(const CSSPoint& aPoint) 1.336 + { 1.337 + mTestAsyncScrollOffset = aPoint; 1.338 + } 1.339 + 1.340 + /** 1.341 + * Returns whether this APZC has room to be panned (in any direction). 1.342 + */ 1.343 + bool IsPannable() const; 1.344 + 1.345 +protected: 1.346 + // Protected destructor, to discourage deletion outside of Release(): 1.347 + ~AsyncPanZoomController(); 1.348 + 1.349 + /** 1.350 + * Helper method for touches beginning. Sets everything up for panning and any 1.351 + * multitouch gestures. 1.352 + */ 1.353 + nsEventStatus OnTouchStart(const MultiTouchInput& aEvent); 1.354 + 1.355 + /** 1.356 + * Helper method for touches moving. Does any transforms needed when panning. 1.357 + */ 1.358 + nsEventStatus OnTouchMove(const MultiTouchInput& aEvent); 1.359 + 1.360 + /** 1.361 + * Helper method for touches ending. Redraws the screen if necessary and does 1.362 + * any cleanup after a touch has ended. 1.363 + */ 1.364 + nsEventStatus OnTouchEnd(const MultiTouchInput& aEvent); 1.365 + 1.366 + /** 1.367 + * Helper method for touches being cancelled. Treated roughly the same as a 1.368 + * touch ending (OnTouchEnd()). 1.369 + */ 1.370 + nsEventStatus OnTouchCancel(const MultiTouchInput& aEvent); 1.371 + 1.372 + /** 1.373 + * Helper method for scales beginning. Distinct from the OnTouch* handlers in 1.374 + * that this implies some outside implementation has determined that the user 1.375 + * is pinching. 1.376 + */ 1.377 + nsEventStatus OnScaleBegin(const PinchGestureInput& aEvent); 1.378 + 1.379 + /** 1.380 + * Helper method for scaling. As the user moves their fingers when pinching, 1.381 + * this changes the scale of the page. 1.382 + */ 1.383 + nsEventStatus OnScale(const PinchGestureInput& aEvent); 1.384 + 1.385 + /** 1.386 + * Helper method for scales ending. Redraws the screen if necessary and does 1.387 + * any cleanup after a scale has ended. 1.388 + */ 1.389 + nsEventStatus OnScaleEnd(const PinchGestureInput& aEvent); 1.390 + 1.391 + /** 1.392 + * Helper methods for long press gestures. 1.393 + */ 1.394 + nsEventStatus OnLongPress(const TapGestureInput& aEvent); 1.395 + nsEventStatus OnLongPressUp(const TapGestureInput& aEvent); 1.396 + 1.397 + /** 1.398 + * Helper method for single tap gestures. 1.399 + */ 1.400 + nsEventStatus OnSingleTapUp(const TapGestureInput& aEvent); 1.401 + 1.402 + /** 1.403 + * Helper method for a single tap confirmed. 1.404 + */ 1.405 + nsEventStatus OnSingleTapConfirmed(const TapGestureInput& aEvent); 1.406 + 1.407 + /** 1.408 + * Helper method for double taps. 1.409 + */ 1.410 + nsEventStatus OnDoubleTap(const TapGestureInput& aEvent); 1.411 + 1.412 + /** 1.413 + * Helper method to cancel any gesture currently going to Gecko. Used 1.414 + * primarily when a user taps the screen over some clickable content but then 1.415 + * pans down instead of letting go (i.e. to cancel a previous touch so that a 1.416 + * new one can properly take effect. 1.417 + */ 1.418 + nsEventStatus OnCancelTap(const TapGestureInput& aEvent); 1.419 + 1.420 + /** 1.421 + * Scrolls the viewport by an X,Y offset. 1.422 + */ 1.423 + void ScrollBy(const CSSPoint& aOffset); 1.424 + 1.425 + /** 1.426 + * Scales the viewport by an amount (note that it multiplies this scale in to 1.427 + * the current scale, it doesn't set it to |aScale|). Also considers a focus 1.428 + * point so that the page zooms inward/outward from that point. 1.429 + */ 1.430 + void ScaleWithFocus(float aScale, 1.431 + const CSSPoint& aFocus); 1.432 + 1.433 + /** 1.434 + * Schedules a composite on the compositor thread. Wrapper for 1.435 + * CompositorParent::ScheduleRenderOnCompositorThread(). 1.436 + */ 1.437 + void ScheduleComposite(); 1.438 + 1.439 + /** 1.440 + * Gets the displacement of the current touch since it began. That is, it is 1.441 + * the distance between the current position and the initial position of the 1.442 + * current touch (this only makes sense if a touch is currently happening and 1.443 + * OnTouchMove() is being invoked). 1.444 + */ 1.445 + float PanDistance(); 1.446 + 1.447 + /** 1.448 + * Gets a vector of the velocities of each axis. 1.449 + */ 1.450 + const ScreenPoint GetVelocityVector(); 1.451 + 1.452 + /** 1.453 + * Gets a reference to the first touch point from a MultiTouchInput. This 1.454 + * gets only the first one and assumes the rest are either missing or not 1.455 + * relevant. 1.456 + */ 1.457 + ScreenIntPoint& GetFirstTouchScreenPoint(const MultiTouchInput& aEvent); 1.458 + 1.459 + /** 1.460 + * Sets the panning state basing on the pan direction angle and current touch-action value. 1.461 + */ 1.462 + void HandlePanningWithTouchAction(double angle, TouchBehaviorFlags value); 1.463 + 1.464 + /** 1.465 + * Sets the panning state ignoring the touch action value. 1.466 + */ 1.467 + void HandlePanning(double angle); 1.468 + 1.469 + /** 1.470 + * Sets up anything needed for panning. This takes us out of the "TOUCHING" 1.471 + * state and starts actually panning us. 1.472 + */ 1.473 + nsEventStatus StartPanning(const MultiTouchInput& aStartPoint); 1.474 + 1.475 + /** 1.476 + * Wrapper for Axis::UpdateWithTouchAtDevicePoint(). Calls this function for 1.477 + * both axes and factors in the time delta from the last update. 1.478 + */ 1.479 + void UpdateWithTouchAtDevicePoint(const MultiTouchInput& aEvent); 1.480 + 1.481 + /** 1.482 + * Does any panning required due to a new touch event. 1.483 + */ 1.484 + void TrackTouch(const MultiTouchInput& aEvent); 1.485 + 1.486 + /** 1.487 + * Utility function to send updated FrameMetrics to Gecko so that it can paint 1.488 + * the displayport area. Calls into GeckoContentController to do the actual 1.489 + * work. Note that only one paint request can be active at a time. If a paint 1.490 + * request is made while a paint is currently happening, it gets queued up. If 1.491 + * a new paint request arrives before a paint is completed, the old request 1.492 + * gets discarded. 1.493 + */ 1.494 + void RequestContentRepaint(); 1.495 + 1.496 + /** 1.497 + * Tell the paint throttler to request a content repaint with the given 1.498 + * metrics. (Helper function used by RequestContentRepaint.) 1.499 + */ 1.500 + void RequestContentRepaint(FrameMetrics& aFrameMetrics); 1.501 + 1.502 + /** 1.503 + * Actually send the next pending paint request to gecko. 1.504 + */ 1.505 + void DispatchRepaintRequest(const FrameMetrics& aFrameMetrics); 1.506 + 1.507 + /** 1.508 + * Advances a fling by an interpolated amount based on the passed in |aDelta|. 1.509 + * This should be called whenever sampling the content transform for this 1.510 + * frame. Returns true if the fling animation should be advanced by one frame, 1.511 + * or false if there is no fling or the fling has ended. 1.512 + */ 1.513 + bool DoFling(const TimeDuration& aDelta); 1.514 + 1.515 + /** 1.516 + * Gets the current frame metrics. This is *not* the Gecko copy stored in the 1.517 + * layers code. 1.518 + */ 1.519 + const FrameMetrics& GetFrameMetrics(); 1.520 + 1.521 + /** 1.522 + * Sets the timer for content response to a series of touch events, if it 1.523 + * hasn't been already. This is to prevent us from batching up touch events 1.524 + * indefinitely in the case that content doesn't respond with whether or not 1.525 + * it wants to preventDefault. When the timer is fired, the touch event queue 1.526 + * will be flushed. 1.527 + */ 1.528 + void SetContentResponseTimer(); 1.529 + 1.530 + /** 1.531 + * Timeout function for content response. This should be called on a timer 1.532 + * after we get our first touch event in a batch, under the condition that we 1.533 + * waiting for response from content. If a notification comes indicating whether or not 1.534 + * content preventDefaulted a series of touch events and touch behavior values are 1.535 + * set before the timeout, the timeout should be cancelled. 1.536 + */ 1.537 + void TimeoutContentResponse(); 1.538 + 1.539 + /** 1.540 + * Timeout function for mozbrowserasyncscroll event. Because we throttle 1.541 + * mozbrowserasyncscroll events in some conditions, this function ensures 1.542 + * that the last mozbrowserasyncscroll event will be fired after a period of 1.543 + * time. 1.544 + */ 1.545 + void FireAsyncScrollOnTimeout(); 1.546 + 1.547 +private: 1.548 + enum PanZoomState { 1.549 + NOTHING, /* no touch-start events received */ 1.550 + FLING, /* all touches removed, but we're still scrolling page */ 1.551 + TOUCHING, /* one touch-start event received */ 1.552 + 1.553 + PANNING, /* panning the frame */ 1.554 + PANNING_LOCKED_X, /* touch-start followed by move (i.e. panning with axis lock) X axis */ 1.555 + PANNING_LOCKED_Y, /* as above for Y axis */ 1.556 + 1.557 + CROSS_SLIDING_X, /* Panning disabled while user does a horizontal gesture 1.558 + on a vertically-scrollable view. This used for the 1.559 + Windows Metro "cross-slide" gesture. */ 1.560 + CROSS_SLIDING_Y, /* as above for Y axis */ 1.561 + 1.562 + PINCHING, /* nth touch-start, where n > 1. this mode allows pan and zoom */ 1.563 + ANIMATING_ZOOM, /* animated zoom to a new rect */ 1.564 + WAITING_CONTENT_RESPONSE, /* a state halfway between NOTHING and TOUCHING - the user has 1.565 + put a finger down, but we don't yet know if a touch listener has 1.566 + prevented the default actions yet and the allowed touch behavior 1.567 + was not set yet. we still need to abort animations. */ 1.568 + }; 1.569 + 1.570 + // State related to a single touch block. Does not persist across touch blocks. 1.571 + struct TouchBlockState { 1.572 + 1.573 + TouchBlockState() 1.574 + : mAllowedTouchBehaviorSet(false), 1.575 + mPreventDefault(false), 1.576 + mPreventDefaultSet(false), 1.577 + mSingleTapOccurred(false) 1.578 + {} 1.579 + 1.580 + // Values of allowed touch behavior for touch points of this touch block. 1.581 + // Since there are maybe a few current active touch points per time (multitouch case) 1.582 + // and each touch point should have its own value of allowed touch behavior- we're 1.583 + // keeping an array of allowed touch behavior values, not the single value. 1.584 + nsTArray<TouchBehaviorFlags> mAllowedTouchBehaviors; 1.585 + 1.586 + // Specifies whether mAllowedTouchBehaviors is set for this touch events block. 1.587 + bool mAllowedTouchBehaviorSet; 1.588 + 1.589 + // Flag used to specify that content prevented the default behavior of this 1.590 + // touch events block. 1.591 + bool mPreventDefault; 1.592 + 1.593 + // Specifies whether mPreventDefault property is set for this touch events block. 1.594 + bool mPreventDefaultSet; 1.595 + 1.596 + // Specifies whether a single tap event was generated during this touch block. 1.597 + bool mSingleTapOccurred; 1.598 + }; 1.599 + 1.600 + /* 1.601 + * Returns whether current touch behavior values allow pinch-zooming. 1.602 + */ 1.603 + bool TouchActionAllowPinchZoom(); 1.604 + 1.605 + /* 1.606 + * Returns whether current touch behavior values allow double-tap-zooming. 1.607 + */ 1.608 + bool TouchActionAllowDoubleTapZoom(); 1.609 + 1.610 + /* 1.611 + * Returns allowed touch behavior from the mAllowedTouchBehavior array. 1.612 + * In case apzc didn't receive touch behavior values within the timeout 1.613 + * it returns default value. 1.614 + */ 1.615 + TouchBehaviorFlags GetTouchBehavior(uint32_t touchIndex); 1.616 + 1.617 + /** 1.618 + * To move from the WAITING_CONTENT_RESPONSE state to TOUCHING one we need two 1.619 + * conditions set: get content listeners response (whether they called preventDefault) 1.620 + * and get allowed touch behaviors. 1.621 + * This method checks both conditions and changes (or not changes) state 1.622 + * appropriately. 1.623 + */ 1.624 + void CheckContentResponse(); 1.625 + 1.626 + /** 1.627 + * Helper to set the current state. Holds the monitor before actually setting 1.628 + * it and fires content controller events based on state changes. Always set 1.629 + * the state using this call, do not set it directly. 1.630 + */ 1.631 + void SetState(PanZoomState aState); 1.632 + 1.633 + /** 1.634 + * Convert ScreenPoint relative to this APZC to CSSPoint relative 1.635 + * to the parent document. This excludes the transient compositor transform. 1.636 + * NOTE: This must be converted to CSSPoint relative to the child 1.637 + * document before sending over IPC. 1.638 + */ 1.639 + bool ConvertToGecko(const ScreenPoint& aPoint, CSSPoint* aOut); 1.640 + 1.641 + /** 1.642 + * Internal helpers for checking general state of this apzc. 1.643 + */ 1.644 + bool IsTransformingState(PanZoomState aState); 1.645 + bool IsPanningState(PanZoomState mState); 1.646 + 1.647 + enum AxisLockMode { 1.648 + FREE, /* No locking at all */ 1.649 + STANDARD, /* Default axis locking mode that remains locked until pan ends*/ 1.650 + STICKY, /* Allow lock to be broken, with hysteresis */ 1.651 + }; 1.652 + 1.653 + static AxisLockMode GetAxisLockMode(); 1.654 + 1.655 + // Convert a point from local screen coordinates to parent layer coordinates. 1.656 + // This is a common operation as inputs from the tree manager are in screen 1.657 + // coordinates but the composition bounds is in parent layer coordinates. 1.658 + ParentLayerPoint ToParentLayerCoords(const ScreenPoint& aPoint); 1.659 + 1.660 + // Update mFrameMetrics.mTransformScale. This should be called whenever 1.661 + // our CSS transform or the non-transient part of our async transform 1.662 + // changes, as it corresponds to the scale portion of those transforms. 1.663 + void UpdateTransformScale(); 1.664 + 1.665 + // Helper function for OnSingleTapUp() and OnSingleTapConfirmed(). 1.666 + nsEventStatus GenerateSingleTap(const ScreenIntPoint& aPoint, mozilla::Modifiers aModifiers); 1.667 + 1.668 + // Common processing at the end of a touch block. 1.669 + void OnTouchEndOrCancel(); 1.670 + 1.671 + uint64_t mLayersId; 1.672 + nsRefPtr<CompositorParent> mCompositorParent; 1.673 + PCompositorParent* mCrossProcessCompositorParent; 1.674 + TaskThrottler mPaintThrottler; 1.675 + 1.676 + /* Access to the following two fields is protected by the mRefPtrMonitor, 1.677 + since they are accessed on the UI thread but can be cleared on the 1.678 + compositor thread. */ 1.679 + nsRefPtr<GeckoContentController> mGeckoContentController; 1.680 + nsRefPtr<GestureEventListener> mGestureEventListener; 1.681 + Monitor mRefPtrMonitor; 1.682 + 1.683 + /* Utility functions that return a addrefed pointer to the corresponding fields. */ 1.684 + already_AddRefed<GeckoContentController> GetGeckoContentController(); 1.685 + already_AddRefed<GestureEventListener> GetGestureEventListener(); 1.686 + 1.687 +protected: 1.688 + // Both |mFrameMetrics| and |mLastContentPaintMetrics| are protected by the 1.689 + // monitor. Do not read from or modify either of them without locking. 1.690 + FrameMetrics mFrameMetrics; 1.691 + 1.692 + // Protects |mFrameMetrics|, |mLastContentPaintMetrics|, and |mState|. 1.693 + // Before manipulating |mFrameMetrics| or |mLastContentPaintMetrics|, the 1.694 + // monitor should be held. When setting |mState|, either the SetState() 1.695 + // function can be used, or the monitor can be held and then |mState| updated. 1.696 + // IMPORTANT: See the note about lock ordering at the top of APZCTreeManager.h. 1.697 + // This is mutable to allow entering it from 'const' methods; doing otherwise 1.698 + // would significantly limit what methods could be 'const'. 1.699 + mutable ReentrantMonitor mMonitor; 1.700 + 1.701 + // Specifies whether we should use touch-action css property. Initialized from 1.702 + // the preferences. This property (in comparison with the global one) simplifies 1.703 + // testing apzc with (and without) touch-action property enabled concurrently 1.704 + // (e.g. with the gtest framework). 1.705 + bool mTouchActionPropertyEnabled; 1.706 + 1.707 +private: 1.708 + // Metrics of the container layer corresponding to this APZC. This is 1.709 + // stored here so that it is accessible from the UI/controller thread. 1.710 + // These are the metrics at last content paint, the most recent 1.711 + // values we were notified of in NotifyLayersUpdate(). Since it represents 1.712 + // the Gecko state, it should be used as a basis for untransformation when 1.713 + // sending messages back to Gecko. 1.714 + FrameMetrics mLastContentPaintMetrics; 1.715 + // The last metrics that we requested a paint for. These are used to make sure 1.716 + // that we're not requesting a paint of the same thing that's already drawn. 1.717 + // If we don't do this check, we don't get a ShadowLayersUpdated back. 1.718 + FrameMetrics mLastPaintRequestMetrics; 1.719 + // The last metrics that we actually sent to Gecko. This allows us to transform 1.720 + // inputs into a coordinate space that Gecko knows about. This assumes the pipe 1.721 + // through which input events and repaint requests are sent to Gecko operates 1.722 + // in a FIFO manner. 1.723 + FrameMetrics mLastDispatchedPaintMetrics; 1.724 + 1.725 + nsTArray<MultiTouchInput> mTouchQueue; 1.726 + 1.727 + CancelableTask* mContentResponseTimeoutTask; 1.728 + 1.729 + AxisX mX; 1.730 + AxisY mY; 1.731 + 1.732 + // This flag is set to true when we are in a axis-locked pan as a result of 1.733 + // the touch-action CSS property. 1.734 + bool mPanDirRestricted; 1.735 + 1.736 + // Most up-to-date constraints on zooming. These should always be reasonable 1.737 + // values; for example, allowing a min zoom of 0.0 can cause very bad things 1.738 + // to happen. 1.739 + ZoomConstraints mZoomConstraints; 1.740 + 1.741 + // The last time the compositor has sampled the content transform for this 1.742 + // frame. 1.743 + TimeStamp mLastSampleTime; 1.744 + // The last time a touch event came through on the UI thread. 1.745 + uint32_t mLastEventTime; 1.746 + 1.747 + // Stores the previous focus point if there is a pinch gesture happening. Used 1.748 + // to allow panning by moving multiple fingers (thus moving the focus point). 1.749 + ParentLayerPoint mLastZoomFocus; 1.750 + 1.751 + // Stores the state of panning and zooming this frame. This is protected by 1.752 + // |mMonitor|; that is, it should be held whenever this is updated. 1.753 + PanZoomState mState; 1.754 + 1.755 + // The last time and offset we fire the mozbrowserasyncscroll event when 1.756 + // compositor has sampled the content transform for this frame. 1.757 + TimeStamp mLastAsyncScrollTime; 1.758 + CSSPoint mLastAsyncScrollOffset; 1.759 + 1.760 + // The current offset drawn on the screen, it may not be sent since we have 1.761 + // throttling policy for mozbrowserasyncscroll event. 1.762 + CSSPoint mCurrentAsyncScrollOffset; 1.763 + 1.764 + // The delay task triggered by the throttling mozbrowserasyncscroll event 1.765 + // ensures the last mozbrowserasyncscroll event is always been fired. 1.766 + CancelableTask* mAsyncScrollTimeoutTask; 1.767 + 1.768 + // Flag used to determine whether or not we should try to enter the 1.769 + // WAITING_LISTENERS state. This is used in the case that we are processing a 1.770 + // queued up event block. If set, this means that we are handling this queue 1.771 + // and we don't want to queue the events back up again. 1.772 + bool mHandlingTouchQueue; 1.773 + 1.774 + // Stores information about the current touch block. 1.775 + TouchBlockState mTouchBlockState; 1.776 + 1.777 + // Extra offset to add in SampleContentTransformForFrame for testing 1.778 + CSSPoint mTestAsyncScrollOffset; 1.779 + 1.780 + RefPtr<AsyncPanZoomAnimation> mAnimation; 1.781 + 1.782 + friend class Axis; 1.783 + friend class FlingAnimation; 1.784 + 1.785 + 1.786 + /* =================================================================== 1.787 + * The functions and members in this section are used to build a tree 1.788 + * structure out of APZC instances. This tree can only be walked or 1.789 + * manipulated while holding the lock in the associated APZCTreeManager 1.790 + * instance. 1.791 + */ 1.792 +public: 1.793 + void SetLastChild(AsyncPanZoomController* child) { 1.794 + mLastChild = child; 1.795 + if (child) { 1.796 + child->mParent = this; 1.797 + } 1.798 + } 1.799 + 1.800 + void SetPrevSibling(AsyncPanZoomController* sibling) { 1.801 + mPrevSibling = sibling; 1.802 + if (sibling) { 1.803 + sibling->mParent = mParent; 1.804 + } 1.805 + } 1.806 + 1.807 + AsyncPanZoomController* GetLastChild() const { return mLastChild; } 1.808 + AsyncPanZoomController* GetPrevSibling() const { return mPrevSibling; } 1.809 + AsyncPanZoomController* GetParent() const { return mParent; } 1.810 + 1.811 + /* Returns true if there is no APZC higher in the tree with the same 1.812 + * layers id. 1.813 + */ 1.814 + bool IsRootForLayersId() const { 1.815 + return !mParent || (mParent->mLayersId != mLayersId); 1.816 + } 1.817 + 1.818 + bool IsRootForLayersId(const uint64_t& aLayersId) const { 1.819 + return (mLayersId == aLayersId) && IsRootForLayersId(); 1.820 + } 1.821 + 1.822 +private: 1.823 + // This is a raw pointer to avoid introducing a reference cycle between 1.824 + // AsyncPanZoomController and APZCTreeManager. Since these objects don't 1.825 + // live on the main thread, we can't use the cycle collector with them. 1.826 + // The APZCTreeManager owns the lifetime of the APZCs, so nulling this 1.827 + // pointer out in Destroy() will prevent accessing deleted memory. 1.828 + Atomic<APZCTreeManager*> mTreeManager; 1.829 + 1.830 + nsRefPtr<AsyncPanZoomController> mLastChild; 1.831 + nsRefPtr<AsyncPanZoomController> mPrevSibling; 1.832 + nsRefPtr<AsyncPanZoomController> mParent; 1.833 + 1.834 + 1.835 + /* =================================================================== 1.836 + * The functions and members in this section are used in building the 1.837 + * scroll handoff chain, so that we can have seamless scrolling continue 1.838 + * across APZC instances. 1.839 + */ 1.840 +public: 1.841 + void SetScrollHandoffParentId(FrameMetrics::ViewID aScrollParentId) { 1.842 + mScrollParentId = aScrollParentId; 1.843 + } 1.844 + 1.845 + FrameMetrics::ViewID GetScrollHandoffParentId() const { 1.846 + return mScrollParentId; 1.847 + } 1.848 + 1.849 + /** 1.850 + * Attempt to scroll in response to a touch-move from |aStartPoint| to 1.851 + * |aEndPoint|, which are in our (transformed) screen coordinates. 1.852 + * Due to overscroll handling, there may not actually have been a touch-move 1.853 + * at these points, but this function will scroll as if there had been. 1.854 + * If this attempt causes overscroll (i.e. the layer cannot be scrolled 1.855 + * by the entire amount requested), the overscroll is passed back to the 1.856 + * tree manager via APZCTreeManager::DispatchScroll(). 1.857 + * |aOverscrollHandoffChainIndex| is used by the tree manager to keep track 1.858 + * of which APZC to hand off the overscroll to; this function increments it 1.859 + * and passes it on to APZCTreeManager::DispatchScroll() in the event of 1.860 + * overscroll. 1.861 + */ 1.862 + void AttemptScroll(const ScreenPoint& aStartPoint, const ScreenPoint& aEndPoint, 1.863 + uint32_t aOverscrollHandoffChainIndex = 0); 1.864 + 1.865 + void FlushRepaintForOverscrollHandoff(); 1.866 + 1.867 +private: 1.868 + FrameMetrics::ViewID mScrollParentId; 1.869 + 1.870 + /** 1.871 + * A helper function for calling APZCTreeManager::DispatchScroll(). 1.872 + * Guards against the case where the APZC is being concurrently destroyed 1.873 + * (and thus mTreeManager is being nulled out). 1.874 + */ 1.875 + void CallDispatchScroll(const ScreenPoint& aStartPoint, const ScreenPoint& aEndPoint, 1.876 + uint32_t aOverscrollHandoffChainIndex); 1.877 + 1.878 + 1.879 + /* =================================================================== 1.880 + * The functions and members in this section are used to maintain the 1.881 + * area that this APZC instance is responsible for. This is used when 1.882 + * hit-testing to see which APZC instance should handle touch events. 1.883 + */ 1.884 +public: 1.885 + void SetLayerHitTestData(const ParentLayerRect& aRect, const gfx3DMatrix& aTransformToLayer, 1.886 + const gfx3DMatrix& aTransformForLayer) { 1.887 + mVisibleRect = aRect; 1.888 + mAncestorTransform = aTransformToLayer; 1.889 + mCSSTransform = aTransformForLayer; 1.890 + UpdateTransformScale(); 1.891 + } 1.892 + 1.893 + gfx3DMatrix GetAncestorTransform() const { 1.894 + return mAncestorTransform; 1.895 + } 1.896 + 1.897 + gfx3DMatrix GetCSSTransform() const { 1.898 + return mCSSTransform; 1.899 + } 1.900 + 1.901 + bool VisibleRegionContains(const ParentLayerPoint& aPoint) const { 1.902 + return mVisibleRect.Contains(aPoint); 1.903 + } 1.904 + 1.905 +private: 1.906 + /* This is the visible region of the layer that this APZC corresponds to, in 1.907 + * that layer's screen pixels (the same coordinate system in which this APZC 1.908 + * receives events in ReceiveInputEvent()). */ 1.909 + ParentLayerRect mVisibleRect; 1.910 + /* This is the cumulative CSS transform for all the layers between the parent 1.911 + * APZC and this one (not inclusive) */ 1.912 + gfx3DMatrix mAncestorTransform; 1.913 + /* This is the CSS transform for this APZC's layer. */ 1.914 + gfx3DMatrix mCSSTransform; 1.915 + 1.916 + 1.917 + /* =================================================================== 1.918 + * The functions and members in this section are used for sharing the 1.919 + * FrameMetrics across processes for the progressive tiling code. 1.920 + */ 1.921 +private: 1.922 + /* Unique id assigned to each APZC. Used with ViewID to uniquely identify 1.923 + * shared FrameMeterics used in progressive tile painting. */ 1.924 + const uint32_t mAPZCId; 1.925 + 1.926 + ipc::SharedMemoryBasic* mSharedFrameMetricsBuffer; 1.927 + CrossProcessMutex* mSharedLock; 1.928 + /** 1.929 + * Called when ever mFrameMetrics is updated so that if it is being 1.930 + * shared with the content process the shared FrameMetrics may be updated. 1.931 + */ 1.932 + void UpdateSharedCompositorFrameMetrics(); 1.933 + /** 1.934 + * Create a shared memory buffer for containing the FrameMetrics and 1.935 + * a CrossProcessMutex that may be shared with the content process 1.936 + * for use in progressive tiled update calculations. 1.937 + */ 1.938 + void ShareCompositorFrameMetrics(); 1.939 +}; 1.940 + 1.941 +class AsyncPanZoomAnimation { 1.942 + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AsyncPanZoomAnimation) 1.943 + 1.944 +public: 1.945 + AsyncPanZoomAnimation(const TimeDuration& aRepaintInterval = 1.946 + TimeDuration::Forever()) 1.947 + : mRepaintInterval(aRepaintInterval) 1.948 + { } 1.949 + 1.950 + virtual bool Sample(FrameMetrics& aFrameMetrics, 1.951 + const TimeDuration& aDelta) = 0; 1.952 + 1.953 + /** 1.954 + * Get the deferred tasks in |mDeferredTasks|. See |mDeferredTasks| 1.955 + * for more information. 1.956 + * Clears |mDeferredTasks|. 1.957 + */ 1.958 + Vector<Task*> TakeDeferredTasks() { 1.959 + Vector<Task*> result; 1.960 + mDeferredTasks.swap(result); 1.961 + return result; 1.962 + } 1.963 + 1.964 + /** 1.965 + * Specifies how frequently (at most) we want to do repaints during the 1.966 + * animation sequence. TimeDuration::Forever() will cause it to only repaint 1.967 + * at the end of the animation. 1.968 + */ 1.969 + TimeDuration mRepaintInterval; 1.970 + 1.971 +protected: 1.972 + // Protected destructor, to discourage deletion outside of Release(): 1.973 + virtual ~AsyncPanZoomAnimation() 1.974 + { } 1.975 + 1.976 + /** 1.977 + * Tasks scheduled for execution after the APZC's mMonitor is released. 1.978 + * Derived classes can add tasks here in Sample(), and the APZC can call 1.979 + * ExecuteDeferredTasks() to execute them. 1.980 + */ 1.981 + Vector<Task*> mDeferredTasks; 1.982 +}; 1.983 + 1.984 +} 1.985 +} 1.986 + 1.987 +#endif // mozilla_layers_PanZoomController_h