// 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 "ui/aura/window_occlusion_change_builder.h" #include #include "third_party/skia/include/core/SkRegion.h" #include "ui/aura/test/aura_test_base.h" #include "ui/aura/test/test_window_delegate.h" #include "ui/aura/test/test_windows.h" namespace aura { namespace { // A delegate that remembers the occlusion info of its window. class OcclusionTrackWindowDelegate : public test::TestWindowDelegate { public: OcclusionTrackWindowDelegate() = default; ~OcclusionTrackWindowDelegate() override = default; void set_window(Window* window) { window_ = window; } bool occlusion_change_count() const { return occlusion_change_count_; } Window::OcclusionState last_occlusion_state() const { return last_occlusion_state_; } const SkRegion& last_occluded_region() const { return last_occluded_region_; } private: // test::TestWindowDelegate: void OnWindowOcclusionChanged( Window::OcclusionState occlusion_state) override { ++occlusion_change_count_; last_occlusion_state_ = occlusion_state; last_occluded_region_ = window_->occluded_region_in_root(); } Window* window_ = nullptr; int occlusion_change_count_ = 0; Window::OcclusionState last_occlusion_state_ = Window::OcclusionState::UNKNOWN; SkRegion last_occluded_region_; DISALLOW_COPY_AND_ASSIGN(OcclusionTrackWindowDelegate); }; } // namespace class WindowOcclusionChangeBuilderTest : public test::AuraTestBase { public: WindowOcclusionChangeBuilderTest() = default; ~WindowOcclusionChangeBuilderTest() override = default; std::unique_ptr CreateTestWindow( OcclusionTrackWindowDelegate* delegate) { auto window = std::make_unique(delegate); delegate->set_window(window.get()); window->set_owned_by_parent(false); window->SetType(client::WINDOW_TYPE_NORMAL); window->Init(ui::LAYER_TEXTURED); window->Show(); root_window()->AddChild(window.get()); return window; } private: DISALLOW_COPY_AND_ASSIGN(WindowOcclusionChangeBuilderTest); }; // Test that window occlusion info is updated after commit. TEST_F(WindowOcclusionChangeBuilderTest, SingleWindow) { SkRegion region; region.setRect({1, 2, 3, 4}); for (const auto state : {Window::OcclusionState::VISIBLE, Window::OcclusionState::OCCLUDED, Window::OcclusionState::HIDDEN}) { OcclusionTrackWindowDelegate delegate; auto window = CreateTestWindow(&delegate); auto builder = WindowOcclusionChangeBuilder::Create(); builder->Add(window.get(), state, region); // Change should not be applied before Commit call. EXPECT_EQ(0, delegate.occlusion_change_count()); // All changes are committed when builder is released. builder.reset(); EXPECT_EQ(1, delegate.occlusion_change_count()); EXPECT_EQ(state, delegate.last_occlusion_state()); EXPECT_EQ(region, delegate.last_occluded_region()); } } // Test updating multiple windows. TEST_F(WindowOcclusionChangeBuilderTest, MultipleWindow) { auto builder = WindowOcclusionChangeBuilder::Create(); OcclusionTrackWindowDelegate delegate1; auto window1 = CreateTestWindow(&delegate1); const Window::OcclusionState state1 = Window::OcclusionState::VISIBLE; SkRegion region1; region1.setRect({1, 2, 3, 4}); builder->Add(window1.get(), state1, region1); OcclusionTrackWindowDelegate delegate2; auto window2 = CreateTestWindow(&delegate2); const Window::OcclusionState state2 = Window::OcclusionState::OCCLUDED; SkRegion region2; region2.setRect({5, 6, 7, 8}); builder->Add(window2.get(), state2, region2); // Changes should not be applied before Commit call. EXPECT_EQ(0, delegate1.occlusion_change_count()); EXPECT_EQ(0, delegate2.occlusion_change_count()); // All changes are committed when builder is released. builder.reset(); EXPECT_EQ(1, delegate1.occlusion_change_count()); EXPECT_EQ(state1, delegate1.last_occlusion_state()); EXPECT_EQ(region1, delegate1.last_occluded_region()); EXPECT_EQ(1, delegate2.occlusion_change_count()); EXPECT_EQ(state2, delegate2.last_occlusion_state()); EXPECT_EQ(region2, delegate2.last_occluded_region()); } // Tests that the last change wins when there are multiple changes on the same // window. TEST_F(WindowOcclusionChangeBuilderTest, MultipleChanges) { OcclusionTrackWindowDelegate delegate; auto window = CreateTestWindow(&delegate); auto builder = WindowOcclusionChangeBuilder::Create(); builder->Add(window.get(), Window::OcclusionState::VISIBLE, SkRegion()); builder->Add(window.get(), Window::OcclusionState::HIDDEN, SkRegion()); SkRegion region; region.setRect({1, 2, 3, 4}); builder->Add(window.get(), Window::OcclusionState::OCCLUDED, region); // All changes are committed when builder is released. builder.reset(); EXPECT_EQ(1, delegate.occlusion_change_count()); EXPECT_EQ(Window::OcclusionState::OCCLUDED, delegate.last_occlusion_state()); EXPECT_EQ(region, delegate.last_occluded_region()); } // Test that occlusion info is not updated if window is destroyed before commit. TEST_F(WindowOcclusionChangeBuilderTest, DestroyBeforeCommit) { OcclusionTrackWindowDelegate delegate; auto window = CreateTestWindow(&delegate); auto builder = WindowOcclusionChangeBuilder::Create(); builder->Add(window.get(), Window::OcclusionState::VISIBLE, SkRegion()); // Destroy window before applying the changes. window.reset(); // All changes are committed when builder is released. builder.reset(); // Occlusion info is not updated. EXPECT_EQ(0, delegate.occlusion_change_count()); } } // namespace aura