1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/layers/apz/src/APZCTreeManager.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,382 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#ifndef mozilla_layers_APZCTreeManager_h 1.10 +#define mozilla_layers_APZCTreeManager_h 1.11 + 1.12 +#include <stdint.h> // for uint64_t, uint32_t 1.13 +#include "FrameMetrics.h" // for FrameMetrics, etc 1.14 +#include "Units.h" // for CSSPoint, CSSRect, etc 1.15 +#include "gfxPoint.h" // for gfxPoint 1.16 +#include "gfx3DMatrix.h" // for gfx3DMatrix 1.17 +#include "mozilla/Assertions.h" // for MOZ_ASSERT_HELPER2 1.18 +#include "mozilla/EventForwards.h" // for WidgetInputEvent, nsEventStatus 1.19 +#include "mozilla/Monitor.h" // for Monitor 1.20 +#include "nsAutoPtr.h" // for nsRefPtr 1.21 +#include "nsCOMPtr.h" // for already_AddRefed 1.22 +#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc 1.23 +#include "mozilla/Vector.h" // for mozilla::Vector 1.24 +#include "nsTArrayForwardDeclare.h" // for nsTArray, nsTArray_Impl, etc 1.25 +#include "mozilla/gfx/Logging.h" // for gfx::TreeLog 1.26 + 1.27 +class gfx3DMatrix; 1.28 + 1.29 +namespace mozilla { 1.30 +class InputData; 1.31 + 1.32 +namespace layers { 1.33 + 1.34 +enum AllowedTouchBehavior { 1.35 + NONE = 0, 1.36 + VERTICAL_PAN = 1 << 0, 1.37 + HORIZONTAL_PAN = 1 << 1, 1.38 + PINCH_ZOOM = 1 << 2, 1.39 + DOUBLE_TAP_ZOOM = 1 << 3, 1.40 + UNKNOWN = 1 << 4 1.41 +}; 1.42 + 1.43 +class Layer; 1.44 +class AsyncPanZoomController; 1.45 +class CompositorParent; 1.46 + 1.47 +/** 1.48 + * ****************** NOTE ON LOCK ORDERING IN APZ ************************** 1.49 + * 1.50 + * There are two kinds of locks used by APZ: APZCTreeManager::mTreeLock 1.51 + * ("the tree lock") and AsyncPanZoomController::mMonitor ("APZC locks"). 1.52 + * 1.53 + * To avoid deadlock, we impose a lock ordering between these locks, which is: 1.54 + * 1.55 + * tree lock -> APZC locks 1.56 + * 1.57 + * The interpretation of the lock ordering is that if lock A precedes lock B 1.58 + * in the ordering sequence, then you must NOT wait on A while holding B. 1.59 + * 1.60 + * ************************************************************************** 1.61 + */ 1.62 + 1.63 +/** 1.64 + * This class manages the tree of AsyncPanZoomController instances. There is one 1.65 + * instance of this class owned by each CompositorParent, and it contains as 1.66 + * many AsyncPanZoomController instances as there are scrollable container layers. 1.67 + * This class generally lives on the compositor thread, although some functions 1.68 + * may be called from other threads as noted; thread safety is ensured internally. 1.69 + * 1.70 + * The bulk of the work of this class happens as part of the UpdatePanZoomControllerTree 1.71 + * function, which is when a layer tree update is received by the compositor. 1.72 + * This function walks through the layer tree and creates a tree of APZC instances 1.73 + * to match the scrollable container layers. APZC instances may be preserved across 1.74 + * calls to this function if the corresponding layers are still present in the layer 1.75 + * tree. 1.76 + * 1.77 + * The other functions on this class are used by various pieces of client code to 1.78 + * notify the APZC instances of events relevant to them. This includes, for example, 1.79 + * user input events that drive panning and zooming, changes to the scroll viewport 1.80 + * area, and changes to pan/zoom constraints. 1.81 + * 1.82 + * Note that the ClearTree function MUST be called when this class is no longer needed; 1.83 + * see the method documentation for details. 1.84 + */ 1.85 +class APZCTreeManager { 1.86 + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(APZCTreeManager) 1.87 + 1.88 + typedef mozilla::layers::AllowedTouchBehavior AllowedTouchBehavior; 1.89 + typedef uint32_t TouchBehaviorFlags; 1.90 + 1.91 +public: 1.92 + APZCTreeManager(); 1.93 + 1.94 + /** 1.95 + * Rebuild the APZC tree based on the layer update that just came up. Preserve 1.96 + * APZC instances where possible, but retire those whose layers are no longer 1.97 + * in the layer tree. 1.98 + * 1.99 + * This must be called on the compositor thread as it walks the layer tree. 1.100 + * 1.101 + * @param aCompositor A pointer to the compositor parent instance that owns 1.102 + * this APZCTreeManager 1.103 + * @param aRoot The root of the (full) layer tree 1.104 + * @param aFirstPaintLayersId The layers id of the subtree to which aIsFirstPaint 1.105 + * applies. 1.106 + * @param aIsFirstPaint True if the layers update that this is called in response 1.107 + * to included a first-paint. If this is true, the part of 1.108 + * the tree that is affected by the first-paint flag is 1.109 + * indicated by the aFirstPaintLayersId parameter. 1.110 + */ 1.111 + void UpdatePanZoomControllerTree(CompositorParent* aCompositor, Layer* aRoot, 1.112 + bool aIsFirstPaint, uint64_t aFirstPaintLayersId); 1.113 + 1.114 + /** 1.115 + * General handler for incoming input events. Manipulates the frame metrics 1.116 + * based on what type of input it is. For example, a PinchGestureEvent will 1.117 + * cause scaling. This should only be called externally to this class. 1.118 + * 1.119 + * @param aEvent input event object, will not be modified 1.120 + * @param aOutTargetGuid returns the guid of the apzc this event was 1.121 + * delivered to. May be null. 1.122 + */ 1.123 + nsEventStatus ReceiveInputEvent(const InputData& aEvent, 1.124 + ScrollableLayerGuid* aOutTargetGuid); 1.125 + 1.126 + /** 1.127 + * WidgetInputEvent handler. Transforms |aEvent| (which is assumed to be an 1.128 + * already-existing instance of an WidgetInputEvent which may be an 1.129 + * WidgetTouchEvent) to have its coordinates in DOM space. This is so that the 1.130 + * event can be passed through the DOM and content can handle them. 1.131 + * 1.132 + * NOTE: Be careful of invoking the WidgetInputEvent variant. This can only be 1.133 + * called on the main thread. See widget/InputData.h for more information on 1.134 + * why we have InputData and WidgetInputEvent separated. 1.135 + * NOTE: On unix, mouse events are treated as touch and are forwarded 1.136 + * to the appropriate apz as such. 1.137 + * 1.138 + * @param aEvent input event object; is modified in-place 1.139 + * @param aOutTargetGuid returns the guid of the apzc this event was 1.140 + * delivered to. May be null. 1.141 + */ 1.142 + nsEventStatus ReceiveInputEvent(WidgetInputEvent& aEvent, 1.143 + ScrollableLayerGuid* aOutTargetGuid); 1.144 + 1.145 + /** 1.146 + * A helper for transforming coordinates to gecko coordinate space. 1.147 + * 1.148 + * @param aPoint point to transform 1.149 + * @param aOutTransformedPoint resulting transformed point 1.150 + */ 1.151 + void TransformCoordinateToGecko(const ScreenIntPoint& aPoint, 1.152 + LayoutDeviceIntPoint* aOutTransformedPoint); 1.153 + 1.154 + /** 1.155 + * Kicks an animation to zoom to a rect. This may be either a zoom out or zoom 1.156 + * in. The actual animation is done on the compositor thread after being set 1.157 + * up. |aRect| must be given in CSS pixels, relative to the document. 1.158 + */ 1.159 + void ZoomToRect(const ScrollableLayerGuid& aGuid, 1.160 + const CSSRect& aRect); 1.161 + 1.162 + /** 1.163 + * If we have touch listeners, this should always be called when we know 1.164 + * definitively whether or not content has preventDefaulted any touch events 1.165 + * that have come in. If |aPreventDefault| is true, any touch events in the 1.166 + * queue will be discarded. 1.167 + */ 1.168 + void ContentReceivedTouch(const ScrollableLayerGuid& aGuid, 1.169 + bool aPreventDefault); 1.170 + 1.171 + /** 1.172 + * Updates any zoom constraints contained in the <meta name="viewport"> tag. 1.173 + */ 1.174 + void UpdateZoomConstraints(const ScrollableLayerGuid& aGuid, 1.175 + const ZoomConstraints& aConstraints); 1.176 + 1.177 + /** 1.178 + * Cancels any currently running animation. Note that all this does is set the 1.179 + * state of the AsyncPanZoomController back to NOTHING, but it is the 1.180 + * animation's responsibility to check this before advancing. 1.181 + */ 1.182 + void CancelAnimation(const ScrollableLayerGuid &aGuid); 1.183 + 1.184 + /** 1.185 + * Calls Destroy() on all APZC instances attached to the tree, and resets the 1.186 + * tree back to empty. This function may be called multiple times during the 1.187 + * lifetime of this APZCTreeManager, but it must always be called at least once 1.188 + * when this APZCTreeManager is no longer needed. Failing to call this function 1.189 + * may prevent objects from being freed properly. 1.190 + */ 1.191 + void ClearTree(); 1.192 + 1.193 + /** 1.194 + * Tests if a screen point intersect an apz in the tree. 1.195 + */ 1.196 + bool HitTestAPZC(const ScreenIntPoint& aPoint); 1.197 + 1.198 + /** 1.199 + * Set the dpi value used by all AsyncPanZoomControllers. 1.200 + * DPI defaults to 72 if not set using SetDPI() at any point. 1.201 + */ 1.202 + static void SetDPI(float aDpiValue) { sDPI = aDpiValue; } 1.203 + 1.204 + /** 1.205 + * Returns the current dpi value in use. 1.206 + */ 1.207 + static float GetDPI() { return sDPI; } 1.208 + 1.209 + /** 1.210 + * Returns values of allowed touch-behavior for the touches of aEvent via out parameter. 1.211 + * Internally performs asks appropriate AsyncPanZoomController to perform 1.212 + * hit testing on its own. 1.213 + */ 1.214 + void GetAllowedTouchBehavior(WidgetInputEvent* aEvent, 1.215 + nsTArray<TouchBehaviorFlags>& aOutValues); 1.216 + 1.217 + /** 1.218 + * Sets allowed touch behavior values for current touch-session for specific apzc (determined by guid). 1.219 + * Should be invoked by the widget. Each value of the aValues arrays corresponds to the different 1.220 + * touch point that is currently active. 1.221 + * Must be called after receiving the TOUCH_START event that starts the touch-session. 1.222 + */ 1.223 + void SetAllowedTouchBehavior(const ScrollableLayerGuid& aGuid, 1.224 + const nsTArray<TouchBehaviorFlags>& aValues); 1.225 + 1.226 + /** 1.227 + * This is a callback for AsyncPanZoomController to call when it wants to 1.228 + * scroll in response to a touch-move event, or when it needs to hand off 1.229 + * overscroll to the next APZC. Note that because of scroll grabbing, the 1.230 + * first APZC to scroll may not be the one that is receiving the touch events. 1.231 + * 1.232 + * |aAPZC| is the APZC that received the touch events triggering the scroll 1.233 + * (in the case of an initial scroll), or the last APZC to scroll (in the 1.234 + * case of overscroll) 1.235 + * |aStartPoint| and |aEndPoint| are in |aAPZC|'s transformed screen 1.236 + * coordinates (i.e. the same coordinates in which touch points are given to 1.237 + * APZCs). The amount of (over)scroll is represented by two points rather 1.238 + * than a displacement because with certain 3D transforms, the same 1.239 + * displacement between different points in transformed coordinates can 1.240 + * represent different displacements in untransformed coordinates. 1.241 + * |aOverscrollHandoffChainIndex| is the next position in the overscroll 1.242 + * handoff chain that should be scrolled. 1.243 + * 1.244 + * The way this method works is best illustrated with an example. 1.245 + * Consider three nested APZCs, A, B, and C, with C being the innermost one. 1.246 + * Say B is scroll-grabbing. 1.247 + * The touch events go to C because it's the innermost one (so e.g. taps 1.248 + * should go through C), but the overscroll handoff chain is B -> C -> A 1.249 + * because B is scroll-grabbing. 1.250 + * For convenience I'll refer to the three APZC objects as A, B, and C, and 1.251 + * to the tree manager object as TM. 1.252 + * Here's what happens when C receives a touch-move event: 1.253 + * - C.TrackTouch() calls TM.DispatchScroll() with index = 0. 1.254 + * - TM.DispatchScroll() calls B.AttemptScroll() (since B is at index 0 in the chain). 1.255 + * - B.AttemptScroll() scrolls B. If there is overscroll, it calls TM.DispatchScroll() with index = 1. 1.256 + * - TM.DispatchScroll() calls C.AttemptScroll() (since C is at index 1 in the chain) 1.257 + * - C.AttemptScroll() scrolls C. If there is overscroll, it calls TM.DispatchScroll() with index = 2. 1.258 + * - TM.DispatchScroll() calls A.AttemptScroll() (since A is at index 2 in the chain) 1.259 + * - A.AttemptScroll() scrolls A. If there is overscroll, it calls TM.DispatchScroll() with index = 3. 1.260 + * - TM.DispatchScroll() discards the rest of the scroll as there are no more elements in the chain. 1.261 + * 1.262 + * Note: this should be used for panning only. For handing off overscroll for 1.263 + * a fling, use HandOffFling(). 1.264 + */ 1.265 + void DispatchScroll(AsyncPanZoomController* aAPZC, ScreenPoint aStartPoint, ScreenPoint aEndPoint, 1.266 + uint32_t aOverscrollHandoffChainIndex); 1.267 + 1.268 + /** 1.269 + * This is a callback for AsyncPanZoomController to call when it wants to 1.270 + * hand off overscroll from a fling. 1.271 + * @param aApzc the APZC that is handing off the fling 1.272 + * @param aVelocity the current velocity of the fling, in |aApzc|'s screen 1.273 + * pixels per millisecond 1.274 + */ 1.275 + void HandOffFling(AsyncPanZoomController* aApzc, ScreenPoint aVelocity); 1.276 + 1.277 + bool FlushRepaintsForOverscrollHandoffChain(); 1.278 + 1.279 + /** 1.280 + * Determine whether |aApzc|, or any APZC along its overscroll handoff chain, 1.281 + * has room to be panned. 1.282 + * Expects the overscroll handoff chain to already be built. 1.283 + */ 1.284 + bool CanBePanned(AsyncPanZoomController* aApzc); 1.285 + 1.286 +protected: 1.287 + // Protected destructor, to discourage deletion outside of Release(): 1.288 + virtual ~APZCTreeManager(); 1.289 + 1.290 + /** 1.291 + * Debug-build assertion that can be called to ensure code is running on the 1.292 + * compositor thread. 1.293 + */ 1.294 + virtual void AssertOnCompositorThread(); 1.295 + 1.296 + /* 1.297 + * Build the chain of APZCs that will handle overscroll for a pan starting at |aInitialTarget|. 1.298 + */ 1.299 + void BuildOverscrollHandoffChain(const nsRefPtr<AsyncPanZoomController>& aInitialTarget); 1.300 +public: 1.301 + /* Some helper functions to find an APZC given some identifying input. These functions 1.302 + lock the tree of APZCs while they find the right one, and then return an addref'd 1.303 + pointer to it. This allows caller code to just use the target APZC without worrying 1.304 + about it going away. These are public for testing code and generally should not be 1.305 + used by other production code. 1.306 + */ 1.307 + already_AddRefed<AsyncPanZoomController> GetTargetAPZC(const ScrollableLayerGuid& aGuid); 1.308 + already_AddRefed<AsyncPanZoomController> GetTargetAPZC(const ScreenPoint& aPoint); 1.309 + void GetInputTransforms(AsyncPanZoomController *aApzc, gfx3DMatrix& aTransformToApzcOut, 1.310 + gfx3DMatrix& aTransformToGeckoOut); 1.311 +private: 1.312 + /* Helpers */ 1.313 + AsyncPanZoomController* FindTargetAPZC(AsyncPanZoomController* aApzc, FrameMetrics::ViewID aScrollId); 1.314 + AsyncPanZoomController* FindTargetAPZC(AsyncPanZoomController* aApzc, const ScrollableLayerGuid& aGuid); 1.315 + AsyncPanZoomController* GetAPZCAtPoint(AsyncPanZoomController* aApzc, const gfxPoint& aHitTestPoint); 1.316 + already_AddRefed<AsyncPanZoomController> CommonAncestor(AsyncPanZoomController* aApzc1, AsyncPanZoomController* aApzc2); 1.317 + already_AddRefed<AsyncPanZoomController> RootAPZCForLayersId(AsyncPanZoomController* aApzc); 1.318 + already_AddRefed<AsyncPanZoomController> GetTouchInputBlockAPZC(const WidgetTouchEvent& aEvent); 1.319 + nsEventStatus ProcessTouchEvent(WidgetTouchEvent& touchEvent, ScrollableLayerGuid* aOutTargetGuid); 1.320 + nsEventStatus ProcessEvent(WidgetInputEvent& inputEvent, ScrollableLayerGuid* aOutTargetGuid); 1.321 + void UpdateZoomConstraintsRecursively(AsyncPanZoomController* aApzc, 1.322 + const ZoomConstraints& aConstraints); 1.323 + void ClearOverscrollHandoffChain(); 1.324 + 1.325 + /** 1.326 + * Recursive helper function to build the APZC tree. The tree of APZC instances has 1.327 + * the same shape as the layer tree, but excludes all the layers that are not scrollable. 1.328 + * Note that this means APZCs corresponding to layers at different depths in the tree 1.329 + * may end up becoming siblings. It also means that the "root" APZC may have siblings. 1.330 + * This function walks the layer tree backwards through siblings and constructs the APZC 1.331 + * tree also as a last-child-prev-sibling tree because that simplifies the hit detection 1.332 + * code. 1.333 + */ 1.334 + AsyncPanZoomController* UpdatePanZoomControllerTree(CompositorParent* aCompositor, 1.335 + Layer* aLayer, uint64_t aLayersId, 1.336 + gfx3DMatrix aTransform, 1.337 + AsyncPanZoomController* aParent, 1.338 + AsyncPanZoomController* aNextSibling, 1.339 + bool aIsFirstPaint, 1.340 + uint64_t aFirstPaintLayersId, 1.341 + nsTArray< nsRefPtr<AsyncPanZoomController> >* aApzcsToDestroy); 1.342 + 1.343 +private: 1.344 + /* Whenever walking or mutating the tree rooted at mRootApzc, mTreeLock must be held. 1.345 + * This lock does not need to be held while manipulating a single APZC instance in 1.346 + * isolation (that is, if its tree pointers are not being accessed or mutated). The 1.347 + * lock also needs to be held when accessing the mRootApzc instance variable, as that 1.348 + * is considered part of the APZC tree management state. 1.349 + * Finally, the lock needs to be held when accessing mOverscrollHandoffChain. 1.350 + * IMPORTANT: See the note about lock ordering at the top of this file. */ 1.351 + mozilla::Monitor mTreeLock; 1.352 + nsRefPtr<AsyncPanZoomController> mRootApzc; 1.353 + /* This tracks the APZC that should receive all inputs for the current input event block. 1.354 + * This allows touch points to move outside the thing they started on, but still have the 1.355 + * touch events delivered to the same initial APZC. This will only ever be touched on the 1.356 + * input delivery thread, and so does not require locking. 1.357 + */ 1.358 + nsRefPtr<AsyncPanZoomController> mApzcForInputBlock; 1.359 + /* The number of touch points we are tracking that are currently on the screen. */ 1.360 + uint32_t mTouchCount; 1.361 + /* The transform from root screen coordinates into mApzcForInputBlock's 1.362 + * screen coordinates, as returned through the 'aTransformToApzcOut' parameter 1.363 + * of GetInputTransform(), at the start of the input block. This is cached 1.364 + * because this transform can change over the course of the input block, 1.365 + * but for some operations we need to use the initial transform. 1.366 + * Meaningless if mApzcForInputBlock is nullptr. 1.367 + */ 1.368 + gfx3DMatrix mCachedTransformToApzcForInputBlock; 1.369 + /* The chain of APZCs that will handle pans for the current touch input 1.370 + * block, in the order in which they will be scrolled. When one APZC has 1.371 + * been scrolled as far as it can, any overscroll will be handed off to 1.372 + * the next APZC in the chain. 1.373 + */ 1.374 + Vector< nsRefPtr<AsyncPanZoomController> > mOverscrollHandoffChain; 1.375 + /* For logging the APZC tree for debugging (enabled by the apz.printtree 1.376 + * pref). */ 1.377 + gfx::TreeLog mApzcTreeLog; 1.378 + 1.379 + static float sDPI; 1.380 +}; 1.381 + 1.382 +} 1.383 +} 1.384 + 1.385 +#endif // mozilla_layers_PanZoomController_h