Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/gfx/layers/apz/test/gtest/TestEventRegions.cpp
Line
Count
Source (jump to first uncovered line)
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
#include "APZCTreeManagerTester.h"
8
#include "APZTestCommon.h"
9
#include "InputUtils.h"
10
11
class APZEventRegionsTester : public APZCTreeManagerTester {
12
protected:
13
  UniquePtr<ScopedLayerTreeRegistration> registration;
14
  TestAsyncPanZoomController* rootApzc;
15
16
0
  void CreateEventRegionsLayerTree1() {
17
0
    const char* layerTreeSyntax = "c(tt)";
18
0
    nsIntRegion layerVisibleRegions[] = {
19
0
      nsIntRegion(IntRect(0, 0, 200, 200)),     // root
20
0
      nsIntRegion(IntRect(0, 0, 100, 200)),     // left half
21
0
      nsIntRegion(IntRect(0, 100, 200, 100)),   // bottom half
22
0
    };
23
0
    root = CreateLayerTree(layerTreeSyntax, layerVisibleRegions, nullptr, lm, layers);
24
0
    SetScrollableFrameMetrics(root, FrameMetrics::START_SCROLL_ID);
25
0
    SetScrollableFrameMetrics(layers[1], FrameMetrics::START_SCROLL_ID + 1);
26
0
    SetScrollableFrameMetrics(layers[2], FrameMetrics::START_SCROLL_ID + 2);
27
0
    SetScrollHandoff(layers[1], root);
28
0
    SetScrollHandoff(layers[2], root);
29
0
30
0
    // Set up the event regions over a 200x200 area. The root layer has the
31
0
    // whole 200x200 as the hit region; layers[1] has the left half and
32
0
    // layers[2] has the bottom half. The bottom-left 100x100 area is also
33
0
    // in the d-t-c region for both layers[1] and layers[2] (but layers[2] is
34
0
    // on top so it gets the events by default if the main thread doesn't
35
0
    // respond).
36
0
    EventRegions regions(nsIntRegion(IntRect(0, 0, 200, 200)));
37
0
    root->SetEventRegions(regions);
38
0
    regions.mDispatchToContentHitRegion = nsIntRegion(IntRect(0, 100, 100, 100));
39
0
    regions.mHitRegion = nsIntRegion(IntRect(0, 0, 100, 200));
40
0
    layers[1]->SetEventRegions(regions);
41
0
    regions.mHitRegion = nsIntRegion(IntRect(0, 100, 200, 100));
42
0
    layers[2]->SetEventRegions(regions);
43
0
44
0
    registration = MakeUnique<ScopedLayerTreeRegistration>(manager, LayersId{0}, root, mcc);
45
0
    manager->UpdateHitTestingTree(LayersId{0}, root, false, LayersId{0}, 0);
46
0
    rootApzc = ApzcOf(root);
47
0
  }
48
49
0
  void CreateEventRegionsLayerTree2() {
50
0
    const char* layerTreeSyntax = "c(t)";
51
0
    nsIntRegion layerVisibleRegions[] = {
52
0
      nsIntRegion(IntRect(0, 0, 100, 500)),
53
0
      nsIntRegion(IntRect(0, 150, 100, 100)),
54
0
    };
55
0
    root = CreateLayerTree(layerTreeSyntax, layerVisibleRegions, nullptr, lm, layers);
56
0
    SetScrollableFrameMetrics(root, FrameMetrics::START_SCROLL_ID);
57
0
58
0
    // Set up the event regions so that the child thebes layer is positioned far
59
0
    // away from the scrolling container layer.
60
0
    EventRegions regions(nsIntRegion(IntRect(0, 0, 100, 100)));
61
0
    root->SetEventRegions(regions);
62
0
    regions.mHitRegion = nsIntRegion(IntRect(0, 150, 100, 100));
63
0
    layers[1]->SetEventRegions(regions);
64
0
65
0
    registration = MakeUnique<ScopedLayerTreeRegistration>(manager, LayersId{0}, root, mcc);
66
0
    manager->UpdateHitTestingTree(LayersId{0}, root, false, LayersId{0}, 0);
67
0
    rootApzc = ApzcOf(root);
68
0
  }
69
70
0
  void CreateObscuringLayerTree() {
71
0
    const char* layerTreeSyntax = "c(c(t)t)";
72
0
    // LayerID                     0 1 2 3
73
0
    // 0 is the root.
74
0
    // 1 is a parent scrollable layer.
75
0
    // 2 is a child scrollable layer.
76
0
    // 3 is the Obscurer, who ruins everything.
77
0
    nsIntRegion layerVisibleRegions[] = {
78
0
        // x coordinates are uninteresting
79
0
        nsIntRegion(IntRect(0,   0, 200, 200)),  // [0, 200]
80
0
        nsIntRegion(IntRect(0,   0, 200, 200)),  // [0, 200]
81
0
        nsIntRegion(IntRect(0, 100, 200,  50)),  // [100, 150]
82
0
        nsIntRegion(IntRect(0, 100, 200, 100))   // [100, 200]
83
0
    };
84
0
    root = CreateLayerTree(layerTreeSyntax, layerVisibleRegions, nullptr, lm, layers);
85
0
86
0
    SetScrollableFrameMetrics(root, FrameMetrics::START_SCROLL_ID, CSSRect(0, 0, 200, 200));
87
0
    SetScrollableFrameMetrics(layers[1], FrameMetrics::START_SCROLL_ID + 1, CSSRect(0, 0, 200, 300));
88
0
    SetScrollableFrameMetrics(layers[2], FrameMetrics::START_SCROLL_ID + 2, CSSRect(0, 0, 200, 100));
89
0
    SetScrollHandoff(layers[2], layers[1]);
90
0
    SetScrollHandoff(layers[1], root);
91
0
92
0
    EventRegions regions(nsIntRegion(IntRect(0, 0, 200, 200)));
93
0
    root->SetEventRegions(regions);
94
0
    regions.mHitRegion = nsIntRegion(IntRect(0, 0, 200, 300));
95
0
    layers[1]->SetEventRegions(regions);
96
0
    regions.mHitRegion = nsIntRegion(IntRect(0, 100, 200, 100));
97
0
    layers[2]->SetEventRegions(regions);
98
0
99
0
    registration = MakeUnique<ScopedLayerTreeRegistration>(manager, LayersId{0}, root, mcc);
100
0
    manager->UpdateHitTestingTree(LayersId{0}, root, false, LayersId{0}, 0);
101
0
    rootApzc = ApzcOf(root);
102
0
  }
103
104
0
  void CreateBug1119497LayerTree() {
105
0
    const char* layerTreeSyntax = "c(tt)";
106
0
    // LayerID                     0 12
107
0
    // 0 is the root and has an APZC
108
0
    // 1 is behind 2 and has an APZC
109
0
    // 2 entirely covers 1 and should take all the input events, but has no APZC
110
0
    // so hits to 2 should go to to the root APZC
111
0
    nsIntRegion layerVisibleRegions[] = {
112
0
      nsIntRegion(IntRect(0, 0, 100, 100)),
113
0
      nsIntRegion(IntRect(0, 0, 100, 100)),
114
0
      nsIntRegion(IntRect(0, 0, 100, 100)),
115
0
    };
116
0
    root = CreateLayerTree(layerTreeSyntax, layerVisibleRegions, nullptr, lm, layers);
117
0
118
0
    SetScrollableFrameMetrics(root, FrameMetrics::START_SCROLL_ID);
119
0
    SetScrollableFrameMetrics(layers[1], FrameMetrics::START_SCROLL_ID + 1);
120
0
121
0
    registration = MakeUnique<ScopedLayerTreeRegistration>(manager, LayersId{0}, root, mcc);
122
0
    manager->UpdateHitTestingTree(LayersId{0}, root, false, LayersId{0}, 0);
123
0
  }
124
125
0
  void CreateBug1117712LayerTree() {
126
0
    const char* layerTreeSyntax = "c(c(t)t)";
127
0
    // LayerID                     0 1 2 3
128
0
    // 0 is the root
129
0
    // 1 is a container layer whose sole purpose to make a non-empty ancestor
130
0
    //   transform for 2, so that 2's screen-to-apzc and apzc-to-gecko
131
0
    //   transforms are different from 3's.
132
0
    // 2 is a small layer that is the actual target
133
0
    // 3 is a big layer obscuring 2 with a dispatch-to-content region
134
0
    nsIntRegion layerVisibleRegions[] = {
135
0
      nsIntRegion(IntRect(0, 0, 100, 100)),
136
0
      nsIntRegion(IntRect(0, 0, 0, 0)),
137
0
      nsIntRegion(IntRect(0, 0, 10, 10)),
138
0
      nsIntRegion(IntRect(0, 0, 100, 100)),
139
0
    };
140
0
    Matrix4x4 layerTransforms[] = {
141
0
      Matrix4x4(),
142
0
      Matrix4x4::Translation(50, 0, 0),
143
0
      Matrix4x4(),
144
0
      Matrix4x4(),
145
0
    };
146
0
    root = CreateLayerTree(layerTreeSyntax, layerVisibleRegions, layerTransforms, lm, layers);
147
0
148
0
    SetScrollableFrameMetrics(layers[2], FrameMetrics::START_SCROLL_ID, CSSRect(0, 0, 10, 10));
149
0
    SetScrollableFrameMetrics(layers[3], FrameMetrics::START_SCROLL_ID + 1, CSSRect(0, 0, 100, 100));
150
0
    SetScrollHandoff(layers[3], layers[2]);
151
0
152
0
    EventRegions regions(nsIntRegion(IntRect(0, 0, 10, 10)));
153
0
    layers[2]->SetEventRegions(regions);
154
0
    regions.mHitRegion = nsIntRegion(IntRect(0, 0, 100, 100));
155
0
    regions.mDispatchToContentHitRegion = nsIntRegion(IntRect(0, 0, 100, 100));
156
0
    layers[3]->SetEventRegions(regions);
157
0
158
0
    registration = MakeUnique<ScopedLayerTreeRegistration>(manager, LayersId{0}, root, mcc);
159
0
    manager->UpdateHitTestingTree(LayersId{0}, root, false, LayersId{0}, 0);
160
0
  }
161
};
162
163
0
TEST_F(APZEventRegionsTester, HitRegionImmediateResponse) {
164
0
  SCOPED_GFX_VAR(UseWebRender, bool, false);
165
0
166
0
  CreateEventRegionsLayerTree1();
167
0
168
0
  TestAsyncPanZoomController* root = ApzcOf(layers[0]);
169
0
  TestAsyncPanZoomController* left = ApzcOf(layers[1]);
170
0
  TestAsyncPanZoomController* bottom = ApzcOf(layers[2]);
171
0
172
0
  MockFunction<void(std::string checkPointName)> check;
173
0
  {
174
0
    InSequence s;
175
0
    EXPECT_CALL(*mcc, HandleTap(TapType::eSingleTap, _, _, left->GetGuid(), _)).Times(1);
176
0
    EXPECT_CALL(check, Call("Tapped on left"));
177
0
    EXPECT_CALL(*mcc, HandleTap(TapType::eSingleTap, _, _, bottom->GetGuid(), _)).Times(1);
178
0
    EXPECT_CALL(check, Call("Tapped on bottom"));
179
0
    EXPECT_CALL(*mcc, HandleTap(TapType::eSingleTap, _, _, root->GetGuid(), _)).Times(1);
180
0
    EXPECT_CALL(check, Call("Tapped on root"));
181
0
    EXPECT_CALL(check, Call("Tap pending on d-t-c region"));
182
0
    EXPECT_CALL(*mcc, HandleTap(TapType::eSingleTap, _, _, bottom->GetGuid(), _)).Times(1);
183
0
    EXPECT_CALL(check, Call("Tapped on bottom again"));
184
0
    EXPECT_CALL(*mcc, HandleTap(TapType::eSingleTap, _, _, left->GetGuid(), _)).Times(1);
185
0
    EXPECT_CALL(check, Call("Tapped on left this time"));
186
0
  }
187
0
188
0
  TimeDuration tapDuration = TimeDuration::FromMilliseconds(100);
189
0
190
0
  // Tap in the exposed hit regions of each of the layers once and ensure
191
0
  // the clicks are dispatched right away
192
0
  Tap(manager, ScreenIntPoint(10, 10), tapDuration);
193
0
  mcc->RunThroughDelayedTasks();    // this runs the tap event
194
0
  check.Call("Tapped on left");
195
0
  Tap(manager, ScreenIntPoint(110, 110), tapDuration);
196
0
  mcc->RunThroughDelayedTasks();    // this runs the tap event
197
0
  check.Call("Tapped on bottom");
198
0
  Tap(manager, ScreenIntPoint(110, 10), tapDuration);
199
0
  mcc->RunThroughDelayedTasks();    // this runs the tap event
200
0
  check.Call("Tapped on root");
201
0
202
0
  // Now tap on the dispatch-to-content region where the layers overlap
203
0
  Tap(manager, ScreenIntPoint(10, 110), tapDuration);
204
0
  mcc->RunThroughDelayedTasks();    // this runs the main-thread timeout
205
0
  check.Call("Tap pending on d-t-c region");
206
0
  mcc->RunThroughDelayedTasks();    // this runs the tap event
207
0
  check.Call("Tapped on bottom again");
208
0
209
0
  // Now let's do that again, but simulate a main-thread response
210
0
  uint64_t inputBlockId = 0;
211
0
  Tap(manager, ScreenIntPoint(10, 110), tapDuration, nullptr, &inputBlockId);
212
0
  nsTArray<ScrollableLayerGuid> targets;
213
0
  targets.AppendElement(left->GetGuid());
214
0
  manager->SetTargetAPZC(inputBlockId, targets);
215
0
  while (mcc->RunThroughDelayedTasks());    // this runs the tap event
216
0
  check.Call("Tapped on left this time");
217
0
}
218
219
0
TEST_F(APZEventRegionsTester, HitRegionAccumulatesChildren) {
220
0
  CreateEventRegionsLayerTree2();
221
0
222
0
  // Tap in the area of the child layer that's not directly included in the
223
0
  // parent layer's hit region. Verify that it comes out of the APZC's
224
0
  // content controller, which indicates the input events got routed correctly
225
0
  // to the APZC.
226
0
  EXPECT_CALL(*mcc, HandleTap(TapType::eSingleTap, _, _, rootApzc->GetGuid(), _)).Times(1);
227
0
  Tap(manager, ScreenIntPoint(10, 160), TimeDuration::FromMilliseconds(100));
228
0
}
229
230
0
TEST_F(APZEventRegionsTester, Obscuration) {
231
0
  SCOPED_GFX_VAR(UseWebRender, bool, false);
232
0
233
0
  CreateObscuringLayerTree();
234
0
  ScopedLayerTreeRegistration registration(manager, LayersId{0}, root, mcc);
235
0
236
0
  manager->UpdateHitTestingTree(LayersId{0}, root, false, LayersId{0}, 0);
237
0
238
0
  RefPtr<TestAsyncPanZoomController> parent = ApzcOf(layers[1]);
239
0
  TestAsyncPanZoomController* child = ApzcOf(layers[2]);
240
0
241
0
  Pan(parent, 75, 25, PanOptions::NoFling);
242
0
243
0
  gfx::CompositorHitTestInfo result;
244
0
  RefPtr<AsyncPanZoomController> hit = manager->GetTargetAPZC(ScreenPoint(50, 75), &result);
245
0
  EXPECT_EQ(child, hit.get());
246
0
  EXPECT_EQ(CompositorHitTestInfo::eVisibleToHitTest, result);
247
0
}
248
249
0
TEST_F(APZEventRegionsTester, Bug1119497) {
250
0
  CreateBug1119497LayerTree();
251
0
252
0
  gfx::CompositorHitTestInfo result;
253
0
  RefPtr<AsyncPanZoomController> hit = manager->GetTargetAPZC(ScreenPoint(50, 50), &result);
254
0
  // We should hit layers[2], so |result| will be eVisibleToHitTest but there's no
255
0
  // actual APZC on layers[2], so it will be the APZC of the root layer.
256
0
  EXPECT_EQ(ApzcOf(layers[0]), hit.get());
257
0
  EXPECT_EQ(CompositorHitTestInfo::eVisibleToHitTest, result);
258
0
}
259
260
0
TEST_F(APZEventRegionsTester, Bug1117712) {
261
0
  CreateBug1117712LayerTree();
262
0
263
0
  TestAsyncPanZoomController* apzc2 = ApzcOf(layers[2]);
264
0
265
0
  // These touch events should hit the dispatch-to-content region of layers[3]
266
0
  // and so get queued with that APZC as the tentative target.
267
0
  uint64_t inputBlockId = 0;
268
0
  Tap(manager, ScreenIntPoint(55, 5), TimeDuration::FromMilliseconds(100), nullptr, &inputBlockId);
269
0
  // But now we tell the APZ that really it hit layers[2], and expect the tap
270
0
  // to be delivered at the correct coordinates.
271
0
  EXPECT_CALL(*mcc, HandleTap(TapType::eSingleTap, LayoutDevicePoint(55, 5), 0, apzc2->GetGuid(), _)).Times(1);
272
0
273
0
  nsTArray<ScrollableLayerGuid> targets;
274
0
  targets.AppendElement(apzc2->GetGuid());
275
0
  manager->SetTargetAPZC(inputBlockId, targets);
276
0
}