1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=8 et tw=80 : */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_layers_HitTestingTreeNode_h
#define mozilla_layers_HitTestingTreeNode_h
#include "APZUtils.h" // for HitTestResult
#include "FrameMetrics.h" // for ScrollableLayerGuid
#include "Layers.h"
#include "mozilla/gfx/Matrix.h" // for Matrix4x4
#include "mozilla/layers/LayersTypes.h" // for EventRegions
#include "mozilla/Maybe.h" // for Maybe
#include "mozilla/RefPtr.h" // for nsRefPtr
namespace mozilla {
namespace layers {
class AsyncDragMetrics;
class AsyncPanZoomController;
/**
* This class represents a node in a tree that is used by the APZCTreeManager
* to do hit testing. The tree is roughly a copy of the layer tree, but will
* contain multiple nodes in cases where the layer has multiple FrameMetrics.
* In other words, the structure of this tree should be identical to the
* LayerMetrics tree (see documentation in LayerMetricsWrapper.h).
*
* Not all HitTestingTreeNode instances will have an APZC associated with them;
* only HitTestingTreeNodes that correspond to layers with scrollable metrics
* have APZCs.
* Multiple HitTestingTreeNode instances may share the same underlying APZC
* instance if the layers they represent share the same scrollable metrics (i.e.
* are part of the same animated geometry root). If this happens, exactly one of
* the HitTestingTreeNode instances will be designated as the "primary holder"
* of the APZC. When this primary holder is destroyed, it will destroy the APZC
* along with it; in contrast, destroying non-primary-holder nodes will not
* destroy the APZC.
* Code should not make assumptions about which of the nodes will be the
* primary holder, only that that there will be exactly one for each APZC in
* the tree.
*
* The reason this tree exists at all is so that we can do hit-testing on the
* thread that we receive input on (referred to the as the controller thread in
* APZ terminology), which may be different from the compositor thread.
* Accessing the compositor layer tree can only be done on the compositor
* thread, and so it is simpler to make a copy of the hit-testing related
* properties into a separate tree.
*/
class HitTestingTreeNode {
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(HitTestingTreeNode);
private:
~HitTestingTreeNode();
public:
HitTestingTreeNode(AsyncPanZoomController* aApzc, bool aIsPrimaryHolder,
uint64_t aLayersId);
void RecycleWith(AsyncPanZoomController* aApzc, uint64_t aLayersId);
void Destroy();
/* Tree construction methods */
void SetLastChild(HitTestingTreeNode* aChild);
void SetPrevSibling(HitTestingTreeNode* aSibling);
void MakeRoot();
/* Tree walking methods. GetFirstChild is O(n) in the number of children. The
* other tree walking methods are all O(1). */
HitTestingTreeNode* GetFirstChild() const;
HitTestingTreeNode* GetLastChild() const;
HitTestingTreeNode* GetPrevSibling() const;
HitTestingTreeNode* GetParent() const;
/* APZC related methods */
AsyncPanZoomController* GetApzc() const;
AsyncPanZoomController* GetNearestContainingApzc() const;
bool IsPrimaryHolder() const;
uint64_t GetLayersId() const;
/* Hit test related methods */
void SetHitTestData(const EventRegions& aRegions,
const CSSTransformMatrix& aTransform,
const Maybe<ParentLayerIntRegion>& aClipRegion,
const EventRegionsOverride& aOverride);
bool IsOutsideClip(const ParentLayerPoint& aPoint) const;
/* Scrollbar info */
void SetScrollbarData(FrameMetrics::ViewID aScrollViewId,
Layer::ScrollDirection aDir,
int32_t aScrollSize,
bool aIsScrollContainer);
bool MatchesScrollDragMetrics(const AsyncDragMetrics& aDragMetrics) const;
int32_t GetScrollSize() const;
bool IsScrollbarNode() const;
/* Fixed pos info */
void SetFixedPosData(FrameMetrics::ViewID aFixedPosTarget);
FrameMetrics::ViewID GetFixedPosTarget() const;
/* Convert aPoint into the LayerPixel space for the layer corresponding to
* this node. */
Maybe<LayerPoint> Untransform(const ParentLayerPoint& aPoint) const;
/* Assuming aPoint is inside the clip region for this node, check which of the
* event region spaces it falls inside. */
HitTestResult HitTest(const ParentLayerPoint& aPoint) const;
/* Returns the mOverride flag. */
EventRegionsOverride GetEventRegionsOverride() const;
/* Debug helpers */
void Dump(const char* aPrefix = "") const;
private:
void SetApzcParent(AsyncPanZoomController* aApzc);
RefPtr<HitTestingTreeNode> mLastChild;
RefPtr<HitTestingTreeNode> mPrevSibling;
RefPtr<HitTestingTreeNode> mParent;
RefPtr<AsyncPanZoomController> mApzc;
bool mIsPrimaryApzcHolder;
uint64_t mLayersId;
FrameMetrics::ViewID mScrollViewId;
Layer::ScrollDirection mScrollDir;
int32_t mScrollSize;
bool mIsScrollbarContainer;
FrameMetrics::ViewID mFixedPosTarget;
/* Let {L,M} be the {layer, scrollable metrics} pair that this node
* corresponds to in the layer tree. mEventRegions contains the event regions
* from L, in the case where event-regions are enabled. If event-regions are
* disabled, it will contain the visible region of L, which we use as an
* approximation to the hit region for the purposes of obscuring other layers.
* This value is in L's LayerPixels.
*/
EventRegions mEventRegions;
/* This is the transform from layer L. This does NOT include any async
* transforms. */
CSSTransformMatrix mTransform;
/* This is clip rect for L that we wish to use for hit-testing purposes. Note
* that this may not be exactly the same as the clip rect on layer L because
* of the touch-sensitive region provided by the GeckoContentController, or
* because we may use the composition bounds of the layer if the clip is not
* present. This value is in L's ParentLayerPixels. */
Maybe<ParentLayerIntRegion> mClipRegion;
/* Indicates whether or not the event regions on this node need to be
* overridden in a certain way. */
EventRegionsOverride mOverride;
};
} // namespace layers
} // namespace mozilla
#endif // mozilla_layers_HitTestingTreeNode_h
|