Source code

Revision control

Other Tools

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 "Layers.h"
11
#include "mozilla/gfx/CompositorHitTestInfo.h"
12
#include "mozilla/gfx/Matrix.h" // for Matrix4x4
13
#include "mozilla/layers/LayersTypes.h" // for EventRegions
14
#include "mozilla/layers/ScrollableLayerGuid.h" // for ScrollableLayerGuid
15
#include "mozilla/Maybe.h" // for Maybe
16
#include "mozilla/RefPtr.h" // for nsRefPtr
17
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
* LayerMetrics tree (see documentation in LayerMetricsWrapper.h).
30
*
31
* Not all HitTestingTreeNode instances will have an APZC associated with them;
32
* only HitTestingTreeNodes that correspond to layers with scrollable metrics
33
* have APZCs.
34
* Multiple HitTestingTreeNode instances may share the same underlying APZC
35
* instance if the layers they represent share the same scrollable metrics (i.e.
36
* are part of the same animated geometry root). If this happens, exactly one of
37
* the HitTestingTreeNode instances will be designated as the "primary holder"
38
* of the APZC. When this primary holder is destroyed, it will destroy the APZC
39
* along with it; in contrast, destroying non-primary-holder nodes will not
40
* destroy the APZC.
41
* Code should not make assumptions about which of the nodes will be the
42
* primary holder, only that that there will be exactly one for each APZC in
43
* the tree.
44
*
45
* The reason this tree exists at all is so that we can do hit-testing on the
46
* thread that we receive input on (referred to the as the controller thread in
47
* APZ terminology), which may be different from the compositor thread.
48
* Accessing the compositor layer tree can only be done on the compositor
49
* thread, and so it is simpler to make a copy of the hit-testing related
50
* properties into a separate tree.
51
*
52
* The tree pointers on the node (mLastChild, etc.) can only be manipulated
53
* while holding the APZ tree lock. Any code that wishes to use a
54
* HitTestingTreeNode outside of holding the tree lock should do so by using
55
* the HitTestingTreeNodeAutoLock wrapper, which prevents the node from
56
* being recycled (and also holds a RefPtr to the node to prevent it from
57
* getting freed).
58
*/
59
class HitTestingTreeNode {
60
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(HitTestingTreeNode);
61
62
private:
63
~HitTestingTreeNode();
64
65
public:
66
HitTestingTreeNode(AsyncPanZoomController* aApzc, bool aIsPrimaryHolder,
67
LayersId aLayersId);
68
void RecycleWith(const RecursiveMutexAutoLock& aProofOfTreeLock,
69
AsyncPanZoomController* aApzc, LayersId aLayersId);
70
// Clears the tree pointers on the node, thereby breaking RefPtr cycles. This
71
// can trigger free'ing of this and other HitTestingTreeNode instances.
72
void Destroy();
73
74
// Returns true if and only if the node is available for recycling as part
75
// of a hit-testing tree update. Note that this node can have Destroy() called
76
// on it whether or not it is recyclable.
77
bool IsRecyclable(const RecursiveMutexAutoLock& aProofOfTreeLock);
78
79
/* Tree construction methods */
80
81
void SetLastChild(HitTestingTreeNode* aChild);
82
void SetPrevSibling(HitTestingTreeNode* aSibling);
83
void MakeRoot();
84
85
/* Tree walking methods. GetFirstChild is O(n) in the number of children. The
86
* other tree walking methods are all O(1). */
87
88
HitTestingTreeNode* GetFirstChild() const;
89
HitTestingTreeNode* GetLastChild() const;
90
HitTestingTreeNode* GetPrevSibling() const;
91
HitTestingTreeNode* GetParent() const;
92
93
bool IsAncestorOf(const HitTestingTreeNode* aOther) const;
94
95
/* APZC related methods */
96
97
AsyncPanZoomController* GetApzc() const;
98
AsyncPanZoomController* GetNearestContainingApzc() const;
99
bool IsPrimaryHolder() const;
100
LayersId GetLayersId() const;
101
102
/* Hit test related methods */
103
104
void SetHitTestData(const EventRegions& aRegions,
105
const LayerIntRegion& aVisibleRegion,
106
const LayerIntSize& aRemoteDocumentSize,
107
const CSSTransformMatrix& aTransform,
108
const Maybe<ParentLayerIntRegion>& aClipRegion,
109
const EventRegionsOverride& aOverride,
110
bool aIsBackfaceHidden, bool aIsAsyncZoomContainer);
111
bool IsOutsideClip(const ParentLayerPoint& aPoint) const;
112
113
/* Scrollbar info */
114
115
void SetScrollbarData(const Maybe<uint64_t>& aScrollbarAnimationId,
116
const ScrollbarData& aScrollbarData);
117
bool MatchesScrollDragMetrics(const AsyncDragMetrics& aDragMetrics) const;
118
bool IsScrollbarNode() const; // Scroll thumb or scrollbar container layer.
119
bool IsScrollbarContainerNode() const; // Scrollbar container layer.
120
// This can only be called if IsScrollbarNode() is true
121
ScrollDirection GetScrollbarDirection() const;
122
bool IsScrollThumbNode() const; // Scroll thumb container layer.
123
ScrollableLayerGuid::ViewID GetScrollTargetId() const;
124
const ScrollbarData& GetScrollbarData() const;
125
Maybe<uint64_t> GetScrollbarAnimationId() const;
126
127
/* Fixed pos info */
128
129
void SetFixedPosData(ScrollableLayerGuid::ViewID aFixedPosTarget,
130
SideBits aFixedPosSides,
131
const Maybe<uint64_t>& aFixedPositionAnimationId);
132
ScrollableLayerGuid::ViewID GetFixedPosTarget() const;
133
SideBits GetFixedPosSides() const;
134
Maybe<uint64_t> GetFixedPositionAnimationId() const;
135
136
/* Sticky pos info */
137
void SetStickyPosData(ScrollableLayerGuid::ViewID aStickyPosTarget,
138
const LayerRectAbsolute& aScrollRangeOuter,
139
const LayerRectAbsolute& aScrollRangeInner);
140
ScrollableLayerGuid::ViewID GetStickyPosTarget() const;
141
const LayerRectAbsolute& GetStickyScrollRangeOuter() const;
142
const LayerRectAbsolute& GetStickyScrollRangeInner() const;
143
144
/* Convert |aPoint| into the LayerPixel space for the layer corresponding to
145
* this node. |aTransform| is the complete (content + async) transform for
146
* this node. */
147
Maybe<LayerPoint> Untransform(
148
const ParentLayerPoint& aPoint,
149
const LayerToParentLayerMatrix4x4& aTransform) const;
150
/* Assuming aPoint is inside the clip region for this node, check which of the
151
* event region spaces it falls inside. */
152
gfx::CompositorHitTestInfo HitTest(const LayerPoint& aPoint) const;
153
/* Returns the mOverride flag. */
154
EventRegionsOverride GetEventRegionsOverride() const;
155
const CSSTransformMatrix& GetTransform() const;
156
/* This is similar to APZCTreeManager::GetApzcToGeckoTransform but without
157
* the async bits. It's used on the main-thread for transforming coordinates
158
* across a BrowserParent/BrowserChild interface.*/
159
LayerToScreenMatrix4x4 GetTransformToGecko() const;
160
const LayerIntRegion& GetVisibleRegion() const;
161
162
/* Returns the screen coordinate rectangle of remote iframe corresponding to
163
* this node. The rectangle is the result of clipped by ancestor async
164
* scrolling. */
165
ScreenRect GetRemoteDocumentScreenRect() const;
166
167
bool IsAsyncZoomContainer() const;
168
169
/* Debug helpers */
170
void Dump(const char* aPrefix = "") const;
171
172
private:
173
friend class HitTestingTreeNodeAutoLock;
174
// Functions that are private but called from HitTestingTreeNodeAutoLock
175
void Lock(const RecursiveMutexAutoLock& aProofOfTreeLock);
176
void Unlock(const RecursiveMutexAutoLock& aProofOfTreeLock);
177
178
void SetApzcParent(AsyncPanZoomController* aApzc);
179
180
RefPtr<HitTestingTreeNode> mLastChild;
181
RefPtr<HitTestingTreeNode> mPrevSibling;
182
RefPtr<HitTestingTreeNode> mParent;
183
184
RefPtr<AsyncPanZoomController> mApzc;
185
bool mIsPrimaryApzcHolder;
186
int mLockCount;
187
188
LayersId mLayersId;
189
190
// This is only set if WebRender is enabled, and only for HTTNs
191
// where IsScrollThumbNode() returns true. It holds the animation id that we
192
// use to move the thumb node to reflect async scrolling.
193
Maybe<uint64_t> mScrollbarAnimationId;
194
195
// This is set for scrollbar Container and Thumb layers.
196
ScrollbarData mScrollbarData;
197
198
// This is only set if WebRender is enabled. It holds the animation id that
199
// we use to adjust fixed position content for the toolbar.
200
Maybe<uint64_t> mFixedPositionAnimationId;
201
202
ScrollableLayerGuid::ViewID mFixedPosTarget;
203
SideBits mFixedPosSides;
204
205
ScrollableLayerGuid::ViewID mStickyPosTarget;
206
LayerRectAbsolute mStickyScrollRangeOuter;
207
LayerRectAbsolute mStickyScrollRangeInner;
208
209
/* Let {L,M} be the {layer, scrollable metrics} pair that this node
210
* corresponds to in the layer tree. mEventRegions contains the event regions
211
* from L, in the case where event-regions are enabled. If event-regions are
212
* disabled, it will contain the visible region of L, which we use as an
213
* approximation to the hit region for the purposes of obscuring other layers.
214
* This value is in L's LayerPixels.
215
*/
216
EventRegions mEventRegions;
217
218
LayerIntRegion mVisibleRegion;
219
220
/* The size of remote iframe on the corresponding layer coordinate.
221
* It's empty if this node is not for remote iframe. */
222
LayerIntSize mRemoteDocumentSize;
223
224
/* This is the transform from layer L. This does NOT include any async
225
* transforms. */
226
CSSTransformMatrix mTransform;
227
228
/* Whether layer L is backface-visibility:hidden, and its backface is
229
* currently visible. It's true that the latter depends on the layer's
230
* shadow transform, but the sorts of changes APZ makes to the shadow
231
* transform shouldn't change the backface from hidden to visible or
232
* vice versa, so it's sufficient to record this at hit test tree
233
* building time. */
234
bool mIsBackfaceHidden;
235
236
/* Whether layer L is the async zoom container layer. */
237
bool mIsAsyncZoomContainer;
238
239
/* This is clip rect for L that we wish to use for hit-testing purposes. Note
240
* that this may not be exactly the same as the clip rect on layer L because
241
* of the touch-sensitive region provided by the GeckoContentController, or
242
* because we may use the composition bounds of the layer if the clip is not
243
* present. This value is in L's ParentLayerPixels. */
244
Maybe<ParentLayerIntRegion> mClipRegion;
245
246
/* Indicates whether or not the event regions on this node need to be
247
* overridden in a certain way. */
248
EventRegionsOverride mOverride;
249
};
250
251
/**
252
* A class that allows safe usage of a HitTestingTreeNode outside of the APZ
253
* tree lock. In general, this class should be Initialize()'d inside the tree
254
* lock (enforced by the proof-of-lock to Initialize), and then can be returned
255
* to a scope outside the tree lock and used safely. Upon destruction or
256
* Clear() being called, it unlocks the underlying node at which point it can
257
* be recycled or freed.
258
*/
259
class HitTestingTreeNodeAutoLock final {
260
public:
261
HitTestingTreeNodeAutoLock();
262
~HitTestingTreeNodeAutoLock();
263
// Make it move-only. Note that the default implementations of the move
264
// constructor and assignment operator are correct: they'll call the
265
// move constructor of mNode, which will null out mNode on the moved-from
266
// object, and Clear() will early-exit when the moved-from object's
267
// destructor is called.
268
HitTestingTreeNodeAutoLock(HitTestingTreeNodeAutoLock&&) = default;
269
HitTestingTreeNodeAutoLock& operator=(HitTestingTreeNodeAutoLock&&) = default;
270
271
void Initialize(const RecursiveMutexAutoLock& aProofOfTreeLock,
272
already_AddRefed<HitTestingTreeNode> aNode,
273
RecursiveMutex& aTreeMutex);
274
void Clear();
275
276
// Convenience operators to simplify the using code.
277
explicit operator bool() const { return !!mNode; }
278
bool operator!() const { return !mNode; }
279
HitTestingTreeNode* operator->() const { return mNode.get(); }
280
281
// Allow getting back a raw pointer to the node, but only inside the scope
282
// of the tree lock. The caller is responsible for ensuring that they do not
283
// use the raw pointer outside that scope.
284
HitTestingTreeNode* Get(
285
mozilla::RecursiveMutexAutoLock& aProofOfTreeLock) const {
286
return mNode.get();
287
}
288
289
private:
290
RefPtr<HitTestingTreeNode> mNode;
291
RecursiveMutex* mTreeMutex;
292
};
293
294
} // namespace layers
295
} // namespace mozilla
296
297
#endif // mozilla_layers_HitTestingTreeNode_h