Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set sw=2 ts=8 et 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 : #include "HitTestingTreeNode.h"
8 :
9 : #include "AsyncPanZoomController.h" // for AsyncPanZoomController
10 : #include "gfxPrefs.h"
11 : #include "LayersLogging.h" // for Stringify
12 : #include "mozilla/gfx/Point.h" // for Point4D
13 : #include "mozilla/layers/APZThreadUtils.h" // for AssertOnCompositorThread
14 : #include "mozilla/layers/APZUtils.h" // for CompleteAsyncTransform
15 : #include "mozilla/layers/AsyncCompositionManager.h" // for ViewTransform::operator Matrix4x4()
16 : #include "mozilla/layers/AsyncDragMetrics.h" // for AsyncDragMetrics
17 : #include "nsPrintfCString.h" // for nsPrintfCString
18 : #include "UnitTransforms.h" // for ViewAs
19 :
20 : namespace mozilla {
21 : namespace layers {
22 :
23 13 : HitTestingTreeNode::HitTestingTreeNode(AsyncPanZoomController* aApzc,
24 : bool aIsPrimaryHolder,
25 13 : uint64_t aLayersId)
26 : : mApzc(aApzc)
27 : , mIsPrimaryApzcHolder(aIsPrimaryHolder)
28 : , mLayersId(aLayersId)
29 : , mScrollViewId(FrameMetrics::NULL_SCROLL_ID)
30 : , mScrollbarAnimationId(0)
31 : , mIsScrollbarContainer(false)
32 : , mFixedPosTarget(FrameMetrics::NULL_SCROLL_ID)
33 13 : , mOverride(EventRegionsOverride::NoOverride)
34 : {
35 13 : if (mIsPrimaryApzcHolder) {
36 2 : MOZ_ASSERT(mApzc);
37 : }
38 13 : MOZ_ASSERT(!mApzc || mApzc->GetLayersId() == mLayersId);
39 13 : }
40 :
41 : void
42 166 : HitTestingTreeNode::RecycleWith(AsyncPanZoomController* aApzc,
43 : uint64_t aLayersId)
44 : {
45 166 : MOZ_ASSERT(!mIsPrimaryApzcHolder);
46 166 : Destroy(); // clear out tree pointers
47 166 : mApzc = aApzc;
48 166 : mLayersId = aLayersId;
49 166 : MOZ_ASSERT(!mApzc || mApzc->GetLayersId() == mLayersId);
50 : // The caller is expected to call SetHitTestData to repopulate the hit-test
51 : // fields.
52 166 : }
53 :
54 6 : HitTestingTreeNode::~HitTestingTreeNode()
55 : {
56 6 : }
57 :
58 : void
59 172 : HitTestingTreeNode::Destroy()
60 : {
61 172 : APZThreadUtils::AssertOnCompositorThread();
62 :
63 172 : mPrevSibling = nullptr;
64 172 : mLastChild = nullptr;
65 172 : mParent = nullptr;
66 :
67 172 : if (mApzc) {
68 5 : if (mIsPrimaryApzcHolder) {
69 0 : mApzc->Destroy();
70 : }
71 5 : mApzc = nullptr;
72 : }
73 :
74 172 : mLayersId = 0;
75 172 : }
76 :
77 : void
78 122 : HitTestingTreeNode::SetLastChild(HitTestingTreeNode* aChild)
79 : {
80 122 : mLastChild = aChild;
81 122 : if (aChild) {
82 90 : aChild->mParent = this;
83 :
84 90 : if (aChild->GetApzc()) {
85 6 : AsyncPanZoomController* parent = GetNearestContainingApzc();
86 : // We assume that HitTestingTreeNodes with an ancestor/descendant
87 : // relationship cannot both point to the same APZC instance. This
88 : // assertion only covers a subset of cases in which that might occur,
89 : // but it's better than nothing.
90 6 : MOZ_ASSERT(aChild->GetApzc() != parent);
91 6 : aChild->SetApzcParent(parent);
92 : }
93 : }
94 122 : }
95 :
96 : void
97 211 : HitTestingTreeNode::SetScrollbarData(FrameMetrics::ViewID aScrollViewId,
98 : const uint64_t& aScrollbarAnimationId,
99 : const ScrollThumbData& aThumbData,
100 : bool aIsScrollContainer)
101 : {
102 211 : mScrollViewId = aScrollViewId;
103 211 : mScrollbarAnimationId = aScrollbarAnimationId;
104 211 : mScrollThumbData = aThumbData;
105 211 : mIsScrollbarContainer = aIsScrollContainer;
106 211 : }
107 :
108 : bool
109 0 : HitTestingTreeNode::MatchesScrollDragMetrics(const AsyncDragMetrics& aDragMetrics) const
110 : {
111 0 : return IsScrollThumbNode() &&
112 0 : mScrollThumbData.mDirection == aDragMetrics.mDirection &&
113 0 : mScrollViewId == aDragMetrics.mViewId;
114 : }
115 :
116 : bool
117 25 : HitTestingTreeNode::IsScrollThumbNode() const
118 : {
119 25 : return mScrollThumbData.mDirection != ScrollDirection::NONE;
120 : }
121 :
122 : bool
123 10 : HitTestingTreeNode::IsScrollbarNode() const
124 : {
125 10 : return mIsScrollbarContainer || IsScrollThumbNode();
126 : }
127 :
128 : FrameMetrics::ViewID
129 0 : HitTestingTreeNode::GetScrollTargetId() const
130 : {
131 0 : return mScrollViewId;
132 : }
133 :
134 : const uint64_t&
135 0 : HitTestingTreeNode::GetScrollbarAnimationId() const
136 : {
137 0 : return mScrollbarAnimationId;
138 : }
139 :
140 : const ScrollThumbData&
141 0 : HitTestingTreeNode::GetScrollThumbData() const
142 : {
143 0 : return mScrollThumbData;
144 : }
145 :
146 : void
147 211 : HitTestingTreeNode::SetFixedPosData(FrameMetrics::ViewID aFixedPosTarget)
148 : {
149 211 : mFixedPosTarget = aFixedPosTarget;
150 211 : }
151 :
152 : FrameMetrics::ViewID
153 5 : HitTestingTreeNode::GetFixedPosTarget() const
154 : {
155 5 : return mFixedPosTarget;
156 : }
157 :
158 : void
159 125 : HitTestingTreeNode::SetPrevSibling(HitTestingTreeNode* aSibling)
160 : {
161 125 : mPrevSibling = aSibling;
162 125 : if (aSibling) {
163 93 : aSibling->mParent = mParent;
164 :
165 93 : if (aSibling->GetApzc()) {
166 5 : AsyncPanZoomController* parent = mParent ? mParent->GetNearestContainingApzc() : nullptr;
167 5 : aSibling->SetApzcParent(parent);
168 : }
169 : }
170 125 : }
171 :
172 : void
173 28 : HitTestingTreeNode::MakeRoot()
174 : {
175 28 : mParent = nullptr;
176 :
177 28 : if (GetApzc()) {
178 28 : SetApzcParent(nullptr);
179 : }
180 28 : }
181 :
182 : HitTestingTreeNode*
183 211 : HitTestingTreeNode::GetFirstChild() const
184 : {
185 211 : HitTestingTreeNode* child = GetLastChild();
186 211 : while (child && child->GetPrevSibling()) {
187 0 : child = child->GetPrevSibling();
188 : }
189 211 : return child;
190 : }
191 :
192 : HitTestingTreeNode*
193 444 : HitTestingTreeNode::GetLastChild() const
194 : {
195 444 : return mLastChild;
196 : }
197 :
198 : HitTestingTreeNode*
199 223 : HitTestingTreeNode::GetPrevSibling() const
200 : {
201 223 : return mPrevSibling;
202 : }
203 :
204 : HitTestingTreeNode*
205 248 : HitTestingTreeNode::GetParent() const
206 : {
207 248 : return mParent;
208 : }
209 :
210 : bool
211 0 : HitTestingTreeNode::IsAncestorOf(const HitTestingTreeNode* aOther) const
212 : {
213 0 : for (const HitTestingTreeNode* cur = aOther; cur; cur = cur->GetParent()) {
214 0 : if (cur == this) {
215 0 : return true;
216 : }
217 : }
218 0 : return false;
219 : }
220 :
221 : AsyncPanZoomController*
222 791 : HitTestingTreeNode::GetApzc() const
223 : {
224 791 : return mApzc;
225 : }
226 :
227 : AsyncPanZoomController*
228 11 : HitTestingTreeNode::GetNearestContainingApzc() const
229 : {
230 33 : for (const HitTestingTreeNode* n = this; n; n = n->GetParent()) {
231 33 : if (n->GetApzc()) {
232 11 : return n->GetApzc();
233 : }
234 : }
235 0 : return nullptr;
236 : }
237 :
238 : bool
239 277 : HitTestingTreeNode::IsPrimaryHolder() const
240 : {
241 277 : return mIsPrimaryApzcHolder;
242 : }
243 :
244 : uint64_t
245 231 : HitTestingTreeNode::GetLayersId() const
246 : {
247 231 : return mLayersId;
248 : }
249 :
250 : void
251 211 : HitTestingTreeNode::SetHitTestData(const EventRegions& aRegions,
252 : const LayerIntRegion& aVisibleRegion,
253 : const CSSTransformMatrix& aTransform,
254 : const Maybe<ParentLayerIntRegion>& aClipRegion,
255 : const EventRegionsOverride& aOverride)
256 : {
257 211 : mEventRegions = aRegions;
258 211 : mVisibleRegion = aVisibleRegion;
259 211 : mTransform = aTransform;
260 211 : mClipRegion = aClipRegion;
261 211 : mOverride = aOverride;
262 211 : }
263 :
264 : bool
265 21 : HitTestingTreeNode::IsOutsideClip(const ParentLayerPoint& aPoint) const
266 : {
267 : // test against clip rect in ParentLayer coordinate space
268 21 : return (mClipRegion.isSome() && !mClipRegion->Contains(aPoint.x, aPoint.y));
269 : }
270 :
271 : Maybe<LayerPoint>
272 20 : HitTestingTreeNode::Untransform(const ParentLayerPoint& aPoint,
273 : const LayerToParentLayerMatrix4x4& aTransform) const
274 : {
275 40 : Maybe<ParentLayerToLayerMatrix4x4> inverse = aTransform.MaybeInverse();
276 20 : if (inverse) {
277 20 : return UntransformBy(inverse.ref(), aPoint);
278 : }
279 0 : return Nothing();
280 : }
281 :
282 : HitTestResult
283 15 : HitTestingTreeNode::HitTest(const LayerPoint& aPoint) const
284 : {
285 15 : if (mOverride & EventRegionsOverride::ForceEmptyHitRegion) {
286 0 : return HitTestResult::HitNothing;
287 : }
288 :
289 15 : auto point = LayerIntPoint::Round(aPoint);
290 :
291 : // test against event regions in Layer coordinate space
292 15 : if (!mEventRegions.mHitRegion.Contains(point.x, point.y)) {
293 10 : return HitTestResult::HitNothing;
294 : }
295 10 : if ((mOverride & EventRegionsOverride::ForceDispatchToContent) ||
296 5 : mEventRegions.mDispatchToContentHitRegion.Contains(point.x, point.y))
297 : {
298 0 : return HitTestResult::HitDispatchToContentRegion;
299 : }
300 5 : if (gfxPrefs::TouchActionEnabled()) {
301 5 : if (mEventRegions.mNoActionRegion.Contains(point.x, point.y)) {
302 0 : return HitTestResult::HitLayerTouchActionNone;
303 : }
304 5 : bool panX = mEventRegions.mHorizontalPanRegion.Contains(point.x, point.y);
305 5 : bool panY = mEventRegions.mVerticalPanRegion.Contains(point.x, point.y);
306 5 : if (panX && panY) {
307 0 : return HitTestResult::HitLayerTouchActionPanXY;
308 5 : } else if (panX) {
309 0 : return HitTestResult::HitLayerTouchActionPanX;
310 5 : } else if (panY) {
311 0 : return HitTestResult::HitLayerTouchActionPanY;
312 : }
313 : }
314 5 : return HitTestResult::HitLayer;
315 : }
316 :
317 : EventRegionsOverride
318 183 : HitTestingTreeNode::GetEventRegionsOverride() const
319 : {
320 183 : return mOverride;
321 : }
322 :
323 : const CSSTransformMatrix&
324 20 : HitTestingTreeNode::GetTransform() const
325 : {
326 20 : return mTransform;
327 : }
328 :
329 : const LayerIntRegion&
330 0 : HitTestingTreeNode::GetVisibleRegion() const
331 : {
332 0 : return mVisibleRegion;
333 : }
334 :
335 : void
336 0 : HitTestingTreeNode::Dump(const char* aPrefix) const
337 : {
338 0 : if (mPrevSibling) {
339 0 : mPrevSibling->Dump(aPrefix);
340 : }
341 0 : printf_stderr("%sHitTestingTreeNode (%p) APZC (%p) g=(%s) %s%s%sr=(%s) t=(%s) c=(%s)\n",
342 : aPrefix, this, mApzc.get(),
343 0 : mApzc ? Stringify(mApzc->GetGuid()).c_str() : nsPrintfCString("l=%" PRIu64, mLayersId).get(),
344 0 : (mOverride & EventRegionsOverride::ForceDispatchToContent) ? "fdtc " : "",
345 0 : (mOverride & EventRegionsOverride::ForceEmptyHitRegion) ? "fehr " : "",
346 0 : (mFixedPosTarget != FrameMetrics::NULL_SCROLL_ID) ? nsPrintfCString("fixed=%" PRIu64 " ", mFixedPosTarget).get() : "",
347 0 : Stringify(mEventRegions).c_str(), Stringify(mTransform).c_str(),
348 0 : mClipRegion ? Stringify(mClipRegion.ref()).c_str() : "none");
349 0 : if (mLastChild) {
350 0 : mLastChild->Dump(nsPrintfCString("%s ", aPrefix).get());
351 : }
352 0 : }
353 :
354 : void
355 39 : HitTestingTreeNode::SetApzcParent(AsyncPanZoomController* aParent)
356 : {
357 : // precondition: GetApzc() is non-null
358 39 : MOZ_ASSERT(GetApzc() != nullptr);
359 39 : if (IsPrimaryHolder()) {
360 34 : GetApzc()->SetParent(aParent);
361 : } else {
362 5 : MOZ_ASSERT(GetApzc()->GetParent() == aParent);
363 : }
364 39 : }
365 :
366 : } // namespace layers
367 : } // namespace mozilla
|