1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "ui/views/animation/compositor_animation_runner.h"
6
7 #include "base/test/bind.h"
8 #include "base/timer/timer.h"
9 #include "ui/compositor/test/draw_waiter_for_test.h"
10 #include "ui/compositor/throughput_tracker.h"
11 #include "ui/gfx/animation/linear_animation.h"
12 #include "ui/views/animation/animation_delegate_views.h"
13 #include "ui/views/buildflags.h"
14 #include "ui/views/test/widget_test.h"
15
16 namespace views {
17 namespace test {
18 namespace {
19 constexpr base::TimeDelta kDuration = base::TimeDelta::FromMilliseconds(100);
20 }
21
22 using CompositorAnimationRunnerTest = WidgetTest;
23
TEST_F(CompositorAnimationRunnerTest,BasicCoverageTest)24 TEST_F(CompositorAnimationRunnerTest, BasicCoverageTest) {
25 WidgetAutoclosePtr widget(CreateTopLevelPlatformWidget());
26 widget->Show();
27
28 AnimationDelegateViews delegate(widget->GetContentsView());
29 gfx::LinearAnimation animation(
30 kDuration, gfx::LinearAnimation::kDefaultFrameRate, &delegate);
31
32 base::RepeatingTimer interval_timer;
33 base::RunLoop run_loop;
34
35 animation.Start();
36 EXPECT_TRUE(animation.is_animating());
37 EXPECT_TRUE(delegate.container()->has_custom_animation_runner());
38
39 interval_timer.Start(FROM_HERE, kDuration, base::BindLambdaForTesting([&]() {
40 if (animation.is_animating())
41 return;
42
43 interval_timer.Stop();
44 run_loop.Quit();
45 }));
46
47 run_loop.Run();
48 }
49
50 namespace {
51
52 // Test AnimationDelegateView which has a non-zero expected animation duration
53 // time, which is required for getting smoothness reports.
54 class TestAnimationDelegateViews : public AnimationDelegateViews {
55 public:
TestAnimationDelegateViews(View * view)56 explicit TestAnimationDelegateViews(View* view)
57 : AnimationDelegateViews(view) {}
58 TestAnimationDelegateViews(TestAnimationDelegateViews&) = delete;
59 TestAnimationDelegateViews& operator=(TestAnimationDelegateViews&) = delete;
60 ~TestAnimationDelegateViews() override = default;
61
62 // AnimationDelegateViews:
GetAnimationDurationForReporting() const63 base::TimeDelta GetAnimationDurationForReporting() const override {
64 return kDuration;
65 }
66 };
67
68 } // namespace
69
70 // Tests that ui::ThroughputTracker will report for gfx::Animation.
TEST_F(CompositorAnimationRunnerTest,ThroughputTracker)71 TEST_F(CompositorAnimationRunnerTest, ThroughputTracker) {
72 WidgetAutoclosePtr widget(CreateTopLevelPlatformWidget());
73 widget->Show();
74
75 ui::DrawWaiterForTest::WaitForCompositingStarted(widget->GetCompositor());
76
77 int report_count = 0;
78 int report_count2 = 0;
79
80 TestAnimationDelegateViews delegate(widget->GetContentsView());
81
82 gfx::LinearAnimation animation(
83 kDuration, gfx::LinearAnimation::kDefaultFrameRate, &delegate);
84
85 base::RepeatingTimer interval_timer;
86 base::RunLoop run_loop;
87
88 ui::ThroughputTracker tracker1 =
89 widget->GetCompositor()->RequestNewThroughputTracker();
90 tracker1.Start(base::BindLambdaForTesting(
91 [&](const cc::FrameSequenceMetrics::CustomReportData& data) {
92 ++report_count;
93 run_loop.Quit();
94 }));
95
96 animation.Start();
97 EXPECT_TRUE(animation.is_animating());
98 EXPECT_TRUE(delegate.container()->has_custom_animation_runner());
99
100 interval_timer.Start(FROM_HERE, kDuration, base::BindLambdaForTesting([&]() {
101 if (animation.is_animating())
102 return;
103
104 interval_timer.Stop();
105 tracker1.Stop();
106 }));
107 run_loop.Run();
108 EXPECT_EQ(1, report_count);
109 EXPECT_EQ(0, report_count2);
110
111 // Tests that switching metrics reporters for the next animation works as
112 // expected.
113 base::RunLoop run_loop2;
114
115 ui::ThroughputTracker tracker2 =
116 widget->GetCompositor()->RequestNewThroughputTracker();
117 tracker2.Start(base::BindLambdaForTesting(
118 [&](const cc::FrameSequenceMetrics::CustomReportData& data) {
119 ++report_count2;
120 run_loop2.Quit();
121 }));
122
123 animation.Start();
124 EXPECT_TRUE(animation.is_animating());
125
126 interval_timer.Start(FROM_HERE, kDuration, base::BindLambdaForTesting([&]() {
127 if (animation.is_animating())
128 return;
129
130 interval_timer.Stop();
131 tracker2.Stop();
132 }));
133 run_loop2.Run();
134 EXPECT_EQ(1, report_count);
135 EXPECT_EQ(1, report_count2);
136 }
137
138 // No DesktopAura on ChromeOS.
139 // Each widget on MACOSX has its own ui::Compositor.
140 #if BUILDFLAG(ENABLE_DESKTOP_AURA)
141 using CompositorAnimationRunnerDesktopTest = DesktopWidgetTest;
142
TEST_F(CompositorAnimationRunnerDesktopTest,SwitchCompositor)143 TEST_F(CompositorAnimationRunnerDesktopTest, SwitchCompositor) {
144 WidgetAutoclosePtr widget1(CreateTopLevelNativeWidget());
145 widget1->Show();
146
147 WidgetAutoclosePtr widget2(CreateTopLevelNativeWidget());
148 widget2->Show();
149
150 ASSERT_NE(widget1->GetCompositor(), widget2->GetCompositor());
151
152 Widget* child = CreateChildNativeWidgetWithParent(widget1.get());
153 child->Show();
154 AnimationDelegateViews delegate(child->GetContentsView());
155 gfx::LinearAnimation animation(
156 kDuration, gfx::LinearAnimation::kDefaultFrameRate, &delegate);
157
158 base::RepeatingTimer interval_timer;
159
160 animation.Start();
161 EXPECT_TRUE(animation.is_animating());
162 EXPECT_TRUE(delegate.container()->has_custom_animation_runner());
163 {
164 base::RunLoop run_loop;
165 interval_timer.Start(FROM_HERE, kDuration,
166 base::BindLambdaForTesting([&]() {
167 if (animation.is_animating())
168 return;
169 interval_timer.Stop();
170 run_loop.Quit();
171 }));
172 run_loop.Run();
173 }
174
175 EXPECT_FALSE(animation.is_animating());
176
177 Widget::ReparentNativeView(child->GetNativeView(), widget2->GetNativeView());
178 widget1.reset();
179
180 animation.Start();
181 EXPECT_TRUE(animation.is_animating());
182 EXPECT_TRUE(delegate.container()->has_custom_animation_runner());
183
184 {
185 base::RunLoop run_loop;
186 interval_timer.Start(FROM_HERE, kDuration,
187 base::BindLambdaForTesting([&]() {
188 if (animation.is_animating())
189 return;
190
191 interval_timer.Stop();
192 run_loop.Quit();
193 }));
194
195 run_loop.Run();
196 }
197 }
198 #endif
199
200 } // namespace test
201 } // namespace views
202