gfx/layers/apz/src/APZCTreeManager.h

changeset 0
6474c204b198
     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

mercurial