blob: 8b20337e434b1b63f9c9abfbb9fc24a227c2e60d [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/views/animation/compositor_animation_runner.h"
#include "base/test/bind.h"
#include "base/timer/timer.h"
#include "ui/compositor/test/draw_waiter_for_test.h"
#include "ui/compositor/throughput_tracker.h"
#include "ui/gfx/animation/linear_animation.h"
#include "ui/views/animation/animation_delegate_views.h"
#include "ui/views/buildflags.h"
#include "ui/views/test/widget_test.h"
namespace views {
namespace test {
namespace {
constexpr base::TimeDelta kDuration = base::TimeDelta::FromMilliseconds(100);
}
using CompositorAnimationRunnerTest = WidgetTest;
TEST_F(CompositorAnimationRunnerTest, BasicCoverageTest) {
WidgetAutoclosePtr widget(CreateTopLevelPlatformWidget());
widget->Show();
AnimationDelegateViews delegate(widget->GetContentsView());
gfx::LinearAnimation animation(
kDuration, gfx::LinearAnimation::kDefaultFrameRate, &delegate);
base::RepeatingTimer interval_timer;
base::RunLoop run_loop;
animation.Start();
EXPECT_TRUE(animation.is_animating());
EXPECT_TRUE(delegate.container()->has_custom_animation_runner());
interval_timer.Start(FROM_HERE, kDuration, base::BindLambdaForTesting([&]() {
if (animation.is_animating())
return;
interval_timer.Stop();
run_loop.Quit();
}));
run_loop.Run();
}
namespace {
// Test AnimationDelegateView which has a non-zero expected animation duration
// time, which is required for getting smoothness reports.
class TestAnimationDelegateViews : public AnimationDelegateViews {
public:
explicit TestAnimationDelegateViews(View* view)
: AnimationDelegateViews(view) {}
TestAnimationDelegateViews(TestAnimationDelegateViews&) = delete;
TestAnimationDelegateViews& operator=(TestAnimationDelegateViews&) = delete;
~TestAnimationDelegateViews() override = default;
// AnimationDelegateViews:
base::TimeDelta GetAnimationDurationForReporting() const override {
return kDuration;
}
};
} // namespace
// Tests that ui::ThroughputTracker will report for gfx::Animation.
TEST_F(CompositorAnimationRunnerTest, ThroughputTracker) {
WidgetAutoclosePtr widget(CreateTopLevelPlatformWidget());
widget->Show();
ui::DrawWaiterForTest::WaitForCompositingStarted(widget->GetCompositor());
int report_count = 0;
int report_count2 = 0;
TestAnimationDelegateViews delegate(widget->GetContentsView());
gfx::LinearAnimation animation(
kDuration, gfx::LinearAnimation::kDefaultFrameRate, &delegate);
base::RepeatingTimer interval_timer;
base::RunLoop run_loop;
ui::ThroughputTracker tracker1 =
widget->GetCompositor()->RequestNewThroughputTracker();
tracker1.Start(base::BindLambdaForTesting(
[&](const cc::FrameSequenceMetrics::CustomReportData& data) {
++report_count;
run_loop.Quit();
}));
animation.Start();
EXPECT_TRUE(animation.is_animating());
EXPECT_TRUE(delegate.container()->has_custom_animation_runner());
interval_timer.Start(FROM_HERE, kDuration, base::BindLambdaForTesting([&]() {
if (animation.is_animating())
return;
interval_timer.Stop();
tracker1.Stop();
}));
run_loop.Run();
EXPECT_EQ(1, report_count);
EXPECT_EQ(0, report_count2);
// Tests that switching metrics reporters for the next animation works as
// expected.
base::RunLoop run_loop2;
ui::ThroughputTracker tracker2 =
widget->GetCompositor()->RequestNewThroughputTracker();
tracker2.Start(base::BindLambdaForTesting(
[&](const cc::FrameSequenceMetrics::CustomReportData& data) {
++report_count2;
run_loop2.Quit();
}));
animation.Start();
EXPECT_TRUE(animation.is_animating());
interval_timer.Start(FROM_HERE, kDuration, base::BindLambdaForTesting([&]() {
if (animation.is_animating())
return;
interval_timer.Stop();
tracker2.Stop();
}));
run_loop2.Run();
EXPECT_EQ(1, report_count);
EXPECT_EQ(1, report_count2);
}
// No DesktopAura on ChromeOS.
// Each widget on MACOSX has its own ui::Compositor.
#if BUILDFLAG(ENABLE_DESKTOP_AURA)
using CompositorAnimationRunnerDesktopTest = DesktopWidgetTest;
TEST_F(CompositorAnimationRunnerDesktopTest, SwitchCompositor) {
WidgetAutoclosePtr widget1(CreateTopLevelNativeWidget());
widget1->Show();
WidgetAutoclosePtr widget2(CreateTopLevelNativeWidget());
widget2->Show();
ASSERT_NE(widget1->GetCompositor(), widget2->GetCompositor());
Widget* child = CreateChildNativeWidgetWithParent(widget1.get());
child->Show();
AnimationDelegateViews delegate(child->GetContentsView());
gfx::LinearAnimation animation(
kDuration, gfx::LinearAnimation::kDefaultFrameRate, &delegate);
base::RepeatingTimer interval_timer;
animation.Start();
EXPECT_TRUE(animation.is_animating());
EXPECT_TRUE(delegate.container()->has_custom_animation_runner());
{
base::RunLoop run_loop;
interval_timer.Start(FROM_HERE, kDuration,
base::BindLambdaForTesting([&]() {
if (animation.is_animating())
return;
interval_timer.Stop();
run_loop.Quit();
}));
run_loop.Run();
}
EXPECT_FALSE(animation.is_animating());
Widget::ReparentNativeView(child->GetNativeView(), widget2->GetNativeView());
widget1.reset();
animation.Start();
EXPECT_TRUE(animation.is_animating());
EXPECT_TRUE(delegate.container()->has_custom_animation_runner());
{
base::RunLoop run_loop;
interval_timer.Start(FROM_HERE, kDuration,
base::BindLambdaForTesting([&]() {
if (animation.is_animating())
return;
interval_timer.Stop();
run_loop.Quit();
}));
run_loop.Run();
}
}
#endif
} // namespace test
} // namespace views