123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217 |
- // Copyright 2018 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 "ash/wm/window_preview_view.h"
- #include "ash/constants/app_types.h"
- #include "ash/test/ash_test_base.h"
- #include "ash/wm/window_preview_view_test_api.h"
- #include "ui/aura/client/aura_constants.h"
- #include "ui/views/widget/widget.h"
- #include "ui/wm/core/window_util.h"
- namespace ash {
- namespace {
- using WindowPreviewViewTest = AshTestBase;
- // Creates and returns a widget whose type is the given |type|, which is added
- // as a transient child of the given |parent_widget|.
- std::unique_ptr<views::Widget> CreateTransientChild(
- views::Widget* parent_widget,
- views::Widget::InitParams::Type type) {
- auto widget = std::make_unique<views::Widget>();
- views::Widget::InitParams params{type};
- params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
- params.bounds = gfx::Rect{40, 50};
- params.context = params.parent = parent_widget->GetNativeWindow();
- params.init_properties_container.SetProperty(
- aura::client::kAppType, static_cast<int>(ash::AppType::ARC_APP));
- widget->Init(std::move(params));
- widget->Show();
- return widget;
- }
- // Test that if we have two widgets whos windows are linked together by
- // transience, WindowPreviewView's internal collection will contain both those
- // two windows.
- TEST_F(WindowPreviewViewTest, Basic) {
- auto widget1 = CreateTestWidget();
- auto widget2 = CreateTestWidget();
- ::wm::AddTransientChild(widget1->GetNativeWindow(),
- widget2->GetNativeWindow());
- auto preview_view = std::make_unique<WindowPreviewView>(
- widget1->GetNativeWindow(), /*trilinear_filtering_on_init=*/false);
- WindowPreviewViewTestApi test_api(preview_view.get());
- EXPECT_EQ(2u, test_api.GetMirrorViews().size());
- EXPECT_TRUE(test_api.GetMirrorViews().contains(widget1->GetNativeWindow()));
- EXPECT_TRUE(test_api.GetMirrorViews().contains(widget2->GetNativeWindow()));
- }
- // Tests that the preview view preferred size is the same aspect ratio as the
- // window's non client view.
- TEST_F(WindowPreviewViewTest, AspectRatio) {
- // Default frame header is 32dp, so we expect a window of size 300, 300 to
- // have a preview of 1:1 ratio.
- auto window = CreateAppWindow(gfx::Rect(300, 332));
- auto preview_view = std::make_unique<WindowPreviewView>(
- window.get(), /*trilinear_filtering_on_init=*/false);
- const gfx::SizeF preferred_size(preview_view->GetPreferredSize());
- EXPECT_EQ(1.f, preferred_size.width() / preferred_size.height());
- }
- // Tests that WindowPreviewView behaves as expected when we add or remove
- // transient children.
- TEST_F(WindowPreviewViewTest, TransientChildAddedAndRemoved) {
- auto widget1 = CreateTestWidget();
- auto widget2 = CreateTestWidget();
- auto widget3 = CreateTestWidget();
- ::wm::AddTransientChild(widget1->GetNativeWindow(),
- widget2->GetNativeWindow());
- auto preview_view = std::make_unique<WindowPreviewView>(
- widget1->GetNativeWindow(), /*trilinear_filtering_on_init=*/false);
- WindowPreviewViewTestApi test_api(preview_view.get());
- ASSERT_EQ(2u, test_api.GetMirrorViews().size());
- ::wm::AddTransientChild(widget1->GetNativeWindow(),
- widget3->GetNativeWindow());
- EXPECT_EQ(3u, test_api.GetMirrorViews().size());
- ::wm::RemoveTransientChild(widget1->GetNativeWindow(),
- widget3->GetNativeWindow());
- EXPECT_EQ(2u, test_api.GetMirrorViews().size());
- }
- // Tests that init'ing a Widget with a native window as a transient child before
- // it is parented to a parent window doesn't cause a crash while the
- // WindowPreviewView is observing transient windows additions.
- // https://crbug.com/1003544.
- TEST_F(WindowPreviewViewTest, NoCrashWithTransientChildWithNoWindowState) {
- auto widget1 = CreateTestWidget();
- auto transient_child1 = CreateTransientChild(
- widget1.get(), views::Widget::InitParams::TYPE_WINDOW);
- EXPECT_EQ(widget1->GetNativeWindow(),
- wm::GetTransientParent(transient_child1->GetNativeWindow()));
- auto preview_view = std::make_unique<WindowPreviewView>(
- widget1->GetNativeWindow(), /*trilinear_filtering_on_init=*/false);
- WindowPreviewViewTestApi test_api(preview_view.get());
- ASSERT_EQ(2u, test_api.GetMirrorViews().size());
- // The popup and bubble transient child should be ignored (they result in a
- // native window type WINDOW_TYPE_POPUP), while the TYPE_WINDOW one will be
- // added as a transient child before it is parented to a container. This
- // should not cause a crash.
- auto transient_child2 = CreateTransientChild(
- widget1.get(), views::Widget::InitParams::TYPE_POPUP);
- auto transient_child3 = CreateTransientChild(
- widget1.get(), views::Widget::InitParams::TYPE_BUBBLE);
- auto transient_child4 = CreateTransientChild(
- widget1.get(), views::Widget::InitParams::TYPE_WINDOW);
- EXPECT_EQ(widget1->GetNativeWindow(),
- wm::GetTransientParent(transient_child2->GetNativeWindow()));
- EXPECT_EQ(widget1->GetNativeWindow(),
- wm::GetTransientParent(transient_child3->GetNativeWindow()));
- EXPECT_EQ(widget1->GetNativeWindow(),
- wm::GetTransientParent(transient_child4->GetNativeWindow()));
- EXPECT_EQ(3u, test_api.GetMirrorViews().size());
- transient_child3.reset();
- EXPECT_EQ(3u, test_api.GetMirrorViews().size());
- transient_child4.reset();
- EXPECT_EQ(2u, test_api.GetMirrorViews().size());
- }
- // Tests that if cycling stops before a transient popup child is destroyed
- // doesn't introduce a crash. https://crbug.com/1014543.
- TEST_F(WindowPreviewViewTest,
- NoCrashWhenWindowCyclingIsCanceledWithATransientPopup) {
- auto widget1 = CreateTestWidget();
- auto preview_view = std::make_unique<WindowPreviewView>(
- widget1->GetNativeWindow(), /*trilinear_filtering_on_init=*/false);
- WindowPreviewViewTestApi test_api(preview_view.get());
- ASSERT_EQ(1u, test_api.GetMirrorViews().size());
- auto transient_popup = CreateTransientChild(
- widget1.get(), views::Widget::InitParams::TYPE_POPUP);
- ASSERT_EQ(1u, test_api.GetMirrorViews().size());
- // Simulate canceling window cycling now, there should be no crashes.
- preview_view.reset();
- }
- TEST_F(WindowPreviewViewTest, LayoutChildWithinParentBounds) {
- UpdateDisplay("1000x900");
- // Create two widgets linked transiently. The child window is within the
- // bounds of the parent window.
- auto widget1 = CreateTestWidget();
- auto widget2 = CreateTestWidget();
- widget1->GetNativeWindow()->SetBounds(gfx::Rect(0, -20, 100, 120));
- widget1->GetNativeWindow()->SetProperty(aura::client::kTopViewInset, 20);
- widget2->GetNativeWindow()->SetBounds(gfx::Rect(20, 20, 50, 50));
- widget2->GetNativeWindow()->SetProperty(aura::client::kTopViewInset, 10);
- ::wm::AddTransientChild(widget1->GetNativeWindow(),
- widget2->GetNativeWindow());
- // The top inset is excluded from GetUnionRect() calculations.
- auto preview_view = std::make_unique<WindowPreviewView>(
- widget1->GetNativeWindow(), /*trilinear_filtering_on_init=*/false);
- WindowPreviewViewTestApi test_api(preview_view.get());
- EXPECT_EQ(gfx::RectF(100.f, 100.f), test_api.GetUnionRect());
- // Test that the ratio between the two windows is maintained.
- preview_view->SetBoundsRect(gfx::Rect(500, 500));
- EXPECT_EQ(gfx::Rect(500, 500),
- test_api.GetMirrorViewForWidget(widget1.get())->bounds());
- // The original rect (20, 20, 50, 50) should now be (100, 100, 250, 250).
- // However, the top inset of 10 is now 50, and is excluded from calculations.
- EXPECT_EQ(gfx::Rect(100, 150, 250, 200),
- test_api.GetMirrorViewForWidget(widget2.get())->bounds());
- }
- // Test that WindowPreviewView layouts the transient tree correctly when each
- // transient child is outside the bounds of its transient parent.
- TEST_F(WindowPreviewViewTest, LayoutChildOutsideParentBounds) {
- UpdateDisplay("1000x900");
- // Create two widgets linked transiently. The child window is outside of the
- // bounds of the parent window.
- auto widget1 = CreateTestWidget();
- auto widget2 = CreateTestWidget();
- widget1->GetNativeWindow()->SetBounds(gfx::Rect(0, -20, 200, 220));
- widget1->GetNativeWindow()->SetProperty(aura::client::kTopViewInset, 20);
- widget2->GetNativeWindow()->SetBounds(gfx::Rect(300, 300, 100, 100));
- widget2->GetNativeWindow()->SetProperty(aura::client::kTopViewInset, 20);
- ::wm::AddTransientChild(widget1->GetNativeWindow(),
- widget2->GetNativeWindow());
- // Get the union rect of the two windows. The top inset is excluded from
- // calculations.
- auto preview_view = std::make_unique<WindowPreviewView>(
- widget1->GetNativeWindow(), /*trilinear_filtering_on_init=*/false);
- WindowPreviewViewTestApi test_api(preview_view.get());
- EXPECT_EQ(gfx::RectF(400.f, 400.f), test_api.GetUnionRect());
- // Test that the ratio between the two windows, relative to the smallest
- // rectangle which encompasses them both (0, 0, 400, 400) is maintained. The
- // first window is positioned at the origin, the second window is positioned
- // such that it is 25% larger and the bottom right corner is aligned with
- // |preview_view|'s bottom right corner.
- preview_view->SetBoundsRect(gfx::Rect(500, 500));
- EXPECT_EQ(gfx::Rect(250, 250),
- test_api.GetMirrorViewForWidget(widget1.get())->bounds());
- EXPECT_EQ(gfx::Rect(375, 400, 125, 100),
- test_api.GetMirrorViewForWidget(widget2.get())->bounds());
- }
- } // namespace
- } // namespace ash
|