gfx/layers/apz/src/APZCTreeManager.h

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #ifndef mozilla_layers_APZCTreeManager_h
michael@0 7 #define mozilla_layers_APZCTreeManager_h
michael@0 8
michael@0 9 #include <stdint.h> // for uint64_t, uint32_t
michael@0 10 #include "FrameMetrics.h" // for FrameMetrics, etc
michael@0 11 #include "Units.h" // for CSSPoint, CSSRect, etc
michael@0 12 #include "gfxPoint.h" // for gfxPoint
michael@0 13 #include "gfx3DMatrix.h" // for gfx3DMatrix
michael@0 14 #include "mozilla/Assertions.h" // for MOZ_ASSERT_HELPER2
michael@0 15 #include "mozilla/EventForwards.h" // for WidgetInputEvent, nsEventStatus
michael@0 16 #include "mozilla/Monitor.h" // for Monitor
michael@0 17 #include "nsAutoPtr.h" // for nsRefPtr
michael@0 18 #include "nsCOMPtr.h" // for already_AddRefed
michael@0 19 #include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
michael@0 20 #include "mozilla/Vector.h" // for mozilla::Vector
michael@0 21 #include "nsTArrayForwardDeclare.h" // for nsTArray, nsTArray_Impl, etc
michael@0 22 #include "mozilla/gfx/Logging.h" // for gfx::TreeLog
michael@0 23
michael@0 24 class gfx3DMatrix;
michael@0 25
michael@0 26 namespace mozilla {
michael@0 27 class InputData;
michael@0 28
michael@0 29 namespace layers {
michael@0 30
michael@0 31 enum AllowedTouchBehavior {
michael@0 32 NONE = 0,
michael@0 33 VERTICAL_PAN = 1 << 0,
michael@0 34 HORIZONTAL_PAN = 1 << 1,
michael@0 35 PINCH_ZOOM = 1 << 2,
michael@0 36 DOUBLE_TAP_ZOOM = 1 << 3,
michael@0 37 UNKNOWN = 1 << 4
michael@0 38 };
michael@0 39
michael@0 40 class Layer;
michael@0 41 class AsyncPanZoomController;
michael@0 42 class CompositorParent;
michael@0 43
michael@0 44 /**
michael@0 45 * ****************** NOTE ON LOCK ORDERING IN APZ **************************
michael@0 46 *
michael@0 47 * There are two kinds of locks used by APZ: APZCTreeManager::mTreeLock
michael@0 48 * ("the tree lock") and AsyncPanZoomController::mMonitor ("APZC locks").
michael@0 49 *
michael@0 50 * To avoid deadlock, we impose a lock ordering between these locks, which is:
michael@0 51 *
michael@0 52 * tree lock -> APZC locks
michael@0 53 *
michael@0 54 * The interpretation of the lock ordering is that if lock A precedes lock B
michael@0 55 * in the ordering sequence, then you must NOT wait on A while holding B.
michael@0 56 *
michael@0 57 * **************************************************************************
michael@0 58 */
michael@0 59
michael@0 60 /**
michael@0 61 * This class manages the tree of AsyncPanZoomController instances. There is one
michael@0 62 * instance of this class owned by each CompositorParent, and it contains as
michael@0 63 * many AsyncPanZoomController instances as there are scrollable container layers.
michael@0 64 * This class generally lives on the compositor thread, although some functions
michael@0 65 * may be called from other threads as noted; thread safety is ensured internally.
michael@0 66 *
michael@0 67 * The bulk of the work of this class happens as part of the UpdatePanZoomControllerTree
michael@0 68 * function, which is when a layer tree update is received by the compositor.
michael@0 69 * This function walks through the layer tree and creates a tree of APZC instances
michael@0 70 * to match the scrollable container layers. APZC instances may be preserved across
michael@0 71 * calls to this function if the corresponding layers are still present in the layer
michael@0 72 * tree.
michael@0 73 *
michael@0 74 * The other functions on this class are used by various pieces of client code to
michael@0 75 * notify the APZC instances of events relevant to them. This includes, for example,
michael@0 76 * user input events that drive panning and zooming, changes to the scroll viewport
michael@0 77 * area, and changes to pan/zoom constraints.
michael@0 78 *
michael@0 79 * Note that the ClearTree function MUST be called when this class is no longer needed;
michael@0 80 * see the method documentation for details.
michael@0 81 */
michael@0 82 class APZCTreeManager {
michael@0 83 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(APZCTreeManager)
michael@0 84
michael@0 85 typedef mozilla::layers::AllowedTouchBehavior AllowedTouchBehavior;
michael@0 86 typedef uint32_t TouchBehaviorFlags;
michael@0 87
michael@0 88 public:
michael@0 89 APZCTreeManager();
michael@0 90
michael@0 91 /**
michael@0 92 * Rebuild the APZC tree based on the layer update that just came up. Preserve
michael@0 93 * APZC instances where possible, but retire those whose layers are no longer
michael@0 94 * in the layer tree.
michael@0 95 *
michael@0 96 * This must be called on the compositor thread as it walks the layer tree.
michael@0 97 *
michael@0 98 * @param aCompositor A pointer to the compositor parent instance that owns
michael@0 99 * this APZCTreeManager
michael@0 100 * @param aRoot The root of the (full) layer tree
michael@0 101 * @param aFirstPaintLayersId The layers id of the subtree to which aIsFirstPaint
michael@0 102 * applies.
michael@0 103 * @param aIsFirstPaint True if the layers update that this is called in response
michael@0 104 * to included a first-paint. If this is true, the part of
michael@0 105 * the tree that is affected by the first-paint flag is
michael@0 106 * indicated by the aFirstPaintLayersId parameter.
michael@0 107 */
michael@0 108 void UpdatePanZoomControllerTree(CompositorParent* aCompositor, Layer* aRoot,
michael@0 109 bool aIsFirstPaint, uint64_t aFirstPaintLayersId);
michael@0 110
michael@0 111 /**
michael@0 112 * General handler for incoming input events. Manipulates the frame metrics
michael@0 113 * based on what type of input it is. For example, a PinchGestureEvent will
michael@0 114 * cause scaling. This should only be called externally to this class.
michael@0 115 *
michael@0 116 * @param aEvent input event object, will not be modified
michael@0 117 * @param aOutTargetGuid returns the guid of the apzc this event was
michael@0 118 * delivered to. May be null.
michael@0 119 */
michael@0 120 nsEventStatus ReceiveInputEvent(const InputData& aEvent,
michael@0 121 ScrollableLayerGuid* aOutTargetGuid);
michael@0 122
michael@0 123 /**
michael@0 124 * WidgetInputEvent handler. Transforms |aEvent| (which is assumed to be an
michael@0 125 * already-existing instance of an WidgetInputEvent which may be an
michael@0 126 * WidgetTouchEvent) to have its coordinates in DOM space. This is so that the
michael@0 127 * event can be passed through the DOM and content can handle them.
michael@0 128 *
michael@0 129 * NOTE: Be careful of invoking the WidgetInputEvent variant. This can only be
michael@0 130 * called on the main thread. See widget/InputData.h for more information on
michael@0 131 * why we have InputData and WidgetInputEvent separated.
michael@0 132 * NOTE: On unix, mouse events are treated as touch and are forwarded
michael@0 133 * to the appropriate apz as such.
michael@0 134 *
michael@0 135 * @param aEvent input event object; is modified in-place
michael@0 136 * @param aOutTargetGuid returns the guid of the apzc this event was
michael@0 137 * delivered to. May be null.
michael@0 138 */
michael@0 139 nsEventStatus ReceiveInputEvent(WidgetInputEvent& aEvent,
michael@0 140 ScrollableLayerGuid* aOutTargetGuid);
michael@0 141
michael@0 142 /**
michael@0 143 * A helper for transforming coordinates to gecko coordinate space.
michael@0 144 *
michael@0 145 * @param aPoint point to transform
michael@0 146 * @param aOutTransformedPoint resulting transformed point
michael@0 147 */
michael@0 148 void TransformCoordinateToGecko(const ScreenIntPoint& aPoint,
michael@0 149 LayoutDeviceIntPoint* aOutTransformedPoint);
michael@0 150
michael@0 151 /**
michael@0 152 * Kicks an animation to zoom to a rect. This may be either a zoom out or zoom
michael@0 153 * in. The actual animation is done on the compositor thread after being set
michael@0 154 * up. |aRect| must be given in CSS pixels, relative to the document.
michael@0 155 */
michael@0 156 void ZoomToRect(const ScrollableLayerGuid& aGuid,
michael@0 157 const CSSRect& aRect);
michael@0 158
michael@0 159 /**
michael@0 160 * If we have touch listeners, this should always be called when we know
michael@0 161 * definitively whether or not content has preventDefaulted any touch events
michael@0 162 * that have come in. If |aPreventDefault| is true, any touch events in the
michael@0 163 * queue will be discarded.
michael@0 164 */
michael@0 165 void ContentReceivedTouch(const ScrollableLayerGuid& aGuid,
michael@0 166 bool aPreventDefault);
michael@0 167
michael@0 168 /**
michael@0 169 * Updates any zoom constraints contained in the <meta name="viewport"> tag.
michael@0 170 */
michael@0 171 void UpdateZoomConstraints(const ScrollableLayerGuid& aGuid,
michael@0 172 const ZoomConstraints& aConstraints);
michael@0 173
michael@0 174 /**
michael@0 175 * Cancels any currently running animation. Note that all this does is set the
michael@0 176 * state of the AsyncPanZoomController back to NOTHING, but it is the
michael@0 177 * animation's responsibility to check this before advancing.
michael@0 178 */
michael@0 179 void CancelAnimation(const ScrollableLayerGuid &aGuid);
michael@0 180
michael@0 181 /**
michael@0 182 * Calls Destroy() on all APZC instances attached to the tree, and resets the
michael@0 183 * tree back to empty. This function may be called multiple times during the
michael@0 184 * lifetime of this APZCTreeManager, but it must always be called at least once
michael@0 185 * when this APZCTreeManager is no longer needed. Failing to call this function
michael@0 186 * may prevent objects from being freed properly.
michael@0 187 */
michael@0 188 void ClearTree();
michael@0 189
michael@0 190 /**
michael@0 191 * Tests if a screen point intersect an apz in the tree.
michael@0 192 */
michael@0 193 bool HitTestAPZC(const ScreenIntPoint& aPoint);
michael@0 194
michael@0 195 /**
michael@0 196 * Set the dpi value used by all AsyncPanZoomControllers.
michael@0 197 * DPI defaults to 72 if not set using SetDPI() at any point.
michael@0 198 */
michael@0 199 static void SetDPI(float aDpiValue) { sDPI = aDpiValue; }
michael@0 200
michael@0 201 /**
michael@0 202 * Returns the current dpi value in use.
michael@0 203 */
michael@0 204 static float GetDPI() { return sDPI; }
michael@0 205
michael@0 206 /**
michael@0 207 * Returns values of allowed touch-behavior for the touches of aEvent via out parameter.
michael@0 208 * Internally performs asks appropriate AsyncPanZoomController to perform
michael@0 209 * hit testing on its own.
michael@0 210 */
michael@0 211 void GetAllowedTouchBehavior(WidgetInputEvent* aEvent,
michael@0 212 nsTArray<TouchBehaviorFlags>& aOutValues);
michael@0 213
michael@0 214 /**
michael@0 215 * Sets allowed touch behavior values for current touch-session for specific apzc (determined by guid).
michael@0 216 * Should be invoked by the widget. Each value of the aValues arrays corresponds to the different
michael@0 217 * touch point that is currently active.
michael@0 218 * Must be called after receiving the TOUCH_START event that starts the touch-session.
michael@0 219 */
michael@0 220 void SetAllowedTouchBehavior(const ScrollableLayerGuid& aGuid,
michael@0 221 const nsTArray<TouchBehaviorFlags>& aValues);
michael@0 222
michael@0 223 /**
michael@0 224 * This is a callback for AsyncPanZoomController to call when it wants to
michael@0 225 * scroll in response to a touch-move event, or when it needs to hand off
michael@0 226 * overscroll to the next APZC. Note that because of scroll grabbing, the
michael@0 227 * first APZC to scroll may not be the one that is receiving the touch events.
michael@0 228 *
michael@0 229 * |aAPZC| is the APZC that received the touch events triggering the scroll
michael@0 230 * (in the case of an initial scroll), or the last APZC to scroll (in the
michael@0 231 * case of overscroll)
michael@0 232 * |aStartPoint| and |aEndPoint| are in |aAPZC|'s transformed screen
michael@0 233 * coordinates (i.e. the same coordinates in which touch points are given to
michael@0 234 * APZCs). The amount of (over)scroll is represented by two points rather
michael@0 235 * than a displacement because with certain 3D transforms, the same
michael@0 236 * displacement between different points in transformed coordinates can
michael@0 237 * represent different displacements in untransformed coordinates.
michael@0 238 * |aOverscrollHandoffChainIndex| is the next position in the overscroll
michael@0 239 * handoff chain that should be scrolled.
michael@0 240 *
michael@0 241 * The way this method works is best illustrated with an example.
michael@0 242 * Consider three nested APZCs, A, B, and C, with C being the innermost one.
michael@0 243 * Say B is scroll-grabbing.
michael@0 244 * The touch events go to C because it's the innermost one (so e.g. taps
michael@0 245 * should go through C), but the overscroll handoff chain is B -> C -> A
michael@0 246 * because B is scroll-grabbing.
michael@0 247 * For convenience I'll refer to the three APZC objects as A, B, and C, and
michael@0 248 * to the tree manager object as TM.
michael@0 249 * Here's what happens when C receives a touch-move event:
michael@0 250 * - C.TrackTouch() calls TM.DispatchScroll() with index = 0.
michael@0 251 * - TM.DispatchScroll() calls B.AttemptScroll() (since B is at index 0 in the chain).
michael@0 252 * - B.AttemptScroll() scrolls B. If there is overscroll, it calls TM.DispatchScroll() with index = 1.
michael@0 253 * - TM.DispatchScroll() calls C.AttemptScroll() (since C is at index 1 in the chain)
michael@0 254 * - C.AttemptScroll() scrolls C. If there is overscroll, it calls TM.DispatchScroll() with index = 2.
michael@0 255 * - TM.DispatchScroll() calls A.AttemptScroll() (since A is at index 2 in the chain)
michael@0 256 * - A.AttemptScroll() scrolls A. If there is overscroll, it calls TM.DispatchScroll() with index = 3.
michael@0 257 * - TM.DispatchScroll() discards the rest of the scroll as there are no more elements in the chain.
michael@0 258 *
michael@0 259 * Note: this should be used for panning only. For handing off overscroll for
michael@0 260 * a fling, use HandOffFling().
michael@0 261 */
michael@0 262 void DispatchScroll(AsyncPanZoomController* aAPZC, ScreenPoint aStartPoint, ScreenPoint aEndPoint,
michael@0 263 uint32_t aOverscrollHandoffChainIndex);
michael@0 264
michael@0 265 /**
michael@0 266 * This is a callback for AsyncPanZoomController to call when it wants to
michael@0 267 * hand off overscroll from a fling.
michael@0 268 * @param aApzc the APZC that is handing off the fling
michael@0 269 * @param aVelocity the current velocity of the fling, in |aApzc|'s screen
michael@0 270 * pixels per millisecond
michael@0 271 */
michael@0 272 void HandOffFling(AsyncPanZoomController* aApzc, ScreenPoint aVelocity);
michael@0 273
michael@0 274 bool FlushRepaintsForOverscrollHandoffChain();
michael@0 275
michael@0 276 /**
michael@0 277 * Determine whether |aApzc|, or any APZC along its overscroll handoff chain,
michael@0 278 * has room to be panned.
michael@0 279 * Expects the overscroll handoff chain to already be built.
michael@0 280 */
michael@0 281 bool CanBePanned(AsyncPanZoomController* aApzc);
michael@0 282
michael@0 283 protected:
michael@0 284 // Protected destructor, to discourage deletion outside of Release():
michael@0 285 virtual ~APZCTreeManager();
michael@0 286
michael@0 287 /**
michael@0 288 * Debug-build assertion that can be called to ensure code is running on the
michael@0 289 * compositor thread.
michael@0 290 */
michael@0 291 virtual void AssertOnCompositorThread();
michael@0 292
michael@0 293 /*
michael@0 294 * Build the chain of APZCs that will handle overscroll for a pan starting at |aInitialTarget|.
michael@0 295 */
michael@0 296 void BuildOverscrollHandoffChain(const nsRefPtr<AsyncPanZoomController>& aInitialTarget);
michael@0 297 public:
michael@0 298 /* Some helper functions to find an APZC given some identifying input. These functions
michael@0 299 lock the tree of APZCs while they find the right one, and then return an addref'd
michael@0 300 pointer to it. This allows caller code to just use the target APZC without worrying
michael@0 301 about it going away. These are public for testing code and generally should not be
michael@0 302 used by other production code.
michael@0 303 */
michael@0 304 already_AddRefed<AsyncPanZoomController> GetTargetAPZC(const ScrollableLayerGuid& aGuid);
michael@0 305 already_AddRefed<AsyncPanZoomController> GetTargetAPZC(const ScreenPoint& aPoint);
michael@0 306 void GetInputTransforms(AsyncPanZoomController *aApzc, gfx3DMatrix& aTransformToApzcOut,
michael@0 307 gfx3DMatrix& aTransformToGeckoOut);
michael@0 308 private:
michael@0 309 /* Helpers */
michael@0 310 AsyncPanZoomController* FindTargetAPZC(AsyncPanZoomController* aApzc, FrameMetrics::ViewID aScrollId);
michael@0 311 AsyncPanZoomController* FindTargetAPZC(AsyncPanZoomController* aApzc, const ScrollableLayerGuid& aGuid);
michael@0 312 AsyncPanZoomController* GetAPZCAtPoint(AsyncPanZoomController* aApzc, const gfxPoint& aHitTestPoint);
michael@0 313 already_AddRefed<AsyncPanZoomController> CommonAncestor(AsyncPanZoomController* aApzc1, AsyncPanZoomController* aApzc2);
michael@0 314 already_AddRefed<AsyncPanZoomController> RootAPZCForLayersId(AsyncPanZoomController* aApzc);
michael@0 315 already_AddRefed<AsyncPanZoomController> GetTouchInputBlockAPZC(const WidgetTouchEvent& aEvent);
michael@0 316 nsEventStatus ProcessTouchEvent(WidgetTouchEvent& touchEvent, ScrollableLayerGuid* aOutTargetGuid);
michael@0 317 nsEventStatus ProcessEvent(WidgetInputEvent& inputEvent, ScrollableLayerGuid* aOutTargetGuid);
michael@0 318 void UpdateZoomConstraintsRecursively(AsyncPanZoomController* aApzc,
michael@0 319 const ZoomConstraints& aConstraints);
michael@0 320 void ClearOverscrollHandoffChain();
michael@0 321
michael@0 322 /**
michael@0 323 * Recursive helper function to build the APZC tree. The tree of APZC instances has
michael@0 324 * the same shape as the layer tree, but excludes all the layers that are not scrollable.
michael@0 325 * Note that this means APZCs corresponding to layers at different depths in the tree
michael@0 326 * may end up becoming siblings. It also means that the "root" APZC may have siblings.
michael@0 327 * This function walks the layer tree backwards through siblings and constructs the APZC
michael@0 328 * tree also as a last-child-prev-sibling tree because that simplifies the hit detection
michael@0 329 * code.
michael@0 330 */
michael@0 331 AsyncPanZoomController* UpdatePanZoomControllerTree(CompositorParent* aCompositor,
michael@0 332 Layer* aLayer, uint64_t aLayersId,
michael@0 333 gfx3DMatrix aTransform,
michael@0 334 AsyncPanZoomController* aParent,
michael@0 335 AsyncPanZoomController* aNextSibling,
michael@0 336 bool aIsFirstPaint,
michael@0 337 uint64_t aFirstPaintLayersId,
michael@0 338 nsTArray< nsRefPtr<AsyncPanZoomController> >* aApzcsToDestroy);
michael@0 339
michael@0 340 private:
michael@0 341 /* Whenever walking or mutating the tree rooted at mRootApzc, mTreeLock must be held.
michael@0 342 * This lock does not need to be held while manipulating a single APZC instance in
michael@0 343 * isolation (that is, if its tree pointers are not being accessed or mutated). The
michael@0 344 * lock also needs to be held when accessing the mRootApzc instance variable, as that
michael@0 345 * is considered part of the APZC tree management state.
michael@0 346 * Finally, the lock needs to be held when accessing mOverscrollHandoffChain.
michael@0 347 * IMPORTANT: See the note about lock ordering at the top of this file. */
michael@0 348 mozilla::Monitor mTreeLock;
michael@0 349 nsRefPtr<AsyncPanZoomController> mRootApzc;
michael@0 350 /* This tracks the APZC that should receive all inputs for the current input event block.
michael@0 351 * This allows touch points to move outside the thing they started on, but still have the
michael@0 352 * touch events delivered to the same initial APZC. This will only ever be touched on the
michael@0 353 * input delivery thread, and so does not require locking.
michael@0 354 */
michael@0 355 nsRefPtr<AsyncPanZoomController> mApzcForInputBlock;
michael@0 356 /* The number of touch points we are tracking that are currently on the screen. */
michael@0 357 uint32_t mTouchCount;
michael@0 358 /* The transform from root screen coordinates into mApzcForInputBlock's
michael@0 359 * screen coordinates, as returned through the 'aTransformToApzcOut' parameter
michael@0 360 * of GetInputTransform(), at the start of the input block. This is cached
michael@0 361 * because this transform can change over the course of the input block,
michael@0 362 * but for some operations we need to use the initial transform.
michael@0 363 * Meaningless if mApzcForInputBlock is nullptr.
michael@0 364 */
michael@0 365 gfx3DMatrix mCachedTransformToApzcForInputBlock;
michael@0 366 /* The chain of APZCs that will handle pans for the current touch input
michael@0 367 * block, in the order in which they will be scrolled. When one APZC has
michael@0 368 * been scrolled as far as it can, any overscroll will be handed off to
michael@0 369 * the next APZC in the chain.
michael@0 370 */
michael@0 371 Vector< nsRefPtr<AsyncPanZoomController> > mOverscrollHandoffChain;
michael@0 372 /* For logging the APZC tree for debugging (enabled by the apz.printtree
michael@0 373 * pref). */
michael@0 374 gfx::TreeLog mApzcTreeLog;
michael@0 375
michael@0 376 static float sDPI;
michael@0 377 };
michael@0 378
michael@0 379 }
michael@0 380 }
michael@0 381
michael@0 382 #endif // mozilla_layers_PanZoomController_h

mercurial