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 
10 #include "InputUtils.h"
11 
TEST_F(APZCBasicTester,Overzoom)12 TEST_F(APZCBasicTester, Overzoom) {
13   // the visible area of the document in CSS pixels is x=10 y=0 w=100 h=100
14   FrameMetrics fm;
15   fm.SetCompositionBounds(ParentLayerRect(0, 0, 100, 100));
16   fm.SetScrollableRect(CSSRect(0, 0, 125, 150));
17   fm.SetVisualScrollOffset(CSSPoint(10, 0));
18   fm.SetZoom(CSSToParentLayerScale2D(1.0, 1.0));
19   fm.SetIsRootContent(true);
20   apzc->SetFrameMetrics(fm);
21 
22   MakeApzcZoomable();
23 
24   EXPECT_CALL(*mcc, RequestContentRepaint(_)).Times(1);
25 
26   PinchWithPinchInputAndCheckStatus(apzc, ScreenIntPoint(50, 50), 0.5, true);
27 
28   fm = apzc->GetFrameMetrics();
29   EXPECT_EQ(0.8f, fm.GetZoom().ToScaleFactor().scale);
30   // bug 936721 - PGO builds introduce rounding error so
31   // use a fuzzy match instead
32   EXPECT_LT(std::abs(fm.GetVisualScrollOffset().x), 1e-5);
33   EXPECT_LT(std::abs(fm.GetVisualScrollOffset().y), 1e-5);
34 }
35 
TEST_F(APZCBasicTester,SimpleTransform)36 TEST_F(APZCBasicTester, SimpleTransform) {
37   ParentLayerPoint pointOut;
38   AsyncTransform viewTransformOut;
39   apzc->SampleContentTransformForFrame(&viewTransformOut, pointOut);
40 
41   EXPECT_EQ(ParentLayerPoint(), pointOut);
42   EXPECT_EQ(AsyncTransform(), viewTransformOut);
43 }
44 
TEST_F(APZCBasicTester,ComplexTransform)45 TEST_F(APZCBasicTester, ComplexTransform) {
46   // This test assumes there is a page that gets rendered to
47   // two layers. In CSS pixels, the first layer is 50x50 and
48   // the second layer is 25x50. The widget scale factor is 3.0
49   // and the presShell resolution is 2.0. Therefore, these layers
50   // end up being 300x300 and 150x300 in layer pixels.
51   //
52   // The second (child) layer has an additional CSS transform that
53   // stretches it by 2.0 on the x-axis. Therefore, after applying
54   // CSS transforms, the two layers are the same size in screen
55   // pixels.
56   //
57   // The screen itself is 24x24 in screen pixels (therefore 4x4 in
58   // CSS pixels). The displayport is 1 extra CSS pixel on all
59   // sides.
60 
61   RefPtr<TestAsyncPanZoomController> childApzc =
62       new TestAsyncPanZoomController(LayersId{0}, mcc, tm);
63 
64   const char* layerTreeSyntax = "c(c)";
65   // LayerID                     0 1
66   nsIntRegion layerVisibleRegion[] = {
67       nsIntRegion(IntRect(0, 0, 300, 300)),
68       nsIntRegion(IntRect(0, 0, 150, 300)),
69   };
70   Matrix4x4 transforms[] = {
71       Matrix4x4(),
72       Matrix4x4(),
73   };
74   transforms[0].PostScale(
75       0.5f, 0.5f,
76       1.0f);  // this results from the 2.0 resolution on the root layer
77   transforms[1].PostScale(
78       2.0f, 1.0f,
79       1.0f);  // this is the 2.0 x-axis CSS transform on the child layer
80 
81   nsTArray<RefPtr<Layer> > layers;
82   RefPtr<LayerManager> lm;
83   RefPtr<Layer> root = CreateLayerTree(layerTreeSyntax, layerVisibleRegion,
84                                        transforms, lm, layers);
85 
86   ScrollMetadata metadata;
87   FrameMetrics& metrics = metadata.GetMetrics();
88   metrics.SetCompositionBounds(ParentLayerRect(0, 0, 24, 24));
89   metrics.SetDisplayPort(CSSRect(-1, -1, 6, 6));
90   metrics.SetVisualScrollOffset(CSSPoint(10, 10));
91   metrics.SetLayoutViewport(CSSRect(10, 10, 8, 8));
92   metrics.SetScrollableRect(CSSRect(0, 0, 50, 50));
93   metrics.SetCumulativeResolution(LayoutDeviceToLayerScale2D(2, 2));
94   metrics.SetPresShellResolution(2.0f);
95   metrics.SetZoom(CSSToParentLayerScale2D(6, 6));
96   metrics.SetDevPixelsPerCSSPixel(CSSToLayoutDeviceScale(3));
97   metrics.SetScrollId(ScrollableLayerGuid::START_SCROLL_ID);
98 
99   ScrollMetadata childMetadata = metadata;
100   FrameMetrics& childMetrics = childMetadata.GetMetrics();
101   childMetrics.SetScrollId(ScrollableLayerGuid::START_SCROLL_ID + 1);
102 
103   layers[0]->SetScrollMetadata(metadata);
104   layers[1]->SetScrollMetadata(childMetadata);
105 
106   ParentLayerPoint pointOut;
107   AsyncTransform viewTransformOut;
108 
109   // Both the parent and child layer should behave exactly the same here,
110   // because the CSS transform on the child layer does not affect the
111   // SampleContentTransformForFrame code
112 
113   // initial transform
114   apzc->SetFrameMetrics(metrics);
115   apzc->NotifyLayersUpdated(metadata, true, true);
116   apzc->SampleContentTransformForFrame(&viewTransformOut, pointOut);
117   EXPECT_EQ(AsyncTransform(LayerToParentLayerScale(1), ParentLayerPoint()),
118             viewTransformOut);
119   EXPECT_EQ(ParentLayerPoint(60, 60), pointOut);
120 
121   childApzc->SetFrameMetrics(childMetrics);
122   childApzc->NotifyLayersUpdated(childMetadata, true, true);
123   childApzc->SampleContentTransformForFrame(&viewTransformOut, pointOut);
124   EXPECT_EQ(AsyncTransform(LayerToParentLayerScale(1), ParentLayerPoint()),
125             viewTransformOut);
126   EXPECT_EQ(ParentLayerPoint(60, 60), pointOut);
127 
128   // do an async scroll by 5 pixels and check the transform
129   metrics.ScrollBy(CSSPoint(5, 0));
130   apzc->SetFrameMetrics(metrics);
131   apzc->SampleContentTransformForFrame(&viewTransformOut, pointOut);
132   EXPECT_EQ(
133       AsyncTransform(LayerToParentLayerScale(1), ParentLayerPoint(-30, 0)),
134       viewTransformOut);
135   EXPECT_EQ(ParentLayerPoint(90, 60), pointOut);
136 
137   childMetrics.ScrollBy(CSSPoint(5, 0));
138   childApzc->SetFrameMetrics(childMetrics);
139   childApzc->SampleContentTransformForFrame(&viewTransformOut, pointOut);
140   EXPECT_EQ(
141       AsyncTransform(LayerToParentLayerScale(1), ParentLayerPoint(-30, 0)),
142       viewTransformOut);
143   EXPECT_EQ(ParentLayerPoint(90, 60), pointOut);
144 
145   // do an async zoom of 1.5x and check the transform
146   metrics.ZoomBy(1.5f);
147   apzc->SetFrameMetrics(metrics);
148   apzc->SampleContentTransformForFrame(&viewTransformOut, pointOut);
149   EXPECT_EQ(
150       AsyncTransform(LayerToParentLayerScale(1.5), ParentLayerPoint(-45, 0)),
151       viewTransformOut);
152   EXPECT_EQ(ParentLayerPoint(135, 90), pointOut);
153 
154   childMetrics.ZoomBy(1.5f);
155   childApzc->SetFrameMetrics(childMetrics);
156   childApzc->SampleContentTransformForFrame(&viewTransformOut, pointOut);
157   EXPECT_EQ(
158       AsyncTransform(LayerToParentLayerScale(1.5), ParentLayerPoint(-45, 0)),
159       viewTransformOut);
160   EXPECT_EQ(ParentLayerPoint(135, 90), pointOut);
161 
162   childApzc->Destroy();
163 }
164 
TEST_F(APZCBasicTester,Fling)165 TEST_F(APZCBasicTester, Fling) {
166   SCOPED_GFX_PREF_FLOAT("apz.fling_min_velocity_threshold", 0.0f);
167   int touchStart = 50;
168   int touchEnd = 10;
169   ParentLayerPoint pointOut;
170   AsyncTransform viewTransformOut;
171 
172   // Fling down. Each step scroll further down
173   Pan(apzc, touchStart, touchEnd);
174   ParentLayerPoint lastPoint;
175   for (int i = 1; i < 50; i += 1) {
176     apzc->SampleContentTransformForFrame(&viewTransformOut, pointOut,
177                                          TimeDuration::FromMilliseconds(1));
178     EXPECT_GT(pointOut.y, lastPoint.y);
179     lastPoint = pointOut;
180   }
181 }
182 
183 #ifndef MOZ_WIDGET_ANDROID  // Maybe fails on Android
TEST_F(APZCBasicTester,ResumeInterruptedTouchDrag_Bug1592435)184 TEST_F(APZCBasicTester, ResumeInterruptedTouchDrag_Bug1592435) {
185   // Start a touch-drag and scroll some amount, not lifting the finger.
186   SCOPED_GFX_PREF_FLOAT("apz.touch_start_tolerance", 1.0f / 1000.0f);
187   ScreenIntPoint touchPos(10, 50);
188   uint64_t touchBlock = TouchDown(apzc, touchPos, mcc->Time()).mInputBlockId;
189   SetDefaultAllowedTouchBehavior(apzc, touchBlock);
190   for (int i = 0; i < 20; ++i) {
191     touchPos.y -= 1;
192     mcc->AdvanceByMillis(1);
193     TouchMove(apzc, touchPos, mcc->Time());
194   }
195 
196   // Take note of the scroll offset before the interruption.
197   CSSPoint scrollOffsetBeforeInterruption =
198       apzc->GetFrameMetrics().GetVisualScrollOffset();
199 
200   // Have the main thread interrupt the touch-drag by sending
201   // a main thread scroll update to a nearby location.
202   CSSPoint mainThreadOffset = scrollOffsetBeforeInterruption;
203   mainThreadOffset.y -= 5;
204   ScrollMetadata metadata = apzc->GetScrollMetadata();
205   metadata.GetMetrics().SetLayoutScrollOffset(mainThreadOffset);
206   nsTArray<ScrollPositionUpdate> scrollUpdates;
207   scrollUpdates.AppendElement(ScrollPositionUpdate::NewScroll(
208       ScrollOrigin::Other, CSSPoint::ToAppUnits(mainThreadOffset)));
209   metadata.SetScrollUpdates(scrollUpdates);
210   metadata.GetMetrics().SetScrollGeneration(
211       scrollUpdates.LastElement().GetGeneration());
212   apzc->NotifyLayersUpdated(metadata, false, true);
213 
214   // Continue and finish the touch-drag gesture.
215   for (int i = 0; i < 20; ++i) {
216     touchPos.y -= 1;
217     mcc->AdvanceByMillis(1);
218     TouchMove(apzc, touchPos, mcc->Time());
219   }
220 
221   // Check that the portion of the touch-drag that occurred after
222   // the interruption caused additional scrolling.
223   CSSPoint finalScrollOffset = apzc->GetFrameMetrics().GetVisualScrollOffset();
224   EXPECT_GT(finalScrollOffset.y, scrollOffsetBeforeInterruption.y);
225 
226   // Now do the same thing, but for a visual scroll update.
227   scrollOffsetBeforeInterruption =
228       apzc->GetFrameMetrics().GetVisualScrollOffset();
229   mainThreadOffset = scrollOffsetBeforeInterruption;
230   mainThreadOffset.y -= 5;
231   metadata = apzc->GetScrollMetadata();
232   metadata.GetMetrics().SetVisualDestination(mainThreadOffset);
233   metadata.GetMetrics().SetScrollGeneration(ScrollGeneration::New());
234   metadata.GetMetrics().SetVisualScrollUpdateType(FrameMetrics::eMainThread);
235   scrollUpdates.Clear();
236   metadata.SetScrollUpdates(scrollUpdates);
237   apzc->NotifyLayersUpdated(metadata, false, true);
238   for (int i = 0; i < 20; ++i) {
239     touchPos.y -= 1;
240     mcc->AdvanceByMillis(1);
241     TouchMove(apzc, touchPos, mcc->Time());
242   }
243   finalScrollOffset = apzc->GetFrameMetrics().GetVisualScrollOffset();
244   EXPECT_GT(finalScrollOffset.y, scrollOffsetBeforeInterruption.y);
245 
246   // Clean up by ending the touch gesture.
247   mcc->AdvanceByMillis(1);
248   TouchUp(apzc, touchPos, mcc->Time());
249 }
250 #endif
251 
TEST_F(APZCBasicTester,RelativeScrollOffset)252 TEST_F(APZCBasicTester, RelativeScrollOffset) {
253   // Set up initial conditions: zoomed in, layout offset at (100, 100),
254   // visual offset at (120, 120); the relative offset is therefore (20, 20).
255   ScrollMetadata metadata;
256   FrameMetrics& metrics = metadata.GetMetrics();
257   metrics.SetScrollableRect(CSSRect(0, 0, 1000, 1000));
258   metrics.SetLayoutViewport(CSSRect(100, 100, 100, 100));
259   metrics.SetZoom(CSSToParentLayerScale2D(2.0, 2.0));
260   metrics.SetCompositionBounds(ParentLayerRect(0, 0, 100, 100));
261   metrics.SetVisualScrollOffset(CSSPoint(120, 120));
262   metrics.SetIsRootContent(true);
263   apzc->SetFrameMetrics(metrics);
264 
265   // Scroll the layout viewport to (200, 200).
266   ScrollMetadata mainThreadMetadata = metadata;
267   FrameMetrics& mainThreadMetrics = mainThreadMetadata.GetMetrics();
268   mainThreadMetrics.SetLayoutScrollOffset(CSSPoint(200, 200));
269   nsTArray<ScrollPositionUpdate> scrollUpdates;
270   scrollUpdates.AppendElement(ScrollPositionUpdate::NewScroll(
271       ScrollOrigin::Other, CSSPoint::ToAppUnits(CSSPoint(200, 200))));
272   mainThreadMetadata.SetScrollUpdates(scrollUpdates);
273   mainThreadMetrics.SetScrollGeneration(
274       scrollUpdates.LastElement().GetGeneration());
275   apzc->NotifyLayersUpdated(mainThreadMetadata, /*isFirstPaint=*/false,
276                             /*thisLayerTreeUpdated=*/true);
277 
278   // Check that the relative offset has been preserved.
279   metrics = apzc->GetFrameMetrics();
280   EXPECT_EQ(metrics.GetLayoutScrollOffset(), CSSPoint(200, 200));
281   EXPECT_EQ(metrics.GetVisualScrollOffset(), CSSPoint(220, 220));
282 }
283 
TEST_F(APZCBasicTester,MultipleSmoothScrollsSmooth)284 TEST_F(APZCBasicTester, MultipleSmoothScrollsSmooth) {
285   // We want to test that if we send multiple smooth scroll requests that we
286   // still smoothly animate, ie that we get non-zero change every frame while
287   // the animation is running.
288 
289   ScrollMetadata metadata;
290   FrameMetrics& metrics = metadata.GetMetrics();
291   metrics.SetScrollableRect(CSSRect(0, 0, 100, 10000));
292   metrics.SetLayoutViewport(CSSRect(0, 0, 100, 100));
293   metrics.SetZoom(CSSToParentLayerScale2D(1.0, 1.0));
294   metrics.SetCompositionBounds(ParentLayerRect(0, 0, 100, 100));
295   metrics.SetVisualScrollOffset(CSSPoint(0, 0));
296   metrics.SetIsRootContent(true);
297   apzc->SetFrameMetrics(metrics);
298 
299   // Structure of this test.
300   //   -send a pure relative smooth scroll request via NotifyLayersUpdated
301   //   -advance animations a few times, check that scroll offset is increasing
302   //    after the first few advances
303   //   -send a pure relative smooth scroll request via NotifyLayersUpdated
304   //   -advance animations a few times, check that scroll offset is increasing
305   //   -send a pure relative smooth scroll request via NotifyLayersUpdated
306   //   -advance animations a few times, check that scroll offset is increasing
307 
308   ScrollMetadata metadata2 = metadata;
309   nsTArray<ScrollPositionUpdate> scrollUpdates2;
310   scrollUpdates2.AppendElement(ScrollPositionUpdate::NewPureRelativeScroll(
311       ScrollOrigin::Other, ScrollMode::Smooth,
312       CSSPoint::ToAppUnits(CSSPoint(0, 200))));
313   metadata2.SetScrollUpdates(scrollUpdates2);
314   metadata2.GetMetrics().SetScrollGeneration(
315       scrollUpdates2.LastElement().GetGeneration());
316   apzc->NotifyLayersUpdated(metadata2, /*isFirstPaint=*/false,
317                             /*thisLayerTreeUpdated=*/true);
318 
319   // Get the animation going
320   for (uint32_t i = 0; i < 3; i++) {
321     SampleAnimationOneFrame();
322   }
323 
324   float offset =
325       apzc->GetCurrentAsyncScrollOffset(AsyncPanZoomController::eForCompositing)
326           .y;
327   ASSERT_GT(offset, 0);
328   float lastOffset = offset;
329 
330   for (uint32_t i = 0; i < 2; i++) {
331     for (uint32_t j = 0; j < 3; j++) {
332       SampleAnimationOneFrame();
333       offset = apzc->GetCurrentAsyncScrollOffset(
334                        AsyncPanZoomController::eForCompositing)
335                    .y;
336       ASSERT_GT(offset, lastOffset);
337       lastOffset = offset;
338     }
339 
340     ScrollMetadata metadata3 = metadata;
341     nsTArray<ScrollPositionUpdate> scrollUpdates3;
342     scrollUpdates3.AppendElement(ScrollPositionUpdate::NewPureRelativeScroll(
343         ScrollOrigin::Other, ScrollMode::Smooth,
344         CSSPoint::ToAppUnits(CSSPoint(0, 200))));
345     metadata3.SetScrollUpdates(scrollUpdates3);
346     metadata3.GetMetrics().SetScrollGeneration(
347         scrollUpdates3.LastElement().GetGeneration());
348     apzc->NotifyLayersUpdated(metadata3, /*isFirstPaint=*/false,
349                               /*thisLayerTreeUpdated=*/true);
350   }
351 
352   for (uint32_t j = 0; j < 7; j++) {
353     SampleAnimationOneFrame();
354     offset = apzc->GetCurrentAsyncScrollOffset(
355                      AsyncPanZoomController::eForCompositing)
356                  .y;
357     ASSERT_GT(offset, lastOffset);
358     lastOffset = offset;
359   }
360 }
361 
TEST_F(APZCBasicTester,ZoomAndScrollableRectChangeAfterZoomChange)362 TEST_F(APZCBasicTester, ZoomAndScrollableRectChangeAfterZoomChange) {
363   // We want to check that a small scrollable rect change (which causes us to
364   // reclamp our scroll position, including in the sampled state) does not move
365   // the scroll offset in the sample state based the zoom in the apzc, only
366   // based on the zoom in the sampled state.
367 
368   // First we zoom in to the right hand side. Then start zooming out, then send
369   // a scrollable rect change and check that it doesn't change the sampled state
370   // scroll offset.
371 
372   ScrollMetadata metadata;
373   FrameMetrics& metrics = metadata.GetMetrics();
374   metrics.SetCompositionBounds(ParentLayerRect(0, 0, 100, 100));
375   metrics.SetScrollableRect(CSSRect(0, 0, 100, 1000));
376   metrics.SetLayoutViewport(CSSRect(0, 0, 100, 100));
377   metrics.SetVisualScrollOffset(CSSPoint(0, 0));
378   metrics.SetZoom(CSSToParentLayerScale2D(1.0, 1.0));
379   metrics.SetIsRootContent(true);
380   apzc->SetFrameMetrics(metrics);
381 
382   MakeApzcZoomable();
383 
384   // Zoom to right side.
385   ZoomTarget zoomTarget{CSSRect(75, 25, 25, 25), Nothing()};
386   apzc->ZoomToRect(zoomTarget, 0);
387 
388   // Run the animation to completion, should take 250ms/16.67ms = 15 frames, but
389   // do extra to make sure.
390   for (uint32_t i = 0; i < 30; i++) {
391     SampleAnimationOneFrame();
392   }
393 
394   EXPECT_FALSE(apzc->IsAsyncZooming());
395 
396   // Zoom out.
397   ZoomTarget zoomTarget2{CSSRect(0, 0, 100, 100), Nothing()};
398   apzc->ZoomToRect(zoomTarget2, 0);
399 
400   // Run the animation a few times to get it going.
401   for (uint32_t i = 0; i < 2; i++) {
402     SampleAnimationOneFrame();
403   }
404 
405   // Check that it is decreasing in scale.
406   float prevScale =
407       apzc->GetCurrentPinchZoomScale(AsyncPanZoomController::eForCompositing)
408           .scale;
409   for (uint32_t i = 0; i < 2; i++) {
410     SampleAnimationOneFrame();
411     float scale =
412         apzc->GetCurrentPinchZoomScale(AsyncPanZoomController::eForCompositing)
413             .scale;
414     ASSERT_GT(prevScale, scale);
415     prevScale = scale;
416   }
417 
418   float offset =
419       apzc->GetCurrentAsyncScrollOffset(AsyncPanZoomController::eForCompositing)
420           .x;
421 
422   // Change the scrollable rect slightly to trigger a reclamp.
423   ScrollMetadata metadata2 = metadata;
424   metadata2.GetMetrics().SetScrollableRect(CSSRect(0, 0, 100, 1000.2));
425   apzc->NotifyLayersUpdated(metadata2, /*isFirstPaint=*/false,
426                             /*thisLayerTreeUpdated=*/true);
427 
428   float newOffset =
429       apzc->GetCurrentAsyncScrollOffset(AsyncPanZoomController::eForCompositing)
430           .x;
431 
432   ASSERT_EQ(newOffset, offset);
433 }
434 
TEST_F(APZCBasicTester,ZoomToRectAndCompositionBoundsChange)435 TEST_F(APZCBasicTester, ZoomToRectAndCompositionBoundsChange) {
436   // We want to check that content sending a composition bounds change (due to
437   // addition of scrollbars) during a zoom animation does not cause us to take
438   // the out of date content resolution.
439 
440   ScrollMetadata metadata;
441   FrameMetrics& metrics = metadata.GetMetrics();
442   metrics.SetCompositionBounds(ParentLayerRect(0, 0, 100, 100));
443   metrics.SetCompositionBoundsWidthIgnoringScrollbars(ParentLayerCoord{100});
444   metrics.SetScrollableRect(CSSRect(0, 0, 100, 1000));
445   metrics.SetLayoutViewport(CSSRect(0, 0, 100, 100));
446   metrics.SetVisualScrollOffset(CSSPoint(0, 0));
447   metrics.SetZoom(CSSToParentLayerScale2D(1.0, 1.0));
448   metrics.SetIsRootContent(true);
449   apzc->SetFrameMetrics(metrics);
450 
451   MakeApzcZoomable();
452 
453   // Start a zoom to a rect.
454   ZoomTarget zoomTarget{CSSRect(25, 25, 25, 25), Nothing()};
455   apzc->ZoomToRect(zoomTarget, 0);
456 
457   // Run the animation a few times to get it going.
458   // Check that it is increasing in scale.
459   float prevScale =
460       apzc->GetCurrentPinchZoomScale(AsyncPanZoomController::eForCompositing)
461           .scale;
462   for (uint32_t i = 0; i < 3; i++) {
463     SampleAnimationOneFrame();
464     float scale =
465         apzc->GetCurrentPinchZoomScale(AsyncPanZoomController::eForCompositing)
466             .scale;
467     ASSERT_GE(scale, prevScale);
468     prevScale = scale;
469   }
470 
471   EXPECT_TRUE(apzc->IsAsyncZooming());
472 
473   // Simulate the appearance of a scrollbar by reducing the width of
474   // the composition bounds, while keeping
475   // mCompositionBoundsWidthIgnoringScrollbars unchanged.
476   ScrollMetadata metadata2 = metadata;
477   metadata2.GetMetrics().SetCompositionBounds(ParentLayerRect(0, 0, 90, 100));
478   apzc->NotifyLayersUpdated(metadata2, /*isFirstPaint=*/false,
479                             /*thisLayerTreeUpdated=*/true);
480 
481   float scale =
482       apzc->GetCurrentPinchZoomScale(AsyncPanZoomController::eForCompositing)
483           .scale;
484 
485   ASSERT_EQ(scale, prevScale);
486 
487   // Run the rest of the animation to completion, should take 250ms/16.67ms = 15
488   // frames total, but do extra to make sure.
489   for (uint32_t i = 0; i < 30; i++) {
490     SampleAnimationOneFrame();
491     scale =
492         apzc->GetCurrentPinchZoomScale(AsyncPanZoomController::eForCompositing)
493             .scale;
494     ASSERT_GE(scale, prevScale);
495     prevScale = scale;
496   }
497 
498   EXPECT_FALSE(apzc->IsAsyncZooming());
499 }
500