/src/mozilla-central/gfx/layers/apz/test/gtest/TestBasic.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 "APZCBasicTester.h" |
8 | | #include "APZTestCommon.h" |
9 | | #include "gfxPrefs.h" |
10 | | #include "InputUtils.h" |
11 | | |
12 | 0 | TEST_F(APZCBasicTester, Overzoom) { |
13 | 0 | // the visible area of the document in CSS pixels is x=10 y=0 w=100 h=100 |
14 | 0 | FrameMetrics fm; |
15 | 0 | fm.SetCompositionBounds(ParentLayerRect(0, 0, 100, 100)); |
16 | 0 | fm.SetScrollableRect(CSSRect(0, 0, 125, 150)); |
17 | 0 | fm.SetScrollOffset(CSSPoint(10, 0)); |
18 | 0 | fm.SetZoom(CSSToParentLayerScale2D(1.0, 1.0)); |
19 | 0 | fm.SetIsRootContent(true); |
20 | 0 | apzc->SetFrameMetrics(fm); |
21 | 0 |
|
22 | 0 | MakeApzcZoomable(); |
23 | 0 |
|
24 | 0 | EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(1); |
25 | 0 |
|
26 | 0 | PinchWithPinchInputAndCheckStatus(apzc, ScreenIntPoint(50, 50), 0.5, true); |
27 | 0 |
|
28 | 0 | fm = apzc->GetFrameMetrics(); |
29 | 0 | EXPECT_EQ(0.8f, fm.GetZoom().ToScaleFactor().scale); |
30 | 0 | // bug 936721 - PGO builds introduce rounding error so |
31 | 0 | // use a fuzzy match instead |
32 | 0 | EXPECT_LT(std::abs(fm.GetScrollOffset().x), 1e-5); |
33 | 0 | EXPECT_LT(std::abs(fm.GetScrollOffset().y), 1e-5); |
34 | 0 | } |
35 | | |
36 | 0 | TEST_F(APZCBasicTester, SimpleTransform) { |
37 | 0 | ParentLayerPoint pointOut; |
38 | 0 | AsyncTransform viewTransformOut; |
39 | 0 | apzc->SampleContentTransformForFrame(&viewTransformOut, pointOut); |
40 | 0 |
|
41 | 0 | EXPECT_EQ(ParentLayerPoint(), pointOut); |
42 | 0 | EXPECT_EQ(AsyncTransform(), viewTransformOut); |
43 | 0 | } |
44 | | |
45 | | |
46 | 0 | TEST_F(APZCBasicTester, ComplexTransform) { |
47 | 0 | // This test assumes there is a page that gets rendered to |
48 | 0 | // two layers. In CSS pixels, the first layer is 50x50 and |
49 | 0 | // the second layer is 25x50. The widget scale factor is 3.0 |
50 | 0 | // and the presShell resolution is 2.0. Therefore, these layers |
51 | 0 | // end up being 300x300 and 150x300 in layer pixels. |
52 | 0 | // |
53 | 0 | // The second (child) layer has an additional CSS transform that |
54 | 0 | // stretches it by 2.0 on the x-axis. Therefore, after applying |
55 | 0 | // CSS transforms, the two layers are the same size in screen |
56 | 0 | // pixels. |
57 | 0 | // |
58 | 0 | // The screen itself is 24x24 in screen pixels (therefore 4x4 in |
59 | 0 | // CSS pixels). The displayport is 1 extra CSS pixel on all |
60 | 0 | // sides. |
61 | 0 |
|
62 | 0 | RefPtr<TestAsyncPanZoomController> childApzc = |
63 | 0 | new TestAsyncPanZoomController(LayersId{0}, mcc, tm); |
64 | 0 |
|
65 | 0 | const char* layerTreeSyntax = "c(c)"; |
66 | 0 | // LayerID 0 1 |
67 | 0 | nsIntRegion layerVisibleRegion[] = { |
68 | 0 | nsIntRegion(IntRect(0, 0, 300, 300)), |
69 | 0 | nsIntRegion(IntRect(0, 0, 150, 300)), |
70 | 0 | }; |
71 | 0 | Matrix4x4 transforms[] = { |
72 | 0 | Matrix4x4(), |
73 | 0 | Matrix4x4(), |
74 | 0 | }; |
75 | 0 | transforms[0].PostScale(0.5f, 0.5f, 1.0f); // this results from the 2.0 resolution on the root layer |
76 | 0 | transforms[1].PostScale(2.0f, 1.0f, 1.0f); // this is the 2.0 x-axis CSS transform on the child layer |
77 | 0 |
|
78 | 0 | nsTArray<RefPtr<Layer> > layers; |
79 | 0 | RefPtr<LayerManager> lm; |
80 | 0 | RefPtr<Layer> root = CreateLayerTree(layerTreeSyntax, layerVisibleRegion, transforms, lm, layers); |
81 | 0 |
|
82 | 0 | ScrollMetadata metadata; |
83 | 0 | FrameMetrics& metrics = metadata.GetMetrics(); |
84 | 0 | metrics.SetCompositionBounds(ParentLayerRect(0, 0, 24, 24)); |
85 | 0 | metrics.SetDisplayPort(CSSRect(-1, -1, 6, 6)); |
86 | 0 | metrics.SetScrollOffset(CSSPoint(10, 10)); |
87 | 0 | metrics.SetScrollableRect(CSSRect(0, 0, 50, 50)); |
88 | 0 | metrics.SetCumulativeResolution(LayoutDeviceToLayerScale2D(2, 2)); |
89 | 0 | metrics.SetPresShellResolution(2.0f); |
90 | 0 | metrics.SetZoom(CSSToParentLayerScale2D(6, 6)); |
91 | 0 | metrics.SetDevPixelsPerCSSPixel(CSSToLayoutDeviceScale(3)); |
92 | 0 | metrics.SetScrollId(FrameMetrics::START_SCROLL_ID); |
93 | 0 |
|
94 | 0 | ScrollMetadata childMetadata = metadata; |
95 | 0 | FrameMetrics& childMetrics = childMetadata.GetMetrics(); |
96 | 0 | childMetrics.SetScrollId(FrameMetrics::START_SCROLL_ID + 1); |
97 | 0 |
|
98 | 0 | layers[0]->SetScrollMetadata(metadata); |
99 | 0 | layers[1]->SetScrollMetadata(childMetadata); |
100 | 0 |
|
101 | 0 | ParentLayerPoint pointOut; |
102 | 0 | AsyncTransform viewTransformOut; |
103 | 0 |
|
104 | 0 | // Both the parent and child layer should behave exactly the same here, because |
105 | 0 | // the CSS transform on the child layer does not affect the SampleContentTransformForFrame code |
106 | 0 |
|
107 | 0 | // initial transform |
108 | 0 | apzc->SetFrameMetrics(metrics); |
109 | 0 | apzc->NotifyLayersUpdated(metadata, true, true); |
110 | 0 | apzc->SampleContentTransformForFrame(&viewTransformOut, pointOut); |
111 | 0 | EXPECT_EQ(AsyncTransform(LayerToParentLayerScale(1), ParentLayerPoint()), viewTransformOut); |
112 | 0 | EXPECT_EQ(ParentLayerPoint(60, 60), pointOut); |
113 | 0 |
|
114 | 0 | childApzc->SetFrameMetrics(childMetrics); |
115 | 0 | childApzc->NotifyLayersUpdated(childMetadata, true, true); |
116 | 0 | childApzc->SampleContentTransformForFrame(&viewTransformOut, pointOut); |
117 | 0 | EXPECT_EQ(AsyncTransform(LayerToParentLayerScale(1), ParentLayerPoint()), viewTransformOut); |
118 | 0 | EXPECT_EQ(ParentLayerPoint(60, 60), pointOut); |
119 | 0 |
|
120 | 0 | // do an async scroll by 5 pixels and check the transform |
121 | 0 | metrics.ScrollBy(CSSPoint(5, 0)); |
122 | 0 | apzc->SetFrameMetrics(metrics); |
123 | 0 | apzc->SampleContentTransformForFrame(&viewTransformOut, pointOut); |
124 | 0 | EXPECT_EQ(AsyncTransform(LayerToParentLayerScale(1), ParentLayerPoint(-30, 0)), viewTransformOut); |
125 | 0 | EXPECT_EQ(ParentLayerPoint(90, 60), pointOut); |
126 | 0 |
|
127 | 0 | childMetrics.ScrollBy(CSSPoint(5, 0)); |
128 | 0 | childApzc->SetFrameMetrics(childMetrics); |
129 | 0 | childApzc->SampleContentTransformForFrame(&viewTransformOut, pointOut); |
130 | 0 | EXPECT_EQ(AsyncTransform(LayerToParentLayerScale(1), ParentLayerPoint(-30, 0)), viewTransformOut); |
131 | 0 | EXPECT_EQ(ParentLayerPoint(90, 60), pointOut); |
132 | 0 |
|
133 | 0 | // do an async zoom of 1.5x and check the transform |
134 | 0 | metrics.ZoomBy(1.5f); |
135 | 0 | apzc->SetFrameMetrics(metrics); |
136 | 0 | apzc->SampleContentTransformForFrame(&viewTransformOut, pointOut); |
137 | 0 | EXPECT_EQ(AsyncTransform(LayerToParentLayerScale(1.5), ParentLayerPoint(-45, 0)), viewTransformOut); |
138 | 0 | EXPECT_EQ(ParentLayerPoint(135, 90), pointOut); |
139 | 0 |
|
140 | 0 | childMetrics.ZoomBy(1.5f); |
141 | 0 | childApzc->SetFrameMetrics(childMetrics); |
142 | 0 | childApzc->SampleContentTransformForFrame(&viewTransformOut, pointOut); |
143 | 0 | EXPECT_EQ(AsyncTransform(LayerToParentLayerScale(1.5), ParentLayerPoint(-45, 0)), viewTransformOut); |
144 | 0 | EXPECT_EQ(ParentLayerPoint(135, 90), pointOut); |
145 | 0 |
|
146 | 0 | childApzc->Destroy(); |
147 | 0 | } |
148 | | |
149 | 0 | TEST_F(APZCBasicTester, Fling) { |
150 | 0 | SCOPED_GFX_PREF(APZFlingMinVelocityThreshold, float, 0.0f); |
151 | 0 | int touchStart = 50; |
152 | 0 | int touchEnd = 10; |
153 | 0 | ParentLayerPoint pointOut; |
154 | 0 | AsyncTransform viewTransformOut; |
155 | 0 |
|
156 | 0 | // Fling down. Each step scroll further down |
157 | 0 | Pan(apzc, touchStart, touchEnd); |
158 | 0 | ParentLayerPoint lastPoint; |
159 | 0 | for (int i = 1; i < 50; i+=1) { |
160 | 0 | apzc->SampleContentTransformForFrame(&viewTransformOut, pointOut, TimeDuration::FromMilliseconds(1)); |
161 | 0 | EXPECT_GT(pointOut.y, lastPoint.y); |
162 | 0 | lastPoint = pointOut; |
163 | 0 | } |
164 | 0 | } |
165 | | |
166 | 0 | TEST_F(APZCBasicTester, FlingIntoOverscroll) { |
167 | 0 | // Enable overscrolling. |
168 | 0 | SCOPED_GFX_PREF(APZOverscrollEnabled, bool, true); |
169 | 0 | SCOPED_GFX_PREF(APZFlingMinVelocityThreshold, float, 0.0f); |
170 | 0 |
|
171 | 0 | // Scroll down by 25 px. Don't fling for simplicity. |
172 | 0 | Pan(apzc, 50, 25, PanOptions::NoFling); |
173 | 0 |
|
174 | 0 | // Now scroll back up by 20px, this time flinging after. |
175 | 0 | // The fling should cover the remaining 5 px of room to scroll, then |
176 | 0 | // go into overscroll, and finally snap-back to recover from overscroll. |
177 | 0 | Pan(apzc, 25, 45); |
178 | 0 | const TimeDuration increment = TimeDuration::FromMilliseconds(1); |
179 | 0 | bool reachedOverscroll = false; |
180 | 0 | bool recoveredFromOverscroll = false; |
181 | 0 | while (apzc->AdvanceAnimations(mcc->Time())) { |
182 | 0 | if (!reachedOverscroll && apzc->IsOverscrolled()) { |
183 | 0 | reachedOverscroll = true; |
184 | 0 | } |
185 | 0 | if (reachedOverscroll && !apzc->IsOverscrolled()) { |
186 | 0 | recoveredFromOverscroll = true; |
187 | 0 | } |
188 | 0 | mcc->AdvanceBy(increment); |
189 | 0 | } |
190 | 0 | EXPECT_TRUE(reachedOverscroll); |
191 | 0 | EXPECT_TRUE(recoveredFromOverscroll); |
192 | 0 | } |
193 | | |
194 | 0 | TEST_F(APZCBasicTester, PanningTransformNotifications) { |
195 | 0 | SCOPED_GFX_PREF(APZOverscrollEnabled, bool, true); |
196 | 0 |
|
197 | 0 | // Scroll down by 25 px. Ensure we only get one set of |
198 | 0 | // state change notifications. |
199 | 0 | // |
200 | 0 | // Then, scroll back up by 20px, this time flinging after. |
201 | 0 | // The fling should cover the remaining 5 px of room to scroll, then |
202 | 0 | // go into overscroll, and finally snap-back to recover from overscroll. |
203 | 0 | // Again, ensure we only get one set of state change notifications for |
204 | 0 | // this entire procedure. |
205 | 0 |
|
206 | 0 | MockFunction<void(std::string checkPointName)> check; |
207 | 0 | { |
208 | 0 | InSequence s; |
209 | 0 | EXPECT_CALL(check, Call("Simple pan")); |
210 | 0 | EXPECT_CALL(*mcc, NotifyAPZStateChange(_,GeckoContentController::APZStateChange::eStartTouch,_)).Times(1); |
211 | 0 | EXPECT_CALL(*mcc, NotifyAPZStateChange(_,GeckoContentController::APZStateChange::eTransformBegin,_)).Times(1); |
212 | 0 | EXPECT_CALL(*mcc, NotifyAPZStateChange(_,GeckoContentController::APZStateChange::eStartPanning,_)).Times(1); |
213 | 0 | EXPECT_CALL(*mcc, NotifyAPZStateChange(_,GeckoContentController::APZStateChange::eEndTouch,_)).Times(1); |
214 | 0 | EXPECT_CALL(*mcc, NotifyAPZStateChange(_,GeckoContentController::APZStateChange::eTransformEnd,_)).Times(1); |
215 | 0 | EXPECT_CALL(check, Call("Complex pan")); |
216 | 0 | EXPECT_CALL(*mcc, NotifyAPZStateChange(_,GeckoContentController::APZStateChange::eStartTouch,_)).Times(1); |
217 | 0 | EXPECT_CALL(*mcc, NotifyAPZStateChange(_,GeckoContentController::APZStateChange::eTransformBegin,_)).Times(1); |
218 | 0 | EXPECT_CALL(*mcc, NotifyAPZStateChange(_,GeckoContentController::APZStateChange::eStartPanning,_)).Times(1); |
219 | 0 | EXPECT_CALL(*mcc, NotifyAPZStateChange(_,GeckoContentController::APZStateChange::eEndTouch,_)).Times(1); |
220 | 0 | EXPECT_CALL(*mcc, NotifyAPZStateChange(_,GeckoContentController::APZStateChange::eTransformEnd,_)).Times(1); |
221 | 0 | EXPECT_CALL(check, Call("Done")); |
222 | 0 | } |
223 | 0 |
|
224 | 0 | check.Call("Simple pan"); |
225 | 0 | Pan(apzc, 50, 25, PanOptions::NoFling); |
226 | 0 | check.Call("Complex pan"); |
227 | 0 | Pan(apzc, 25, 45); |
228 | 0 | apzc->AdvanceAnimationsUntilEnd(); |
229 | 0 | check.Call("Done"); |
230 | 0 | } |
231 | | |
232 | | void APZCBasicTester::PanIntoOverscroll() |
233 | 0 | { |
234 | 0 | int touchStart = 500; |
235 | 0 | int touchEnd = 10; |
236 | 0 | Pan(apzc, touchStart, touchEnd); |
237 | 0 | EXPECT_TRUE(apzc->IsOverscrolled()); |
238 | 0 | } |
239 | | |
240 | | void APZCBasicTester::TestOverscroll() |
241 | 0 | { |
242 | 0 | // Pan sufficiently to hit overscroll behavior |
243 | 0 | PanIntoOverscroll(); |
244 | 0 |
|
245 | 0 | // Check that we recover from overscroll via an animation. |
246 | 0 | ParentLayerPoint expectedScrollOffset(0, GetScrollRange().YMost()); |
247 | 0 | SampleAnimationUntilRecoveredFromOverscroll(expectedScrollOffset); |
248 | 0 | } |
249 | | |
250 | | |
251 | 0 | TEST_F(APZCBasicTester, OverScrollPanning) { |
252 | 0 | SCOPED_GFX_PREF(APZOverscrollEnabled, bool, true); |
253 | 0 |
|
254 | 0 | TestOverscroll(); |
255 | 0 | } |
256 | | |
257 | | // Tests that an overscroll animation doesn't trigger an assertion failure |
258 | | // in the case where a sample has a velocity of zero. |
259 | 0 | TEST_F(APZCBasicTester, OverScroll_Bug1152051a) { |
260 | 0 | SCOPED_GFX_PREF(APZOverscrollEnabled, bool, true); |
261 | 0 |
|
262 | 0 | // Doctor the prefs to make the velocity zero at the end of the first sample. |
263 | 0 |
|
264 | 0 | // This ensures our incoming velocity to the overscroll animation is |
265 | 0 | // a round(ish) number, 4.9 (that being the distance of the pan before |
266 | 0 | // overscroll, which is 500 - 10 = 490 pixels, divided by the duration of |
267 | 0 | // the pan, which is 100 ms). |
268 | 0 | SCOPED_GFX_PREF(APZFlingFriction, float, 0); |
269 | 0 |
|
270 | 0 | // To ensure the velocity after the first sample is 0, set the spring |
271 | 0 | // stiffness to the incoming velocity (4.9) divided by the overscroll |
272 | 0 | // (400 pixels) times the step duration (1 ms). |
273 | 0 | SCOPED_GFX_PREF(APZOverscrollSpringStiffness, float, 0.01225f); |
274 | 0 |
|
275 | 0 | TestOverscroll(); |
276 | 0 | } |
277 | | |
278 | | // Tests that ending an overscroll animation doesn't leave around state that |
279 | | // confuses the next overscroll animation. |
280 | 0 | TEST_F(APZCBasicTester, OverScroll_Bug1152051b) { |
281 | 0 | SCOPED_GFX_PREF(APZOverscrollEnabled, bool, true); |
282 | 0 |
|
283 | 0 | SCOPED_GFX_PREF(APZOverscrollStopDistanceThreshold, float, 0.1f); |
284 | 0 |
|
285 | 0 | // Pan sufficiently to hit overscroll behavior |
286 | 0 | PanIntoOverscroll(); |
287 | 0 |
|
288 | 0 | // Sample animations once, to give the fling animation started on touch-up |
289 | 0 | // a chance to realize it's overscrolled, and schedule a call to |
290 | 0 | // HandleFlingOverscroll(). |
291 | 0 | SampleAnimationOnce(); |
292 | 0 |
|
293 | 0 | // This advances the time and runs the HandleFlingOverscroll task scheduled in |
294 | 0 | // the previous call, which starts an overscroll animation. It then samples |
295 | 0 | // the overscroll animation once, to get it to initialize the first overscroll |
296 | 0 | // sample. |
297 | 0 | SampleAnimationOnce(); |
298 | 0 |
|
299 | 0 | // Do a touch-down to cancel the overscroll animation, and then a touch-up |
300 | 0 | // to schedule a new one since we're still overscrolled. We don't pan because |
301 | 0 | // panning can trigger functions that clear the overscroll animation state |
302 | 0 | // in other ways. |
303 | 0 | uint64_t blockId; |
304 | 0 | nsEventStatus status = TouchDown(apzc, ScreenIntPoint(10, 10), mcc->Time(), &blockId); |
305 | 0 | if (gfxPrefs::TouchActionEnabled() && status != nsEventStatus_eConsumeNoDefault) { |
306 | 0 | SetDefaultAllowedTouchBehavior(apzc, blockId); |
307 | 0 | } |
308 | 0 | TouchUp(apzc, ScreenIntPoint(10, 10), mcc->Time()); |
309 | 0 |
|
310 | 0 | // Sample the second overscroll animation to its end. |
311 | 0 | // If the ending of the first overscroll animation fails to clear state |
312 | 0 | // properly, this will assert. |
313 | 0 | ParentLayerPoint expectedScrollOffset(0, GetScrollRange().YMost()); |
314 | 0 | SampleAnimationUntilRecoveredFromOverscroll(expectedScrollOffset); |
315 | 0 | } |
316 | | |
317 | | // Tests that the page doesn't get stuck in an |
318 | | // overscroll animation after a low-velocity pan. |
319 | 0 | TEST_F(APZCBasicTester, OverScrollAfterLowVelocityPan_Bug1343775) { |
320 | 0 | SCOPED_GFX_PREF(APZOverscrollEnabled, bool, true); |
321 | 0 |
|
322 | 0 | // Pan into overscroll with a velocity less than the |
323 | 0 | // apz.fling_min_velocity_threshold preference. |
324 | 0 | Pan(apzc, 10, 30); |
325 | 0 |
|
326 | 0 | EXPECT_TRUE(apzc->IsOverscrolled()); |
327 | 0 |
|
328 | 0 | apzc->AdvanceAnimationsUntilEnd(); |
329 | 0 |
|
330 | 0 | // Check that we recovered from overscroll. |
331 | 0 | EXPECT_FALSE(apzc->IsOverscrolled()); |
332 | 0 | } |
333 | | |
334 | 0 | TEST_F(APZCBasicTester, OverScrollAbort) { |
335 | 0 | SCOPED_GFX_PREF(APZOverscrollEnabled, bool, true); |
336 | 0 |
|
337 | 0 | // Pan sufficiently to hit overscroll behavior |
338 | 0 | int touchStart = 500; |
339 | 0 | int touchEnd = 10; |
340 | 0 | Pan(apzc, touchStart, touchEnd); |
341 | 0 | EXPECT_TRUE(apzc->IsOverscrolled()); |
342 | 0 |
|
343 | 0 | ParentLayerPoint pointOut; |
344 | 0 | AsyncTransform viewTransformOut; |
345 | 0 |
|
346 | 0 | // This sample call will run to the end of the fling animation |
347 | 0 | // and will schedule the overscroll animation. |
348 | 0 | apzc->SampleContentTransformForFrame(&viewTransformOut, pointOut, TimeDuration::FromMilliseconds(10000)); |
349 | 0 | EXPECT_TRUE(apzc->IsOverscrolled()); |
350 | 0 |
|
351 | 0 | // At this point, we have an active overscroll animation. |
352 | 0 | // Check that cancelling the animation clears the overscroll. |
353 | 0 | apzc->CancelAnimation(); |
354 | 0 | EXPECT_FALSE(apzc->IsOverscrolled()); |
355 | 0 | apzc->AssertStateIsReset(); |
356 | 0 | } |
357 | | |
358 | 0 | TEST_F(APZCBasicTester, OverScrollPanningAbort) { |
359 | 0 | SCOPED_GFX_PREF(APZOverscrollEnabled, bool, true); |
360 | 0 |
|
361 | 0 | // Pan sufficiently to hit overscroll behaviour. Keep the finger down so |
362 | 0 | // the pan does not end. |
363 | 0 | int touchStart = 500; |
364 | 0 | int touchEnd = 10; |
365 | 0 | Pan(apzc, touchStart, touchEnd, PanOptions::KeepFingerDown); |
366 | 0 | EXPECT_TRUE(apzc->IsOverscrolled()); |
367 | 0 |
|
368 | 0 | // Check that calling CancelAnimation() while the user is still panning |
369 | 0 | // (and thus no fling or snap-back animation has had a chance to start) |
370 | 0 | // clears the overscroll. |
371 | 0 | apzc->CancelAnimation(); |
372 | 0 | EXPECT_FALSE(apzc->IsOverscrolled()); |
373 | 0 | apzc->AssertStateIsReset(); |
374 | 0 | } |