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