chromium/ui/aura/window_occlusion_tracker_unittest.cc

// Copyright 2017 The Chromium Authors
// 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_tracker.h"

#include "base/functional/callback_helpers.h"
#include "base/memory/raw_ptr.h"
#include "base/run_loop.h"
#include "base/test/bind.h"
#include "base/test/gtest_util.h"
#include "base/test/scoped_feature_list.h"
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/aura/env.h"
#include "ui/aura/test/aura_test_base.h"
#include "ui/aura/test/test_window_delegate.h"
#include "ui/aura/test/test_windows.h"
#include "ui/aura/test/window_occlusion_tracker_test_api.h"
#include "ui/aura/window_observer.h"
#include "ui/aura/window_occlusion_change_builder.h"
#include "ui/base/ui_base_features.h"
#include "ui/compositor/layer.h"
#include "ui/compositor/layer_animation_observer.h"
#include "ui/compositor/layer_animation_sequence.h"
#include "ui/compositor/layer_animator.h"
#include "ui/compositor/scoped_animation_duration_scale_mode.h"
#include "ui/compositor/scoped_layer_animation_settings.h"
#include "ui/compositor/test/layer_animator_test_controller.h"
#include "ui/gfx/interpolated_transform.h"

namespace aura {

namespace {

constexpr base::TimeDelta kTransitionDuration =;

class FakeWindowOcclusionChangeBuilder : public WindowOcclusionChangeBuilder {};

class MockWindowDelegate : public test::ColorTestWindowDelegate {};

class WindowOcclusionTrackerTest : public test::AuraTestBase {};

SkRegion SkRegionFromSkIRects(std::initializer_list<SkIRect> rects) {}

}  // namespace

// Verify that non-overlapping windows have a VISIBLE occlusion state.
// _____  _____
// |    | |    |
// |____| |____|
TEST_F(WindowOcclusionTrackerTest, NonOverlappingWindows) {}

// Verify that partially overlapping windows have a VISIBLE occlusion state.
// ______
// |__|  |
// |_____|
TEST_F(WindowOcclusionTrackerTest, PartiallyOverlappingWindow) {}

// Verify that a window whose bounds are covered by a hidden window is not
// occluded. Also, verify that calling Show() on the hidden window causes
// occlusion states to be recomputed.
//  __....     ... = hidden window
// |__|  .
// .......
TEST_F(WindowOcclusionTrackerTest, HiddenWindowCoversWindow) {}

class WindowOcclusionTrackerOpacityTest
    : public WindowOcclusionTrackerTest,
      public testing::WithParamInterface<bool> {};

// Verify that a window whose bounds are covered by a semi-transparent window is
// not occluded. Also, verify that that when the opacity of a window changes,
// occlusion states are updated.
//  __....     ... = semi-transparent window
// |__|  .
// .......
TEST_P(WindowOcclusionTrackerOpacityTest, SemiTransparentWindowCoversWindow) {}

// Same as previous test, but the occlusion state of the semi-transparent is not
// tracked.
TEST_P(WindowOcclusionTrackerOpacityTest,
       SemiTransparentUntrackedWindowCoversWindow) {}

// Verify that one window whose bounds are covered by a set of two opaque
// windows is occluded.
//  ______
// |  |  |  <-- these two windows cover another window
// |__|__|
TEST_F(WindowOcclusionTrackerTest, TwoWindowsOccludeOneWindow) {}

// Verify that a window and its child that are covered by a sibling are
// occluded.
TEST_F(WindowOcclusionTrackerTest, SiblingOccludesWindowAndChild) {}

// Verify that a window with one half covered by a child and the other half
// covered by a sibling is non-occluded.
TEST_F(WindowOcclusionTrackerTest, ChildAndSiblingOccludeOneWindow) {}

// Verify that a window covered by 2 non-occluded children is non-occluded.
TEST_F(WindowOcclusionTrackerTest, ChildrenOccludeOneWindow) {}

// Verify that when the bounds of a child window covers the bounds of a parent
// window but is itself visible, the parent window is visible.
TEST_F(WindowOcclusionTrackerTest, ChildDoesNotOccludeParent) {}

// Verify that when the stacking order of windows change, occlusion states are
// updated.
TEST_F(WindowOcclusionTrackerTest, StackingChanged) {}

// Verify that when the stacking order of two transparent window changes, the
// occlusion states of their children is updated. The goal of this test is to
// ensure that the fact that the windows whose stacking order change are
// transparent doesn't prevent occlusion states from being recomputed.
TEST_F(WindowOcclusionTrackerTest, TransparentParentStackingChanged) {}

// Verify that when StackChildAtTop() is called on a window whose occlusion
// state is not tracked, the occlusion state of tracked siblings is updated.
TEST_F(WindowOcclusionTrackerTest, UntrackedWindowStackingChanged) {}

// Verify that occlusion states are updated when the bounds of a window change.
TEST_F(WindowOcclusionTrackerTest, BoundsChanged) {}

// Verify that when the bounds of a window are animated, occlusion states are
// updated at the beginning and at the end of the animation, but not during the
// animation. At the beginning of the animation, the window animated window
// should be considered non-occluded and should not occlude other windows. The
// animated window starts occluded.
TEST_F(WindowOcclusionTrackerTest, OccludedWindowBoundsAnimated) {}

// Same as the previous test, but the animated window starts non-occluded.
TEST_F(WindowOcclusionTrackerTest, NonOccludedWindowBoundsAnimated) {}

// Verify that occlusion states are updated when the bounds of a transparent
// window with opaque children change.
TEST_F(WindowOcclusionTrackerTest, TransparentParentBoundsChanged) {}

// Verify that occlusion states are updated when the bounds of a window whose
// occlusion state is not tracked change.
TEST_F(WindowOcclusionTrackerTest, UntrackedWindowBoundsChanged) {}

// Verify that occlusion states are updated when the transform of a window
// changes.
TEST_F(WindowOcclusionTrackerTest, TransformChanged) {}

// Verify that when the transform of a window is animated, occlusion states are
// updated at the beginning and at the end of the animation, but not during the
// animation. At the beginning of the animation, the window animated window
// should be considered non-occluded and should not occlude other windows. The
// animated window starts occluded.
TEST_F(WindowOcclusionTrackerTest, OccludedWindowTransformAnimated) {}

// Same as the previous test, but the animated window starts non-occluded.
TEST_F(WindowOcclusionTrackerTest, NonOccludedWindowTransformAnimated) {}

// Verify that occlusion states are updated when the transform of a transparent
// window with opaque children change.
TEST_F(WindowOcclusionTrackerTest, TransparentParentTransformChanged) {}

// Verify that occlusion states are updated when the transform of a window whose
// occlusion state is not tracked changes.
TEST_F(WindowOcclusionTrackerTest, UntrackedWindowTransformChanged) {}

// Verify that deleting an untracked window which covers a tracked window causes
// the tracked window to be non-occluded.
TEST_F(WindowOcclusionTrackerTest, DeleteUntrackedWindow) {}

// Verify that removing an untracked window which covers a tracked window causes
// the tracked window to be non-occluded.
TEST_F(WindowOcclusionTrackerTest, RemoveUntrackedWindow) {}

// Verify that when a tracked window is removed and re-added to a root,
// occlusion states are still tracked.
TEST_F(WindowOcclusionTrackerTest, RemoveAndAddTrackedToRoot) {}

namespace {

class ResizeWindowObserver : public WindowObserver {};

}  // namespace

// Verify that when the bounds of a child window are updated in response to the
// bounds of a parent window being updated, occlusion states are updated once.
TEST_F(WindowOcclusionTrackerTest, ResizeChildFromObserver) {}

// Verify that the bounds of windows are changed multiple times within the scope
// of a ScopedPause, occlusion states are updated once at the end of the scope.
TEST_F(WindowOcclusionTrackerTest, ScopedPause) {}

// Same as the previous test, but with nested ScopedPause.
TEST_F(WindowOcclusionTrackerTest, NestedScopedPause) {}

// Verify that bounds are computed correctly when a hierarchy of windows have
// transforms.
TEST_F(WindowOcclusionTrackerTest, HierarchyOfTransforms) {}

// Verify that clipping is taken into account when computing occlusion.
TEST_F(WindowOcclusionTrackerTest, Clipping) {}

// Verify that the DCHECK(!WindowIsAnimated(window)) in
// WindowOcclusionTracker::OnWindowDestroyed() doesn't fire if a window is
// destroyed with an incomplete animation (~Window should complete the animation
// and the window should be removed from |animated_windows_| before
// OnWindowDestroyed() is called).
TEST_F(WindowOcclusionTrackerTest, DestroyWindowWithPendingAnimation) {}

// Verify that `WindowOcclusionTracker` can be destroyed safely with a pending
// animation. This mostly applies to secondary `WindowOcclusionTracker`s,
// not the long-lived one in `aura::Env`.
TEST_F(WindowOcclusionTrackerTest,
       DestroyOcclusionTrackerWithPendingAnimation) {}

// Verify that an animated window stops being considered as animated when its
// layer is recreated.
TEST_F(WindowOcclusionTrackerTest, RecreateLayerOfAnimatedWindow) {}

namespace {

class ObserverChangingWindowBounds : public WindowObserver {};

}  // namespace

// Verify that no crash occurs if a tracked window is modified by an observer
// after it has been added to a new root but before WindowOcclusionTracker has
// been notified.
TEST_F(WindowOcclusionTrackerTest, ChangeTrackedWindowBeforeObserveAddToRoot) {}

namespace {

class ObserverDestroyingWindowOnAnimationEnded
    : public ui::LayerAnimationObserver {};

}  // namespace

// Verify that no crash occurs if a LayerAnimationObserver destroys a tracked
// window before WindowOcclusionTracker is notified that the animation ended.
TEST_P(WindowOcclusionTrackerOpacityTest,
       DestroyTrackedWindowFromLayerAnimationObserver) {}

// Verify that no crash occurs if an animation completes on a non-tracked
// window's layer after the window has been removed from a root with a tracked
// window and deleted.
TEST_P(WindowOcclusionTrackerOpacityTest,
       DeleteNonTrackedAnimatedWindowRemovedFromTrackedRoot) {}

TEST_P(WindowOcclusionTrackerOpacityTest,
       OpacityAnimationShouldNotOccludeWindow) {}

namespace {

class WindowDelegateHidingWindowIfOccluded : public MockWindowDelegate {};

class WindowDelegateWithQueuedExpectation : public MockWindowDelegate {};

}  // namespace

// Verify that a window delegate can change the visibility of another window
// when it is notified that its occlusion changed.
TEST_F(WindowOcclusionTrackerTest, HideFromOnWindowOcclusionChanged) {}

namespace {

class WindowDelegateDeletingWindow : public MockWindowDelegate {};

}  // namespace

// Verify that a window can delete a window that is on top of it when it is
// notified that its occlusion changed (a crash would occur if
// WindowOcclusionTracker accessed that window after it was deleted).
TEST_F(WindowOcclusionTrackerTest, DeleteFromOnWindowOcclusionChanged) {}

namespace {

class WindowDelegateChangingWindowVisibility : public MockWindowDelegate {};

}  // namespace

// Verify that if a window changes its visibility every time it is notified that
// its occlusion state changed, a DCHECK occurs.
TEST_F(WindowOcclusionTrackerTest, OcclusionStatesDontBecomeStable) {}

// Verify that the occlusion states are correctly updated when a branch of the
// tree is hidden.
TEST_F(WindowOcclusionTrackerTest, HideTreeBranch) {}

// Verify that a window covered by a shaped window isn't considered occluded.
TEST_F(WindowOcclusionTrackerTest, WindowWithAlphaShape) {}

// Verify that a window covered by a window whose parent has an alpha shape
// isn't considered occluded.
TEST_F(WindowOcclusionTrackerTest, WindowWithParentAlphaShape) {}

namespace {

class WindowDelegateHidingWindow : public MockWindowDelegate {};

class WindowDelegateAddingAndHidingChild : public MockWindowDelegate {};

}  // namespace

// Verify that hiding a window that has a hidden parent doesn't cause occlusion
// to be recomputed.
TEST_F(WindowOcclusionTrackerTest,
       HideWindowWithHiddenParentOnOcclusionChange) {}

// Verify that hiding a window changes the occlusion region to show that the
// window is fully occluded.
TEST_F(WindowOcclusionTrackerTest,
       HideWindowChangesOcclusionRegionToBeFullyOccluded) {}

// Test partial occlusion, test partial occlusion changing hidden, alpha shape
// occlusion from multiple windows

// Verify that a window can occlude another one partially.
TEST_F(WindowOcclusionTrackerTest, WindowOccludesWindowPartially) {}

// Verify that windows with alpha shape do not affect occlusion regions.
TEST_F(WindowOcclusionTrackerTest,
       WindowWithAlphaShapeDoesNotPartiallyOccludeOtherWindows) {}

// Verify that a window can be occluded by multiple other windows.
TEST_F(WindowOcclusionTrackerTest, WindowCanBeOccludedByMultipleWindows) {}

// Verify that the excluded window is indeed ignored by occlusion tracking.
TEST_P(WindowOcclusionTrackerOpacityTest, ExcludeWindow) {}

// Test that calling OnOcclusionStateChanged on a root window causes children
// of the root window to have their delegate notified that it is occluded or
// visible, depending on whether the root window is occluded or not.
TEST_F(WindowOcclusionTrackerTest, NativeWindowOcclusion) {}

TEST_F(WindowOcclusionTrackerTest, ScopedForceVisible) {}

TEST_F(WindowOcclusionTrackerTest, ScopedForceVisibleSiblingsIgnored) {}

TEST_F(WindowOcclusionTrackerTest, ScopedForceVisibleWithOccludedSibling) {}

// Simulates a scenario in which a browser window is forced visible (e.g. while
// projecting) and its parent container (e.g. a virtual desks container) was
// hidden. Verifies that the browser window and its descendants remain visible
// from an occlusion stand point.
TEST_F(WindowOcclusionTrackerTest, ScopedForceVisibleHiddenContainer) {}

TEST_F(WindowOcclusionTrackerTest, ComputeTargetOcclusionForWindow) {}

TEST_F(WindowOcclusionTrackerTest,
       ComputeTargetOcclusionForWindowUsesTargetBounds) {}

TEST_P(WindowOcclusionTrackerOpacityTest,
       ComputeTargetOcclusionForWindowUsesTargetOpacity) {}

TEST_F(WindowOcclusionTrackerTest,
       ComputeTargetOcclusionForWindowUsesTargetVisibility) {}

TEST_F(WindowOcclusionTrackerTest,
       ComputeTargetOcclusionForWindowTransformHierarchy) {}

TEST_F(WindowOcclusionTrackerTest, ComputeTargetOcclusionForAnimatedWindow) {}

TEST_F(WindowOcclusionTrackerTest,
       SetOpaqueRegionsForOcclusionAffectsOcclusionOfOtherWindows) {}

TEST_F(
    WindowOcclusionTrackerTest,
    SetOpaqueRegionsForOcclusionOfAWindowDoesNotAffectOcclusionOfThatWindowItself) {}

TEST_F(WindowOcclusionTrackerTest,
       SemiOpaqueSolidColorLayerDoesNotAffectChildOpacity) {}

TEST_F(WindowOcclusionTrackerTest, OccludedFractionalWindow) {}

TEST_F(WindowOcclusionTrackerTest, OccludingFractionalWindow) {}

TEST_F(WindowOcclusionTrackerTest, ClipToRootWindow) {}

// Run tests with LAYER_TEXTURE_LAYER type or LAYER_SOLID_COLOR type.
INSTANTIATE_TEST_SUITE_P();

}  // namespace aura