tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

HitTestingTreeNode.h (11486B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #ifndef mozilla_layers_HitTestingTreeNode_h
      8 #define mozilla_layers_HitTestingTreeNode_h
      9 
     10 #include "mozilla/gfx/CompositorHitTestInfo.h"
     11 #include "mozilla/gfx/Matrix.h"                  // for Matrix4x4
     12 #include "mozilla/layers/LayersTypes.h"          // for EventRegions
     13 #include "mozilla/layers/ScrollableLayerGuid.h"  // for ScrollableLayerGuid
     14 #include "mozilla/layers/ScrollbarData.h"        // for ScrollbarData
     15 #include "mozilla/Maybe.h"                       // for Maybe
     16 #include "mozilla/RecursiveMutex.h"              // for RecursiveMutexAutoLock
     17 #include "mozilla/RefPtr.h"                      // for nsRefPtr
     18 namespace mozilla {
     19 namespace layers {
     20 
     21 class AsyncDragMetrics;
     22 class AsyncPanZoomController;
     23 
     24 /**
     25 * This class represents a node in a tree that is used by the APZCTreeManager
     26 * to do hit testing. The tree is roughly a copy of the layer tree, but will
     27 * contain multiple nodes in cases where the layer has multiple FrameMetrics.
     28 * In other words, the structure of this tree should be identical to the
     29 * WebRenderScrollDataWrapper tree (see documentation in
     30 * WebRenderScrollDataWrapper.h).
     31 *
     32 * Not all HitTestingTreeNode instances will have an APZC associated with them;
     33 * only HitTestingTreeNodes that correspond to layers with scrollable metrics
     34 * have APZCs.
     35 * Multiple HitTestingTreeNode instances may share the same underlying APZC
     36 * instance if the layers they represent share the same scrollable metrics (i.e.
     37 * are part of the same animated geometry root). If this happens, exactly one of
     38 * the HitTestingTreeNode instances will be designated as the "primary holder"
     39 * of the APZC. When this primary holder is destroyed, it will destroy the APZC
     40 * along with it; in contrast, destroying non-primary-holder nodes will not
     41 * destroy the APZC.
     42 * Code should not make assumptions about which of the nodes will be the
     43 * primary holder, only that that there will be exactly one for each APZC in
     44 * the tree.
     45 *
     46 * The reason this tree exists at all is so that we can do hit-testing on the
     47 * thread that we receive input on (referred to the as the controller thread in
     48 * APZ terminology), which may be different from the compositor thread.
     49 * Accessing the compositor layer tree can only be done on the compositor
     50 * thread, and so it is simpler to make a copy of the hit-testing related
     51 * properties into a separate tree.
     52 *
     53 * The tree pointers on the node (mLastChild, etc.) can only be manipulated
     54 * while holding the APZ tree lock. Any code that wishes to use a
     55 * HitTestingTreeNode outside of holding the tree lock should do so by using
     56 * the HitTestingTreeNodeAutoLock wrapper, which prevents the node from
     57 * being recycled (and also holds a RefPtr to the node to prevent it from
     58 * getting freed).
     59 */
     60 class HitTestingTreeNode {
     61  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(HitTestingTreeNode);
     62 
     63 private:
     64  ~HitTestingTreeNode();
     65 
     66 public:
     67  HitTestingTreeNode(AsyncPanZoomController* aApzc, bool aIsPrimaryHolder,
     68                     LayersId aLayersId);
     69  void RecycleWith(const RecursiveMutexAutoLock& aProofOfTreeLock,
     70                   AsyncPanZoomController* aApzc, LayersId aLayersId);
     71  // Clears the tree pointers on the node, thereby breaking RefPtr cycles. This
     72  // can trigger free'ing of this and other HitTestingTreeNode instances.
     73  void Destroy();
     74 
     75  // Returns true if and only if the node is available for recycling as part
     76  // of a hit-testing tree update. Note that this node can have Destroy() called
     77  // on it whether or not it is recyclable.
     78  bool IsRecyclable(const RecursiveMutexAutoLock& aProofOfTreeLock);
     79 
     80  /* Tree construction methods */
     81 
     82  void SetLastChild(HitTestingTreeNode* aChild);
     83  void SetPrevSibling(HitTestingTreeNode* aSibling);
     84  void MakeRoot();
     85 
     86  /* Tree walking methods. GetFirstChild is O(n) in the number of children. The
     87   * other tree walking methods are all O(1). */
     88 
     89  HitTestingTreeNode* GetFirstChild() const;
     90  HitTestingTreeNode* GetLastChild() const;
     91  HitTestingTreeNode* GetPrevSibling() const;
     92  HitTestingTreeNode* GetParent() const;
     93 
     94  bool IsAncestorOf(const HitTestingTreeNode* aOther) const;
     95 
     96  /* APZC related methods */
     97 
     98  AsyncPanZoomController* GetApzc() const;
     99  AsyncPanZoomController* GetNearestContainingApzc() const;
    100  bool IsPrimaryHolder() const;
    101  LayersId GetLayersId() const;
    102 
    103  /* Hit test related methods */
    104 
    105  void SetHitTestData(
    106      const LayerIntRect& aVisibleRect, const LayerIntSize& aRemoteDocumentSize,
    107      const CSSTransformMatrix& aTransform,
    108      const EventRegionsOverride& aOverride,
    109      const Maybe<ScrollableLayerGuid::ViewID>& aAsyncZoomContainerId);
    110 
    111  /* Scrollbar info */
    112 
    113  void SetScrollbarData(const Maybe<uint64_t>& aScrollbarAnimationId,
    114                        const ScrollbarData& aScrollbarData);
    115  bool MatchesScrollDragMetrics(const AsyncDragMetrics& aDragMetrics,
    116                                LayersId aLayersId) const;
    117  bool IsScrollbarNode() const;  // Scroll thumb or scrollbar container layer.
    118  bool IsScrollbarContainerNode() const;  // Scrollbar container layer.
    119  // This can only be called if IsScrollbarNode() is true
    120  ScrollDirection GetScrollbarDirection() const;
    121  bool IsScrollThumbNode() const;  // Scroll thumb container layer.
    122  ScrollableLayerGuid::ViewID GetScrollTargetId() const;
    123  const ScrollbarData& GetScrollbarData() const;
    124  Maybe<uint64_t> GetScrollbarAnimationId() const;
    125 
    126  /* Fixed pos info */
    127 
    128  void SetFixedPosData(ScrollableLayerGuid::ViewID aFixedPosTarget,
    129                       SideBits aFixedPosSides,
    130                       const Maybe<uint64_t>& aFixedPositionAnimationId);
    131  ScrollableLayerGuid::ViewID GetFixedPosTarget() const;
    132  SideBits GetFixedPosSides() const;
    133  Maybe<uint64_t> GetFixedPositionAnimationId() const;
    134 
    135  /* Sticky pos info */
    136  void SetStickyPosData(ScrollableLayerGuid::ViewID aStickyPosTarget,
    137                        const LayerRectAbsolute& aScrollRangeOuter,
    138                        const LayerRectAbsolute& aScrollRangeInner,
    139                        const Maybe<uint64_t>& aStickyPositionAnimationId);
    140  ScrollableLayerGuid::ViewID GetStickyPosTarget() const;
    141  const LayerRectAbsolute& GetStickyScrollRangeOuter() const;
    142  const LayerRectAbsolute& GetStickyScrollRangeInner() const;
    143  Maybe<uint64_t> GetStickyPositionAnimationId() const;
    144 
    145  /* Returns the mOverride flag. */
    146  EventRegionsOverride GetEventRegionsOverride() const;
    147  const CSSTransformMatrix& GetTransform() const;
    148  /* This is similar to APZCTreeManager::GetApzcToGeckoTransform but without
    149   * the async bits. It's used on the main-thread for transforming coordinates
    150   * across a BrowserParent/BrowserChild interface.
    151   * |aRemoteLayersId| is the LayersId of the remote subtree for which this
    152   * transform will be used. */
    153  LayerToScreenMatrix4x4 GetTransformToGecko(LayersId aRemoteLayersId) const;
    154  const LayerIntRect& GetVisibleRect() const;
    155 
    156  /* Returns the screen coordinate rectangle of remote iframe corresponding to
    157   * this node. The rectangle is the result of clipped by ancestor async
    158   * scrolling. */
    159  ScreenRect GetRemoteDocumentScreenRect(
    160      LayersId aRemoteDocumentLayersId) const;
    161 
    162  Maybe<ScrollableLayerGuid::ViewID> GetAsyncZoomContainerId() const;
    163 
    164  /* Debug helpers */
    165  void Dump(const char* aPrefix = "") const;
    166 
    167 private:
    168  friend class HitTestingTreeNodeAutoLock;
    169  // Functions that are private but called from HitTestingTreeNodeAutoLock
    170  void Lock(const RecursiveMutexAutoLock& aProofOfTreeLock);
    171  void Unlock(const RecursiveMutexAutoLock& aProofOfTreeLock);
    172 
    173  void SetApzcParent(AsyncPanZoomController* aApzc);
    174 
    175  RefPtr<HitTestingTreeNode> mLastChild;
    176  RefPtr<HitTestingTreeNode> mPrevSibling;
    177  RefPtr<HitTestingTreeNode> mParent;
    178 
    179  RefPtr<AsyncPanZoomController> mApzc;
    180  bool mIsPrimaryApzcHolder;
    181  int mLockCount;
    182 
    183  LayersId mLayersId;
    184 
    185  // This is only set for HTTNs where IsScrollThumbNode() returns true. It holds
    186  // the animation id that we use to move the thumb node to reflect async
    187  // scrolling.
    188  Maybe<uint64_t> mScrollbarAnimationId;
    189 
    190  // This is set for scrollbar Container and Thumb layers.
    191  ScrollbarData mScrollbarData;
    192 
    193  // This holds the animation id that we use to adjust fixed position content
    194  // for the toolbar.
    195  Maybe<uint64_t> mFixedPositionAnimationId;
    196 
    197  ScrollableLayerGuid::ViewID mFixedPosTarget;
    198  SideBits mFixedPosSides;
    199 
    200  ScrollableLayerGuid::ViewID mStickyPosTarget;
    201  LayerRectAbsolute mStickyScrollRangeOuter;
    202  LayerRectAbsolute mStickyScrollRangeInner;
    203  // This holds the animation id that we use to adjust sticky position content
    204  // for the toolbar.
    205  Maybe<uint64_t> mStickyPositionAnimationId;
    206 
    207  LayerIntRect mVisibleRect;
    208 
    209  /* The size of remote iframe on the corresponding layer coordinate.
    210   * It's empty if this node is not for remote iframe. */
    211  LayerIntSize mRemoteDocumentSize;
    212 
    213  /* This is the transform from layer L. This does NOT include any async
    214   * transforms. */
    215  CSSTransformMatrix mTransform;
    216 
    217  /* If the layer is the async zoom container layer then this will hold the id.
    218   */
    219  Maybe<ScrollableLayerGuid::ViewID> mAsyncZoomContainerId;
    220 
    221  /* Indicates whether or not the event regions on this node need to be
    222   * overridden in a certain way. */
    223  EventRegionsOverride mOverride;
    224 };
    225 
    226 /**
    227 * A class that allows safe usage of a HitTestingTreeNode outside of the APZ
    228 * tree lock. In general, this class should be Initialize()'d inside the tree
    229 * lock (enforced by the proof-of-lock to Initialize), and then can be returned
    230 * to a scope outside the tree lock and used safely. Upon destruction or
    231 * Clear() being called, it unlocks the underlying node at which point it can
    232 * be recycled or freed.
    233 */
    234 class HitTestingTreeNodeAutoLock final {
    235 public:
    236  HitTestingTreeNodeAutoLock();
    237  ~HitTestingTreeNodeAutoLock();
    238  // Make it move-only. Note that the default implementations of the move
    239  // constructor and assignment operator are correct: they'll call the
    240  // move constructor of mNode, which will null out mNode on the moved-from
    241  // object, and Clear() will early-exit when the moved-from object's
    242  // destructor is called.
    243  HitTestingTreeNodeAutoLock(HitTestingTreeNodeAutoLock&&) = default;
    244  HitTestingTreeNodeAutoLock& operator=(HitTestingTreeNodeAutoLock&&) = default;
    245 
    246  void Initialize(const RecursiveMutexAutoLock& aProofOfTreeLock,
    247                  already_AddRefed<HitTestingTreeNode> aNode,
    248                  RecursiveMutex& aTreeMutex);
    249  void Clear();
    250 
    251  // Convenience operators to simplify the using code.
    252  explicit operator bool() const { return !!mNode; }
    253  bool operator!() const { return !mNode; }
    254  HitTestingTreeNode* operator->() const { return mNode.get(); }
    255 
    256  // Allow getting back a raw pointer to the node, but only inside the scope
    257  // of the tree lock. The caller is responsible for ensuring that they do not
    258  // use the raw pointer outside that scope.
    259  HitTestingTreeNode* Get(
    260      mozilla::RecursiveMutexAutoLock& aProofOfTreeLock) const {
    261    return mNode.get();
    262  }
    263 
    264 private:
    265  RefPtr<HitTestingTreeNode> mNode;
    266  RecursiveMutex* mTreeMutex;
    267 };
    268 
    269 }  // namespace layers
    270 }  // namespace mozilla
    271 
    272 #endif  // mozilla_layers_HitTestingTreeNode_h