Commit 8dccc2d4 authored by Eliot Courtney's avatar Eliot Courtney Committed by Commit Bot

Track occluded region in WindowOcclusionTracker.

We would like to automatically trigger Picture-in-Picture when a certain amount
of the window is occluded. To do this, we need a way to know how much of a
window is occluded by other windows. This occlusion could come from multiple
windows, and an occlusion tracker for aura already exists. This CL extends the
existing occlusion tracking functionality to also track an occluded region for
tracked windows.


Bug: 883157
Bug: 841886
Bug: b/112668686
Bug: b/110011377
Test: unit test
Change-Id: I0d6618ab05109cc46af0cfd72ecc5cbca2f200d4
Reviewed-on: https://chromium-review.googlesource.com/c/1179433
Commit-Queue: Eliot Courtney <edcourtney@chromium.org>
Reviewed-by: default avatarSadrul Chowdhury <sadrul@chromium.org>
Reviewed-by: default avatarFrançois Doray <fdoray@chromium.org>
Cr-Commit-Position: refs/heads/master@{#604532}
parent b5f31e6c
......@@ -1127,7 +1127,8 @@ void WebContentsViewAura::OnWindowTargetVisibilityChanged(bool visible) {
}
void WebContentsViewAura::OnWindowOcclusionChanged(
aura::Window::OcclusionState occlusion_state) {
aura::Window::OcclusionState occlusion_state,
const SkRegion&) {
UpdateWebContentsVisibility();
}
......
......@@ -185,8 +185,8 @@ class CONTENT_EXPORT WebContentsViewAura
void OnWindowDestroying(aura::Window* window) override;
void OnWindowDestroyed(aura::Window* window) override;
void OnWindowTargetVisibilityChanged(bool visible) override;
void OnWindowOcclusionChanged(
aura::Window::OcclusionState occlusion_state) override;
void OnWindowOcclusionChanged(aura::Window::OcclusionState occlusion_state,
const SkRegion&) override;
bool HasHitTestMask() const override;
void GetHitTestMask(gfx::Path* mask) const override;
......
......@@ -88,8 +88,10 @@ void WindowDelegateImpl::OnWindowDestroyed(aura::Window* window) {
void WindowDelegateImpl::OnWindowTargetVisibilityChanged(bool visible) {}
void WindowDelegateImpl::OnWindowOcclusionChanged(
aura::Window::OcclusionState occlusion_state) {
aura::Window::OcclusionState occlusion_state,
const SkRegion&) {
ServerWindow* const server_window = ServerWindow::GetMayBeNull(window_);
// TODO: Send occluded region.
if (server_window)
server_window->owning_window_tree()->SendOcclusionState(window_);
}
......
......@@ -43,8 +43,8 @@ class COMPONENT_EXPORT(WINDOW_SERVICE) WindowDelegateImpl
void OnWindowDestroying(aura::Window* window) override;
void OnWindowDestroyed(aura::Window* window) override;
void OnWindowTargetVisibilityChanged(bool visible) override;
void OnWindowOcclusionChanged(
aura::Window::OcclusionState occlusion_state) override;
void OnWindowOcclusionChanged(aura::Window::OcclusionState occlusion_state,
const SkRegion& occluded_region) override;
bool HasHitTestMask() const override;
void GetHitTestMask(gfx::Path* mask) const override;
......
......@@ -791,7 +791,8 @@ void WindowPortMus::UpdateOcclusionState(Window::OcclusionState new_state) {
occlusion_state_before_hidden_.reset();
}
window_->SetOcclusionState(new_state);
// TODO: Support occlusion region tracking. See crbug.com/900568.
window_->SetOcclusionInfo(new_state, SkRegion());
}
void WindowPortMus::UpdateOcclusionStateAfterVisiblityChange(bool visible) {
......
......@@ -887,11 +887,14 @@ void Window::SetVisible(bool visible) {
NotifyWindowVisibilityChanged(this, visible);
}
void Window::SetOcclusionState(OcclusionState occlusion_state) {
if (occlusion_state != occlusion_state_) {
void Window::SetOcclusionInfo(OcclusionState occlusion_state,
const SkRegion& occluded_region) {
if (occlusion_state != occlusion_state_ ||
occluded_region_ != occluded_region) {
occlusion_state_ = occlusion_state;
occluded_region_ = occluded_region;
if (delegate_)
delegate_->OnWindowOcclusionChanged(occlusion_state);
delegate_->OnWindowOcclusionChanged(occlusion_state, occluded_region);
}
}
......
......@@ -202,6 +202,18 @@ class AURA_EXPORT Window : public ui::LayerDelegate,
// WindowOcclusionTracker::ScopedPause.
OcclusionState occlusion_state() const { return occlusion_state_; }
// Returns the currently occluded region. This will be empty unless
// the window is tracked and has a VISIBLE occlusion state. That is,
// this is only maintained when the window is partially occluded. Further,
// this region may extend outside the window bounds. For performance reasons,
// the actual intersection with the window is not computed. The occluded
// region is the set of window rectangles that may occlude this window.
// Note that this means that the occluded region may be updated if one of
// those windows moves, even if the actual intersection of the occluded
// region with this window does not change. Clients may compute the actual
// intersection region if necessary.
const SkRegion& occluded_region() const { return occluded_region_; }
// Returns the window's bounds in root window's coordinates.
gfx::Rect GetBoundsInRootWindow() const;
......@@ -487,8 +499,9 @@ class AURA_EXPORT Window : public ui::LayerDelegate,
// specific changes. Called from Show()/Hide().
void SetVisible(bool visible);
// Updates the occlusion state of the window.
void SetOcclusionState(OcclusionState occlusion_state);
// Updates the occlusion info of the window.
void SetOcclusionInfo(OcclusionState occlusion_state,
const SkRegion& occluded_region);
// Schedules a paint for the Window's entire bounds.
void SchedulePaint();
......@@ -624,6 +637,9 @@ class AURA_EXPORT Window : public ui::LayerDelegate,
// Occlusion state of the window.
OcclusionState occlusion_state_;
// Occluded region of the window.
SkRegion occluded_region_;
int id_;
// The FrameSinkId associated with this window. If this window is embedding
......
......@@ -86,11 +86,12 @@ class AURA_EXPORT WindowDelegate : public ui::EventHandler {
// Window::TargetVisibility() for details.
virtual void OnWindowTargetVisibilityChanged(bool visible) = 0;
// Called when the occlusion state of the Window changes while tracked (see
// WindowOcclusionTracker::Track). |occlusion_state| is the new occlusion
// state of the Window.
virtual void OnWindowOcclusionChanged(
Window::OcclusionState occlusion_state) {}
// Called when the occlusion state or occluded region of the Window changes
// while tracked (see WindowOcclusionTracker::Track). |occlusion_state| is
// the new occlusion state of the Window. |occluded_region| is the new
// occluded region of the Window.
virtual void OnWindowOcclusionChanged(Window::OcclusionState occlusion_state,
const SkRegion& occluded_region) {}
// Called from Window::HitTest to check if the window has a custom hit test
// mask. It works similar to the views counterparts. That is, if the function
......
......@@ -85,17 +85,6 @@ SkIRect GetWindowBoundsInRootWindow(
return skirect_bounds;
}
// Returns true iff the occlusion states in |tracked_windows| match those
// returned by Window::occlusion_state().
bool OcclusionStatesMatch(
const base::flat_map<Window*, Window::OcclusionState>& tracked_windows) {
for (const auto& tracked_window : tracked_windows) {
if (tracked_window.second != tracked_window.first->occlusion_state())
return false;
}
return true;
}
} // namespace
WindowOcclusionTracker::ScopedPause::ScopedPause(Env* env) : env_(env) {
......@@ -110,8 +99,7 @@ void WindowOcclusionTracker::Track(Window* window) {
DCHECK(window);
DCHECK(window != window->GetRootWindow());
auto insert_result =
tracked_windows_.insert({window, Window::OcclusionState::UNKNOWN});
auto insert_result = tracked_windows_.insert({window, {}});
DCHECK(insert_result.second);
if (!window_observer_.IsObserving(window))
window_observer_.Add(window);
......@@ -123,6 +111,16 @@ WindowOcclusionTracker::WindowOcclusionTracker() = default;
WindowOcclusionTracker::~WindowOcclusionTracker() = default;
bool WindowOcclusionTracker::OcclusionStatesMatch(
const base::flat_map<Window*, OcclusionData>& tracked_windows) {
for (const auto& tracked_window : tracked_windows) {
if (tracked_window.second.occlusion_state !=
tracked_window.first->occlusion_state())
return false;
}
return true;
}
void WindowOcclusionTracker::MaybeComputeOcclusion() {
if (num_pause_occlusion_tracking_ ||
num_times_occlusion_recomputed_in_current_step_ != 0) {
......@@ -133,7 +131,7 @@ void WindowOcclusionTracker::MaybeComputeOcclusion() {
&num_times_occlusion_recomputed_in_current_step_, 0);
// Recompute occlusion states until either:
// - They are stable, i.e. calling Window::SetOcclusionState() on all tracked
// - They are stable, i.e. calling Window::SetOcclusionInfo() on all tracked
// windows does not provoke changes that could affect occlusion.
// - Occlusion states have been recomputed
// |kMaxComputeOcclusionIterationsBeforeStable|
......@@ -150,7 +148,7 @@ void WindowOcclusionTracker::MaybeComputeOcclusion() {
bool found_dirty_root = false;
// Compute occlusion states and store them in |tracked_windows_|. Do not
// call Window::SetOcclusionState() in this phase to prevent changes to the
// call Window::SetOcclusionInfo() in this phase to prevent changes to the
// window tree while it is being traversed.
for (auto& root_window_pair : root_windows_) {
if (root_window_pair.second.dirty) {
......@@ -170,7 +168,7 @@ void WindowOcclusionTracker::MaybeComputeOcclusion() {
++num_times_occlusion_recomputed_;
++num_times_occlusion_recomputed_in_current_step_;
// Call Window::SetOcclusionState() on tracked windows. A WindowDelegate may
// Call Window::SetOcclusionInfo() on tracked windows. A WindowDelegate may
// change the window tree in response to this.
WindowTracker tracked_windows_list;
for (const auto& tracked_window : tracked_windows_)
......@@ -180,15 +178,20 @@ void WindowOcclusionTracker::MaybeComputeOcclusion() {
Window* window = tracked_windows_list.Pop();
auto it = tracked_windows_.find(window);
if (it != tracked_windows_.end() &&
it->second != Window::OcclusionState::UNKNOWN) {
it->second.occlusion_state != Window::OcclusionState::UNKNOWN) {
// Fallback to VISIBLE/HIDDEN if the maximum number of times that
// occlusion can be recomputed was exceeded.
if (exceeded_max_num_times_occlusion_recomputed) {
it->second = window->IsVisible() ? Window::OcclusionState::VISIBLE
: Window::OcclusionState::HIDDEN;
if (window->IsVisible()) {
it->second.occlusion_state = Window::OcclusionState::VISIBLE;
} else {
it->second.occlusion_state = Window::OcclusionState::HIDDEN;
}
it->second.occluded_region = SkRegion();
}
window->SetOcclusionState(it->second);
window->SetOcclusionInfo(it->second.occlusion_state,
it->second.occluded_region);
}
}
}
......@@ -232,19 +235,22 @@ bool WindowOcclusionTracker::RecomputeOcclusionImpl(
const SkIRect* clipped_bounds_for_children =
window->layer()->GetMasksToBounds() ? &window_bounds : clipped_bounds;
bool has_visible_child = false;
SkRegion occluded_region_before_traversing_children = *occluded_region;
for (auto* child : base::Reversed(window->children())) {
has_visible_child |=
RecomputeOcclusionImpl(child, transform_relative_to_root,
clipped_bounds_for_children, occluded_region);
}
// Compute window occlusion state.
if (occluded_region->contains(window_bounds)) {
SetOccluded(window, !has_visible_child);
return has_visible_child;
// Window is fully occluded.
if (occluded_region->contains(window_bounds) && !has_visible_child) {
SetOccluded(window, true, SkRegion());
return false;
}
SetOccluded(window, false);
// Window is partially occluded or unoccluded.
SetOccluded(window, false, occluded_region_before_traversing_children);
if (VisibleWindowIsOpaque(window))
occluded_region->op(window_bounds, SkRegion::kUnion_Op);
return true;
......@@ -303,22 +309,31 @@ bool WindowOcclusionTracker::MaybeObserveAnimatedWindow(Window* window) {
void WindowOcclusionTracker::SetWindowAndDescendantsAreOccluded(
Window* window,
bool is_occluded) {
SetOccluded(window, is_occluded);
SetOccluded(window, is_occluded, SkRegion());
for (Window* child_window : window->children())
SetWindowAndDescendantsAreOccluded(child_window, is_occluded);
}
void WindowOcclusionTracker::SetOccluded(Window* window, bool is_occluded) {
void WindowOcclusionTracker::SetOccluded(Window* window,
bool is_occluded,
const SkRegion& occluded_region) {
auto tracked_window = tracked_windows_.find(window);
if (tracked_window == tracked_windows_.end())
return;
// Set the occluded region of the window.
tracked_window->second.occluded_region = occluded_region;
if (!window->IsVisible())
tracked_window->second = Window::OcclusionState::HIDDEN;
tracked_window->second.occlusion_state = Window::OcclusionState::HIDDEN;
else if (is_occluded)
tracked_window->second = Window::OcclusionState::OCCLUDED;
tracked_window->second.occlusion_state = Window::OcclusionState::OCCLUDED;
else
tracked_window->second = Window::OcclusionState::VISIBLE;
tracked_window->second.occlusion_state = Window::OcclusionState::VISIBLE;
DCHECK(tracked_window->second.occlusion_state ==
Window::OcclusionState::VISIBLE ||
tracked_window->second.occluded_region.isEmpty());
}
bool WindowOcclusionTracker::WindowIsTracked(Window* window) const {
......
......@@ -87,9 +87,22 @@ class AURA_EXPORT WindowOcclusionTracker : public ui::LayerAnimationObserver,
bool dirty = false;
};
// Holds occlusion related information for tracked windows.
struct OcclusionData {
// Occlusion state for a tracked window.
Window::OcclusionState occlusion_state = Window::OcclusionState::UNKNOWN;
// Region in root window coordinates that is occluded.
SkRegion occluded_region;
};
WindowOcclusionTracker();
~WindowOcclusionTracker() override;
// Returns true iff the occlusion states in |tracked_windows| match those
// returned by Window::occlusion_state().
static bool OcclusionStatesMatch(
const base::flat_map<Window*, OcclusionData>& tracked_windows);
// Recomputes the occlusion state of tracked windows under roots marked as
// dirty in |root_windows_| if there are no active ScopedPause instance.
void MaybeComputeOcclusion();
......@@ -126,9 +139,12 @@ class AURA_EXPORT WindowOcclusionTracker : public ui::LayerAnimationObserver,
void SetWindowAndDescendantsAreOccluded(Window* window, bool is_occluded);
// Updates the occlusion state of |window| in |tracked_windows_|, based on
// |is_occluded| and window->IsVisible(). No-op if |window| is not in
// |is_occluded| and window->IsVisible(). Updates the occluded region of
// |window| using |occluded_region|. No-op if |window| is not in
// |tracked_windows_|.
void SetOccluded(Window* window, bool is_occluded);
void SetOccluded(Window* window,
bool is_occluded,
const SkRegion& occluded_region);
// Returns true if |window| is in |tracked_windows_|.
bool WindowIsTracked(Window* window) const;
......@@ -214,8 +230,8 @@ class AURA_EXPORT WindowOcclusionTracker : public ui::LayerAnimationObserver,
Window* new_root) override;
void OnWindowLayerRecreated(Window* window) override;
// Windows whose occlusion state is tracked.
base::flat_map<Window*, Window::OcclusionState> tracked_windows_;
// Windows whose occlusion data is tracked.
base::flat_map<Window*, OcclusionData> tracked_windows_;
// Windows whose bounds or transform are animated.
//
......
......@@ -37,24 +37,30 @@ class MockWindowDelegate : public test::ColorTestWindowDelegate {
void set_window(Window* window) { window_ = window; }
void set_expectation(Window::OcclusionState expectation) {
expectation_ = expectation;
void set_expectation(Window::OcclusionState occlusion_state,
const SkRegion& occluded_region) {
expected_occlusion_state_ = occlusion_state;
expected_occluded_region_ = occluded_region;
}
bool is_expecting_call() const {
return expectation_ != Window::OcclusionState::UNKNOWN;
return expected_occlusion_state_ != Window::OcclusionState::UNKNOWN;
}
void OnWindowOcclusionChanged(
Window::OcclusionState occlusion_state) override {
void OnWindowOcclusionChanged(Window::OcclusionState occlusion_state,
const SkRegion& occluded_region) override {
ASSERT_TRUE(window_);
EXPECT_NE(occlusion_state, Window::OcclusionState::UNKNOWN);
EXPECT_EQ(occlusion_state, expectation_);
expectation_ = Window::OcclusionState::UNKNOWN;
EXPECT_EQ(occlusion_state, expected_occlusion_state_);
EXPECT_EQ(occluded_region, expected_occluded_region_);
expected_occlusion_state_ = Window::OcclusionState::UNKNOWN;
expected_occluded_region_ = SkRegion();
}
private:
Window::OcclusionState expectation_ = Window::OcclusionState::UNKNOWN;
Window::OcclusionState expected_occlusion_state_ =
Window::OcclusionState::UNKNOWN;
SkRegion expected_occluded_region_ = SkRegion();
Window* window_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(MockWindowDelegate);
......@@ -92,6 +98,12 @@ class WindowOcclusionTrackerTest : public test::AuraTestBase {
DISALLOW_COPY_AND_ASSIGN(WindowOcclusionTrackerTest);
};
SkRegion SkRegionFromSkIRects(std::initializer_list<SkIRect> rects) {
SkRegion r;
r.setRects(rects.begin(), rects.size());
return r;
}
} // namespace
// Verify that non-overlapping windows have a VISIBLE occlusion state.
......@@ -100,13 +112,16 @@ class WindowOcclusionTrackerTest : public test::AuraTestBase {
// |____| |____|
TEST_F(WindowOcclusionTrackerTest, NonOverlappingWindows) {
MockWindowDelegate* delegate_a = new MockWindowDelegate();
delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
MockWindowDelegate* delegate_b = new MockWindowDelegate();
delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE,
SkRegion(SkIRect::MakeXYWH(15, 0, 10, 10)));
delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_b, gfx::Rect(15, 0, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
}
......@@ -116,13 +131,16 @@ TEST_F(WindowOcclusionTrackerTest, NonOverlappingWindows) {
// |_____|
TEST_F(WindowOcclusionTrackerTest, PartiallyOverlappingWindow) {
MockWindowDelegate* delegate_a = new MockWindowDelegate();
delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
MockWindowDelegate* delegate_b = new MockWindowDelegate();
delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE,
SkRegion(SkIRect::MakeWH(5, 5)));
delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_b, gfx::Rect(0, 0, 5, 5));
EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
}
......@@ -135,31 +153,31 @@ TEST_F(WindowOcclusionTrackerTest, PartiallyOverlappingWindow) {
TEST_F(WindowOcclusionTrackerTest, HiddenWindowCoversWindow) {
// Create window a. Expect it to be non-occluded.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
// Create window b. Expect it to be non-occluded and expect window a to be
// occluded.
MockWindowDelegate* delegate_b = new MockWindowDelegate();
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED);
delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_b = CreateTrackedWindow(delegate_b, gfx::Rect(0, 0, 15, 15));
EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
// Hide window b. Expect window a to be non-occluded and window b to be
// occluded.
delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
delegate_b->set_expectation(Window::OcclusionState::HIDDEN);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
delegate_b->set_expectation(Window::OcclusionState::HIDDEN, SkRegion());
window_b->Hide();
EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
// Show window b. Expect window a to be occluded and window b to be non-
// occluded.
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED);
delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
window_b->Show();
EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
......@@ -174,15 +192,15 @@ TEST_F(WindowOcclusionTrackerTest, HiddenWindowCoversWindow) {
TEST_F(WindowOcclusionTrackerTest, SemiTransparentWindowCoversWindow) {
// Create window a. Expect it to be non-occluded.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
// Create window b. Expect it to be non-occluded and expect window a to be
// occluded.
MockWindowDelegate* delegate_b = new MockWindowDelegate();
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED);
delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_b = CreateTrackedWindow(delegate_b, gfx::Rect(0, 0, 15, 15));
EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
......@@ -190,13 +208,13 @@ TEST_F(WindowOcclusionTrackerTest, SemiTransparentWindowCoversWindow) {
// Change the opacity of window b to 0.5f. Expect both windows to be non-
// occluded.
EXPECT_FALSE(delegate_a->is_expecting_call());
delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
window_b->layer()->SetOpacity(0.5f);
EXPECT_FALSE(delegate_a->is_expecting_call());
// Change the opacity of window b back to 1.0f. Expect window a to be
// occluded.
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED);
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
window_b->layer()->SetOpacity(1.0f);
EXPECT_FALSE(delegate_a->is_expecting_call());
}
......@@ -206,24 +224,24 @@ TEST_F(WindowOcclusionTrackerTest, SemiTransparentWindowCoversWindow) {
TEST_F(WindowOcclusionTrackerTest, SemiTransparentUntrackedWindowCoversWindow) {
// Create window a. Expect it to be non-occluded.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
// Create untracked window b. Expect window a to be occluded.
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED);
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
Window* window_b = CreateUntrackedWindow(gfx::Rect(0, 0, 15, 15));
EXPECT_FALSE(delegate_a->is_expecting_call());
// Change the opacity of window b to 0.5f. Expect both windows to be non-
// occluded.
delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
window_b->layer()->SetOpacity(0.5f);
EXPECT_FALSE(delegate_a->is_expecting_call());
// Change the opacity of window b back to 1.0f. Expect window a to be
// occluded.
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED);
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
window_b->layer()->SetOpacity(1.0f);
EXPECT_FALSE(delegate_a->is_expecting_call());
}
......@@ -236,25 +254,31 @@ TEST_F(WindowOcclusionTrackerTest, SemiTransparentUntrackedWindowCoversWindow) {
TEST_F(WindowOcclusionTrackerTest, TwoWindowsOccludeOneWindow) {
// Create window a. Expect it to be non-occluded.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
// Create window b with bounds that partially cover window a. Expect both
// windows to be non-occluded.
MockWindowDelegate* delegate_b = new MockWindowDelegate();
delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE,
SkRegion(SkIRect::MakeWH(5, 10)));
delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_b, gfx::Rect(0, 0, 5, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
// Create window c with bounds that cover the portion of window a that isn't
// already covered by window b. Expect window a to be occluded and window a/b
// to be non-occluded.
MockWindowDelegate* delegate_c = new MockWindowDelegate();
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED);
delegate_c->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
delegate_b->set_expectation(Window::OcclusionState::VISIBLE,
SkRegion(SkIRect::MakeXYWH(5, 0, 5, 10)));
delegate_c->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_c, gfx::Rect(5, 0, 5, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
EXPECT_FALSE(delegate_c->is_expecting_call());
}
......@@ -263,23 +287,23 @@ TEST_F(WindowOcclusionTrackerTest, TwoWindowsOccludeOneWindow) {
TEST_F(WindowOcclusionTrackerTest, SiblingOccludesWindowAndChild) {
// Create window a. Expect it to be non-occluded.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_a = CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 20, 20));
EXPECT_FALSE(delegate_a->is_expecting_call());
// Create window b, with bounds that occlude half of its parent window a.
// Expect it to be non-occluded.
MockWindowDelegate* delegate_b = new MockWindowDelegate();
delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_b, gfx::Rect(0, 0, 10, 20), window_a);
EXPECT_FALSE(delegate_b->is_expecting_call());
// Create window c, with bounds that occlude window a and window b. Expect it
// to be non-occluded, and window a and b to be occluded.
MockWindowDelegate* delegate_c = new MockWindowDelegate();
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED);
delegate_b->set_expectation(Window::OcclusionState::OCCLUDED);
delegate_c->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
delegate_b->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
delegate_c->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_c, gfx::Rect(0, 0, 20, 20));
EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
......@@ -291,23 +315,28 @@ TEST_F(WindowOcclusionTrackerTest, SiblingOccludesWindowAndChild) {
TEST_F(WindowOcclusionTrackerTest, ChildAndSiblingOccludeOneWindow) {
// Create window a. Expect it to be non-occluded.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_a = CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 20, 20));
EXPECT_FALSE(delegate_a->is_expecting_call());
// Create window b, with bounds that occlude half of its parent window a.
// Expect it to be non-occluded.
MockWindowDelegate* delegate_b = new MockWindowDelegate();
delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_b, gfx::Rect(0, 0, 10, 20), window_a);
EXPECT_FALSE(delegate_b->is_expecting_call());
// Create window c, with bounds that occlude the other half of window a.
// Expect it to be non-occluded and expect window a to remain non-occluded.
MockWindowDelegate* delegate_c = new MockWindowDelegate();
delegate_c->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE,
SkRegion(SkIRect::MakeXYWH(10, 0, 10, 20)));
delegate_b->set_expectation(Window::OcclusionState::VISIBLE,
SkRegion(SkIRect::MakeXYWH(10, 0, 10, 20)));
delegate_c->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_c, gfx::Rect(10, 0, 10, 20));
EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
EXPECT_FALSE(delegate_c->is_expecting_call());
}
......@@ -315,22 +344,26 @@ TEST_F(WindowOcclusionTrackerTest, ChildAndSiblingOccludeOneWindow) {
TEST_F(WindowOcclusionTrackerTest, ChildrenOccludeOneWindow) {
// Create window a. Expect it to be non-occluded.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_a = CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 20, 20));
EXPECT_FALSE(delegate_a->is_expecting_call());
// Create window b, with bounds that cover half of its parent window a. Expect
// it to be non-occluded.
MockWindowDelegate* delegate_b = new MockWindowDelegate();
delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_b, gfx::Rect(0, 0, 10, 20), window_a);
EXPECT_FALSE(delegate_b->is_expecting_call());
EXPECT_FALSE(delegate_a->is_expecting_call());
// Create window c, with bounds that cover the other half of its parent window
// a. Expect it to be non-occluded. Expect window a to remain non-occluded.
MockWindowDelegate* delegate_c = new MockWindowDelegate();
delegate_c->set_expectation(Window::OcclusionState::VISIBLE);
delegate_b->set_expectation(Window::OcclusionState::VISIBLE,
SkRegion(SkIRect::MakeXYWH(10, 0, 10, 20)));
delegate_c->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_c, gfx::Rect(10, 0, 10, 20), window_a);
EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
EXPECT_FALSE(delegate_c->is_expecting_call());
}
......@@ -339,27 +372,35 @@ TEST_F(WindowOcclusionTrackerTest, ChildrenOccludeOneWindow) {
TEST_F(WindowOcclusionTrackerTest, ChildDoesNotOccludeParent) {
// Create window a. Expect it to be non-occluded.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_a = CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
// Create window b with window a as parent. The bounds of window b fully cover
// window a. Expect both windows to be non-occluded.
MockWindowDelegate* delegate_b = new MockWindowDelegate();
delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_b =
CreateTrackedWindow(delegate_b, gfx::Rect(0, 0, 10, 10), window_a);
EXPECT_FALSE(delegate_b->is_expecting_call());
// Create window c whose bounds don't overlap existing windows.
MockWindowDelegate* delegate_c = new MockWindowDelegate();
delegate_c->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE,
SkRegion(SkIRect::MakeXYWH(15, 0, 10, 10)));
delegate_b->set_expectation(Window::OcclusionState::VISIBLE,
SkRegion(SkIRect::MakeXYWH(15, 0, 10, 10)));
delegate_c->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_c = CreateTrackedWindow(delegate_c, gfx::Rect(15, 0, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
EXPECT_FALSE(delegate_c->is_expecting_call());
// Change the parent of window b from window a to window c. Expect all windows
// to remain non-occluded.
delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
window_c->AddChild(window_b);
EXPECT_FALSE(delegate_b->is_expecting_call());
}
// Verify that when the stacking order of windows change, occlusion states are
......@@ -368,28 +409,28 @@ TEST_F(WindowOcclusionTrackerTest, StackingChanged) {
// Create three windows that have the same bounds. Expect window on top of the
// stack to be non-occluded and other windows to be occluded.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_a = CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
MockWindowDelegate* delegate_b = new MockWindowDelegate();
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED);
delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_b, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
MockWindowDelegate* delegate_c = new MockWindowDelegate();
delegate_b->set_expectation(Window::OcclusionState::OCCLUDED);
delegate_c->set_expectation(Window::OcclusionState::VISIBLE);
delegate_b->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
delegate_c->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_c, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate_b->is_expecting_call());
EXPECT_FALSE(delegate_c->is_expecting_call());
// Move window a on top of the stack. Expect it to be non-occluded and expect
// window c to be occluded.
delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
delegate_c->set_expectation(Window::OcclusionState::OCCLUDED);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
delegate_c->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
root_window()->StackChildAtTop(window_a);
EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_c->is_expecting_call());
......@@ -402,7 +443,7 @@ TEST_F(WindowOcclusionTrackerTest, StackingChanged) {
TEST_F(WindowOcclusionTrackerTest, TransparentParentStackingChanged) {
// Create window a which is transparent. Expect it to be non-occluded.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_a = CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10),
root_window(), true);
EXPECT_FALSE(delegate_a->is_expecting_call());
......@@ -410,14 +451,14 @@ TEST_F(WindowOcclusionTrackerTest, TransparentParentStackingChanged) {
// Create window b which has the same bounds as its parent window a. Expect it
// to be non-occluded.
MockWindowDelegate* delegate_b = new MockWindowDelegate();
delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_b, gfx::Rect(0, 0, 10, 10), window_a);
EXPECT_FALSE(delegate_b->is_expecting_call());
// Create window c which is transparent and has the same bounds as window a
// and window b. Expect it to be non-occluded.
MockWindowDelegate* delegate_c = new MockWindowDelegate();
delegate_c->set_expectation(Window::OcclusionState::VISIBLE);
delegate_c->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_c = CreateTrackedWindow(delegate_c, gfx::Rect(0, 0, 10, 10),
root_window(), true);
EXPECT_FALSE(delegate_c->is_expecting_call());
......@@ -425,9 +466,9 @@ TEST_F(WindowOcclusionTrackerTest, TransparentParentStackingChanged) {
// Create window d which has the same bounds as its parent window c. Expect
// window d to be non-occluded and window a and b to be occluded.
MockWindowDelegate* delegate_d = new MockWindowDelegate();
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED);
delegate_b->set_expectation(Window::OcclusionState::OCCLUDED);
delegate_d->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
delegate_b->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
delegate_d->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_d, gfx::Rect(0, 0, 10, 10), window_c);
EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
......@@ -435,10 +476,10 @@ TEST_F(WindowOcclusionTrackerTest, TransparentParentStackingChanged) {
// Move window a on top of the stack. Expect window a and b to be non-occluded
// and window c and d to be occluded.
delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
delegate_c->set_expectation(Window::OcclusionState::OCCLUDED);
delegate_d->set_expectation(Window::OcclusionState::OCCLUDED);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
delegate_c->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
delegate_d->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
root_window()->StackChildAtTop(window_a);
EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
......@@ -453,12 +494,12 @@ TEST_F(WindowOcclusionTrackerTest, UntrackedWindowStackingChanged) {
// Create window b. Expect it to be non-occluded.
MockWindowDelegate* delegate_b = new MockWindowDelegate();
delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_b, gfx::Rect(0, 0, 5, 5));
EXPECT_FALSE(delegate_b->is_expecting_call());
// Stack window a on top of window b. Expect window b to be occluded.
delegate_b->set_expectation(Window::OcclusionState::OCCLUDED);
delegate_b->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
root_window()->StackChildAtTop(window_a);
EXPECT_FALSE(delegate_b->is_expecting_call());
}
......@@ -467,17 +508,20 @@ TEST_F(WindowOcclusionTrackerTest, UntrackedWindowStackingChanged) {
TEST_F(WindowOcclusionTrackerTest, BoundsChanged) {
// Create two non-overlapping windows. Expect them to be non-occluded.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_a = CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
MockWindowDelegate* delegate_b = new MockWindowDelegate();
delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE,
SkRegion(SkIRect::MakeXYWH(0, 10, 10, 10)));
delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_b = CreateTrackedWindow(delegate_b, gfx::Rect(0, 10, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
// Move window b on top of window a. Expect window a to be occluded.
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED);
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
window_b->SetBounds(window_a->bounds());
EXPECT_FALSE(delegate_a->is_expecting_call());
}
......@@ -498,26 +542,29 @@ TEST_F(WindowOcclusionTrackerTest, OccludedWindowBoundsAnimated) {
// Create 3 windows. Window a is unoccluded. Window c occludes window b.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_a = CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
MockWindowDelegate* delegate_b = new MockWindowDelegate();
delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE,
SkRegion(SkIRect::MakeXYWH(0, 10, 10, 10)));
delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_b = CreateTrackedWindow(delegate_b, gfx::Rect(0, 10, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
window_b->layer()->SetAnimator(test_controller.animator());
MockWindowDelegate* delegate_c = new MockWindowDelegate();
delegate_b->set_expectation(Window::OcclusionState::OCCLUDED);
delegate_c->set_expectation(Window::OcclusionState::VISIBLE);
delegate_b->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
delegate_c->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_c, gfx::Rect(0, 10, 10, 10));
EXPECT_FALSE(delegate_b->is_expecting_call());
EXPECT_FALSE(delegate_c->is_expecting_call());
// Start animating the bounds of window b so that it moves on top of window a.
// Window b should be non-occluded when the animation starts.
delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
window_b->SetBounds(window_a->bounds());
test_controller.Step(kTransitionDuration / 3);
EXPECT_FALSE(delegate_b->is_expecting_call());
......@@ -526,9 +573,13 @@ TEST_F(WindowOcclusionTrackerTest, OccludedWindowBoundsAnimated) {
test_controller.Step(kTransitionDuration / 3);
// Window b should occlude window a at the end of the animation.
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED);
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
// Window b should have window c in its potential occlusion region.
delegate_b->set_expectation(Window::OcclusionState::VISIBLE,
SkRegion(SkIRect::MakeXYWH(0, 10, 10, 10)));
test_controller.Step(kTransitionDuration / 3);
EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
window_b->layer()->SetAnimator(nullptr);
}
......@@ -545,18 +596,21 @@ TEST_F(WindowOcclusionTrackerTest, NonOccludedWindowBoundsAnimated) {
// Create 3 windows. Window a is unoccluded. Window c occludes window b.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_a = CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
MockWindowDelegate* delegate_b = new MockWindowDelegate();
delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE,
SkRegion(SkIRect::MakeXYWH(0, 10, 10, 10)));
delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_b, gfx::Rect(0, 10, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
MockWindowDelegate* delegate_c = new MockWindowDelegate();
delegate_b->set_expectation(Window::OcclusionState::OCCLUDED);
delegate_c->set_expectation(Window::OcclusionState::VISIBLE);
delegate_b->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
delegate_c->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_c = CreateTrackedWindow(delegate_c, gfx::Rect(0, 10, 10, 10));
EXPECT_FALSE(delegate_b->is_expecting_call());
EXPECT_FALSE(delegate_c->is_expecting_call());
......@@ -564,7 +618,7 @@ TEST_F(WindowOcclusionTrackerTest, NonOccludedWindowBoundsAnimated) {
// Start animating the bounds of window c so that it moves on top of window a.
// Window b should be non-occluded when the animation starts.
delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
window_c->SetBounds(window_a->bounds());
test_controller.Step(kTransitionDuration / 3);
EXPECT_FALSE(delegate_b->is_expecting_call());
......@@ -573,9 +627,13 @@ TEST_F(WindowOcclusionTrackerTest, NonOccludedWindowBoundsAnimated) {
test_controller.Step(kTransitionDuration / 3);
// Window c should occlude window a at the end of the animation.
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED);
// Window b should have a potentially occluded region including window c.
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
delegate_b->set_expectation(Window::OcclusionState::VISIBLE,
SkRegion(SkIRect::MakeXYWH(0, 0, 10, 10)));
test_controller.Step(kTransitionDuration / 3);
EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
window_c->layer()->SetAnimator(nullptr);
}
......@@ -585,14 +643,14 @@ TEST_F(WindowOcclusionTrackerTest, NonOccludedWindowBoundsAnimated) {
TEST_F(WindowOcclusionTrackerTest, TransparentParentBoundsChanged) {
// Create window a. Expect it to be non-occluded.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 5, 5));
EXPECT_FALSE(delegate_a->is_expecting_call());
// Create window b which doesn't overlap window a and is transparent. Expect
// it to be non-occluded.
MockWindowDelegate* delegate_b = new MockWindowDelegate();
delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_b = CreateTrackedWindow(delegate_b, gfx::Rect(0, 10, 10, 10),
root_window(), true);
EXPECT_FALSE(delegate_b->is_expecting_call());
......@@ -600,13 +658,16 @@ TEST_F(WindowOcclusionTrackerTest, TransparentParentBoundsChanged) {
// Create window c which has window b as parent and doesn't occlude any
// window.
MockWindowDelegate* delegate_c = new MockWindowDelegate();
delegate_c->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE,
SkRegion(SkIRect::MakeXYWH(0, 10, 5, 5)));
delegate_c->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_c, gfx::Rect(0, 0, 5, 5), window_b);
EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_c->is_expecting_call());
// Move window b so that window c occludes window a. Expect window a to be
// occluded and other windows to be non-occluded.
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED);
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
window_b->SetBounds(gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
}
......@@ -616,15 +677,18 @@ TEST_F(WindowOcclusionTrackerTest, TransparentParentBoundsChanged) {
TEST_F(WindowOcclusionTrackerTest, UntrackedWindowBoundsChanged) {
// Create window a. Expect it to be non-occluded.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_a = CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 5, 5));
EXPECT_FALSE(delegate_a->is_expecting_call());
// Create window b. It should not occlude window a.
delegate_a->set_expectation(Window::OcclusionState::VISIBLE,
SkRegion(SkIRect::MakeXYWH(0, 10, 5, 5)));
Window* window_b = CreateUntrackedWindow(gfx::Rect(0, 10, 5, 5));
EXPECT_FALSE(delegate_a->is_expecting_call());
// Move window b on top of window a. Expect window a to be occluded.
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED);
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
window_b->SetBounds(window_a->bounds());
EXPECT_FALSE(delegate_a->is_expecting_call());
}
......@@ -634,18 +698,21 @@ TEST_F(WindowOcclusionTrackerTest, UntrackedWindowBoundsChanged) {
TEST_F(WindowOcclusionTrackerTest, TransformChanged) {
// Create two non-overlapping windows. Expect them to be non-occluded.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
MockWindowDelegate* delegate_b = new MockWindowDelegate();
delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE,
SkRegion(SkIRect::MakeXYWH(0, 10, 5, 5)));
delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_b = CreateTrackedWindow(delegate_b, gfx::Rect(0, 10, 5, 5));
EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
// Scale and translate window b so that it covers window a. Expect window a to
// be occluded.
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED);
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
gfx::Transform transform;
transform.Translate(0.0f, -10.0f);
transform.Scale(2.0f, 2.0f);
......@@ -669,26 +736,29 @@ TEST_F(WindowOcclusionTrackerTest, OccludedWindowTransformAnimated) {
// Create 3 windows. Window a is unoccluded. Window c occludes window b.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
MockWindowDelegate* delegate_b = new MockWindowDelegate();
delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE,
SkRegion(SkIRect::MakeXYWH(0, 10, 5, 5)));
delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_b = CreateTrackedWindow(delegate_b, gfx::Rect(0, 10, 5, 5));
EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
window_b->layer()->SetAnimator(test_controller.animator());
MockWindowDelegate* delegate_c = new MockWindowDelegate();
delegate_b->set_expectation(Window::OcclusionState::OCCLUDED);
delegate_c->set_expectation(Window::OcclusionState::VISIBLE);
delegate_b->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
delegate_c->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_c, gfx::Rect(0, 10, 5, 5));
EXPECT_FALSE(delegate_b->is_expecting_call());
EXPECT_FALSE(delegate_c->is_expecting_call());
// Start animating the transform of window b so that it moves on top of window
// a. Window b should be non-occluded when the animation starts.
delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
auto transform = std::make_unique<ui::InterpolatedScale>(
gfx::Point3F(1, 1, 1), gfx::Point3F(2.0f, 2.0f, 1));
transform->SetChild(std::make_unique<ui::InterpolatedTranslation>(
......@@ -703,9 +773,13 @@ TEST_F(WindowOcclusionTrackerTest, OccludedWindowTransformAnimated) {
test_controller.Step(kTransitionDuration / 3);
// Window b should occlude window a at the end of the animation.
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED);
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
// Window b should see window c as part of the potential occlusion region.
delegate_b->set_expectation(Window::OcclusionState::VISIBLE,
SkRegion(SkIRect::MakeXYWH(0, 10, 5, 5)));
test_controller.Step(kTransitionDuration / 3);
EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
window_b->layer()->SetAnimator(nullptr);
}
......@@ -722,18 +796,21 @@ TEST_F(WindowOcclusionTrackerTest, NonOccludedWindowTransformAnimated) {
// Create 3 windows. Window a is unoccluded. Window c occludes window b.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 20, 20));
EXPECT_FALSE(delegate_a->is_expecting_call());
MockWindowDelegate* delegate_b = new MockWindowDelegate();
delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE,
SkRegion(SkIRect::MakeXYWH(0, 20, 10, 10)));
delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_b, gfx::Rect(0, 20, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
MockWindowDelegate* delegate_c = new MockWindowDelegate();
delegate_b->set_expectation(Window::OcclusionState::OCCLUDED);
delegate_c->set_expectation(Window::OcclusionState::VISIBLE);
delegate_b->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
delegate_c->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_c = CreateTrackedWindow(delegate_c, gfx::Rect(0, 20, 10, 10));
EXPECT_FALSE(delegate_b->is_expecting_call());
EXPECT_FALSE(delegate_c->is_expecting_call());
......@@ -741,7 +818,7 @@ TEST_F(WindowOcclusionTrackerTest, NonOccludedWindowTransformAnimated) {
// Start animating the bounds of window c so that it moves on top of window a.
// Window b should be non-occluded when the animation starts.
delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
auto transform = std::make_unique<ui::InterpolatedScale>(
gfx::Point3F(1, 1, 1), gfx::Point3F(2.0f, 2.0f, 1));
transform->SetChild(std::make_unique<ui::InterpolatedTranslation>(
......@@ -756,9 +833,13 @@ TEST_F(WindowOcclusionTrackerTest, NonOccludedWindowTransformAnimated) {
test_controller.Step(kTransitionDuration / 3);
// Window c should occlude window a at the end of the animation.
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED);
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
// Window b should now see window c in the potential occlusion region.
delegate_b->set_expectation(Window::OcclusionState::VISIBLE,
SkRegion(SkIRect::MakeWH(20, 20)));
test_controller.Step(kTransitionDuration / 3);
EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
window_c->layer()->SetAnimator(nullptr);
}
......@@ -768,14 +849,14 @@ TEST_F(WindowOcclusionTrackerTest, NonOccludedWindowTransformAnimated) {
TEST_F(WindowOcclusionTrackerTest, TransparentParentTransformChanged) {
// Create window a. Expect it to be non-occluded.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
// Create window b which doesn't overlap window a and is transparent. Expect
// it to be non-occluded.
MockWindowDelegate* delegate_b = new MockWindowDelegate();
delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_b = CreateTrackedWindow(delegate_b, gfx::Rect(0, 10, 10, 10),
root_window(), true);
EXPECT_FALSE(delegate_b->is_expecting_call());
......@@ -783,13 +864,16 @@ TEST_F(WindowOcclusionTrackerTest, TransparentParentTransformChanged) {
// Create window c which has window b as parent and doesn't occlude any
// window.
MockWindowDelegate* delegate_c = new MockWindowDelegate();
delegate_c->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE,
SkRegion(SkIRect::MakeXYWH(0, 10, 5, 5)));
delegate_c->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_c, gfx::Rect(0, 0, 5, 5), window_b);
EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_c->is_expecting_call());
// Scale and translate window b so that window c occludes window a. Expect
// window a to be occluded and other windows to be non-occluded.
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED);
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
gfx::Transform transform;
transform.Translate(0.0f, -10.0f);
transform.Scale(2.0f, 2.0f);
......@@ -802,16 +886,19 @@ TEST_F(WindowOcclusionTrackerTest, TransparentParentTransformChanged) {
TEST_F(WindowOcclusionTrackerTest, UntrackedWindowTransformChanged) {
// Create window a. Expect it to be non-occluded.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
// Create window b. It should not occlude window a.
delegate_a->set_expectation(Window::OcclusionState::VISIBLE,
SkRegion(SkIRect::MakeXYWH(0, 10, 5, 5)));
Window* window_b = CreateUntrackedWindow(gfx::Rect(0, 10, 5, 5));
EXPECT_FALSE(delegate_a->is_expecting_call());
// Scale and translate window b so that it occludes window a. Expect window a
// to be occluded.
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED);
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
gfx::Transform transform;
transform.Translate(0.0f, -10.0f);
transform.Scale(2.0f, 2.0f);
......@@ -824,17 +911,17 @@ TEST_F(WindowOcclusionTrackerTest, UntrackedWindowTransformChanged) {
TEST_F(WindowOcclusionTrackerTest, DeleteUntrackedWindow) {
// Create window a. Expect it to be non-occluded.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 5, 5));
EXPECT_FALSE(delegate_a->is_expecting_call());
// Create window b which occludes window a.
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED);
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
Window* window_b = CreateUntrackedWindow(gfx::Rect(0, 0, 5, 5));
EXPECT_FALSE(delegate_a->is_expecting_call());
// Delete window b. Expect a to be non-occluded.
delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
delete window_b;
EXPECT_FALSE(delegate_a->is_expecting_call());
}
......@@ -844,17 +931,17 @@ TEST_F(WindowOcclusionTrackerTest, DeleteUntrackedWindow) {
TEST_F(WindowOcclusionTrackerTest, RemoveUntrackedWindow) {
// Create window a. Expect it to be non-occluded.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 5, 5));
EXPECT_FALSE(delegate_a->is_expecting_call());
// Create window b which occludes window a.
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED);
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
Window* window_b = CreateUntrackedWindow(gfx::Rect(0, 0, 5, 5));
EXPECT_FALSE(delegate_a->is_expecting_call());
// Delete window b. Expect a to be non-occluded.
delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
root_window()->RemoveChild(window_b);
EXPECT_FALSE(delegate_a->is_expecting_call());
delete window_b;
......@@ -864,7 +951,7 @@ TEST_F(WindowOcclusionTrackerTest, RemoveUntrackedWindow) {
TEST_F(WindowOcclusionTrackerTest, CustomizedWindowHasContent) {
// Create window a. Expect it to be non-occluded.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
......@@ -876,7 +963,7 @@ TEST_F(WindowOcclusionTrackerTest, CustomizedWindowHasContent) {
window_b->Init(ui::LAYER_NOT_DRAWN);
window_b->SetBounds(gfx::Rect(0, 0, 10, 10));
root_window()->AddChild(window_b);
delegate_b->set_expectation(Window::OcclusionState::HIDDEN);
delegate_b->set_expectation(Window::OcclusionState::HIDDEN, SkRegion());
window_b->TrackOcclusionState();
EXPECT_FALSE(delegate_b->is_expecting_call());
......@@ -887,8 +974,8 @@ TEST_F(WindowOcclusionTrackerTest, CustomizedWindowHasContent) {
}));
// Show window b to trigger a occlusion compute and window a is occluded.
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED);
delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
window_b->Show();
EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
......@@ -905,7 +992,7 @@ TEST_F(WindowOcclusionTrackerTest, RemoveAndAddTrackedToRoot) {
// Create window b. Expect it to be non-occluded.
MockWindowDelegate* delegate_c = new MockWindowDelegate();
delegate_c->set_expectation(Window::OcclusionState::VISIBLE);
delegate_c->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_c = CreateTrackedWindow(delegate_c, gfx::Rect(0, 0, 5, 5));
EXPECT_FALSE(delegate_c->is_expecting_call());
......@@ -917,19 +1004,20 @@ TEST_F(WindowOcclusionTrackerTest, RemoveAndAddTrackedToRoot) {
// Create untracked window d which covers window a. Expect window a to be
// occluded.
delegate_c->set_expectation(Window::OcclusionState::OCCLUDED);
delegate_c->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
Window* window_d = CreateUntrackedWindow(gfx::Rect(0, 0, 5, 5));
EXPECT_FALSE(delegate_c->is_expecting_call());
// Move window d so that it doesn't cover window c.
delegate_c->set_expectation(Window::OcclusionState::VISIBLE);
delegate_c->set_expectation(Window::OcclusionState::VISIBLE,
SkRegion(SkIRect::MakeXYWH(0, 10, 5, 5)));
window_d->SetBounds(gfx::Rect(0, 10, 5, 5));
EXPECT_FALSE(delegate_c->is_expecting_call());
// Stack window a on top of window c. Expect window c to be non-occluded. This
// won't work if WindowOcclusionTracked didn't register as an observer of
// window a when window c was made a child of root_window().
delegate_c->set_expectation(Window::OcclusionState::OCCLUDED);
delegate_c->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
root_window()->StackChildAtTop(window_a);
EXPECT_FALSE(delegate_c->is_expecting_call());
}
......@@ -952,7 +1040,6 @@ class ResizeWindowObserver : public WindowObserver {
Window* const window_to_resize_;
DISALLOW_COPY_AND_ASSIGN(ResizeWindowObserver);
;
};
} // namespace
......@@ -962,14 +1049,14 @@ class ResizeWindowObserver : public WindowObserver {
TEST_F(WindowOcclusionTrackerTest, ResizeChildFromObserver) {
// Create window a. Expect it to be non-occluded.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
// Create window b. Expect it to be non-occluded and to occlude window a.
MockWindowDelegate* delegate_b = new MockWindowDelegate();
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED);
delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_b = CreateTrackedWindow(delegate_b, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
......@@ -977,7 +1064,7 @@ TEST_F(WindowOcclusionTrackerTest, ResizeChildFromObserver) {
// Create window c, which is a child of window b. Expect it to be non-
// occluded.
MockWindowDelegate* delegate_c = new MockWindowDelegate();
delegate_c->set_expectation(Window::OcclusionState::VISIBLE);
delegate_c->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_c =
CreateTrackedWindow(delegate_c, gfx::Rect(0, 0, 5, 5), window_b);
EXPECT_FALSE(delegate_b->is_expecting_call());
......@@ -998,15 +1085,18 @@ TEST_F(WindowOcclusionTrackerTest, ResizeChildFromObserver) {
TEST_F(WindowOcclusionTrackerTest, ScopedPause) {
// Create window a. Expect it to be non-occluded.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_a = CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 5, 5));
EXPECT_FALSE(delegate_a->is_expecting_call());
// Create window b which doesn't overlap window a. Expect it to be non-
// Create window b which doesn't overlap window a. Expect it to be non
// occluded.
MockWindowDelegate* delegate_b = new MockWindowDelegate();
delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE,
SkRegion(SkIRect::MakeXYWH(0, 10, 5, 5)));
delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_b = CreateTrackedWindow(delegate_b, gfx::Rect(0, 10, 5, 5));
EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
// Change bounds multiple times. At the end of the scope, expect window a to
......@@ -1018,7 +1108,7 @@ TEST_F(WindowOcclusionTrackerTest, ScopedPause) {
window_a->SetBounds(gfx::Rect(0, 10, 5, 5));
window_b->SetBounds(window_a->bounds());
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED);
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
}
EXPECT_FALSE(delegate_a->is_expecting_call());
}
......@@ -1027,15 +1117,17 @@ TEST_F(WindowOcclusionTrackerTest, ScopedPause) {
TEST_F(WindowOcclusionTrackerTest, NestedScopedPause) {
// Create window a. Expect it to be non-occluded.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_a = CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 5, 5));
EXPECT_FALSE(delegate_a->is_expecting_call());
// Create window b which doesn't overlap window a. Expect it to be non-
// occluded.
MockWindowDelegate* delegate_b = new MockWindowDelegate();
delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE,
SkRegion(SkIRect::MakeXYWH(0, 10, 5, 5)));
delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_b = CreateTrackedWindow(delegate_b, gfx::Rect(0, 10, 5, 5));
EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
// Change bounds multiple times. At the end of the scope, expect window a to
......@@ -1060,7 +1152,7 @@ TEST_F(WindowOcclusionTrackerTest, NestedScopedPause) {
window_b->SetBounds(window_a->bounds());
}
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED);
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
}
EXPECT_FALSE(delegate_a->is_expecting_call());
}
......@@ -1080,17 +1172,19 @@ TEST_F(WindowOcclusionTrackerTest, HierarchyOfTransforms) {
// Effective bounds: x = 34, y = 36, height = 8, width = 10
CreateUntrackedWindow(gfx::Rect(15, 16, 4, 5), window_b);
MockWindowDelegate* delegate_d = new MockWindowDelegate();
delegate_d->set_expectation(Window::OcclusionState::VISIBLE);
delegate_d->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_d = CreateTrackedWindow(delegate_d, gfx::Rect(34, 36, 8, 10));
EXPECT_FALSE(delegate_d->is_expecting_call());
delegate_d->set_expectation(Window::OcclusionState::OCCLUDED);
delegate_d->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
root_window()->StackChildAtBottom(window_d);
EXPECT_FALSE(delegate_d->is_expecting_call());
delegate_d->set_expectation(Window::OcclusionState::VISIBLE);
SkRegion occluded_area = SkRegionFromSkIRects(
{SkIRect::MakeXYWH(2, 2, 10, 10), SkIRect::MakeXYWH(4, 4, 4, 4),
SkIRect::MakeXYWH(34, 36, 8, 10)});
delegate_d->set_expectation(Window::OcclusionState::VISIBLE, occluded_area);
window_d->SetBounds(gfx::Rect(35, 36, 8, 10));
EXPECT_FALSE(delegate_d->is_expecting_call());
......@@ -1104,21 +1198,23 @@ TEST_F(WindowOcclusionTrackerTest, HierarchyOfTransforms) {
TEST_F(WindowOcclusionTrackerTest, Clipping) {
// Create window a. Expect it to be non-occluded.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
// Create window b. Expect it to be non-occluded.
MockWindowDelegate* delegate_b = new MockWindowDelegate();
delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE,
SkRegion(SkIRect::MakeWH(5, 5)));
delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_b = CreateTrackedWindow(delegate_b, gfx::Rect(0, 0, 5, 5));
EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
window_b->layer()->SetMasksToBounds(true);
// Create window c which has window b as parent. Don't expect it to occlude
// window a since its bounds are clipped by window b.
MockWindowDelegate* delegate_c = new MockWindowDelegate();
delegate_c->set_expectation(Window::OcclusionState::VISIBLE);
delegate_c->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_c, gfx::Rect(0, 0, 10, 10), window_b);
EXPECT_FALSE(delegate_c->is_expecting_call());
}
......@@ -1138,7 +1234,7 @@ TEST_F(WindowOcclusionTrackerTest, DestroyWindowWithPendingAnimation) {
layer_animation_settings.SetTransitionDuration(kTransitionDuration);
MockWindowDelegate* delegate = new MockWindowDelegate();
delegate->set_expectation(Window::OcclusionState::VISIBLE);
delegate->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window = CreateTrackedWindow(delegate, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate->is_expecting_call());
window->layer()->SetAnimator(test_controller.animator());
......@@ -1166,28 +1262,29 @@ TEST_F(WindowOcclusionTrackerTest, RecreateLayerOfAnimatedWindow) {
// Create 2 windows. Window b occludes window a.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_a = CreateTrackedWindow(delegate_a, gfx::Rect(2, 2, 1, 1));
EXPECT_FALSE(delegate_a->is_expecting_call());
window_a->layer()->SetAnimator(test_controller.animator());
MockWindowDelegate* delegate_b = new MockWindowDelegate();
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED);
delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_b, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
// Start animating the bounds of window a. Window a should be non-occluded
// when the animation starts.
delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
window_a->SetBounds(gfx::Rect(6, 6, 1, 1));
test_controller.Step(kTransitionDuration / 2);
EXPECT_FALSE(delegate_a->is_expecting_call());
// Recreate the layer of window b. Expect this to behave the same as if the
// animation was abandoned.
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED);
// animation was abandoned. Occlusion region should be half way between the
// animation bounds.
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
std::unique_ptr<ui::Layer> old_layer = window_a->RecreateLayer();
EXPECT_FALSE(delegate_a->is_expecting_call());
......@@ -1217,7 +1314,7 @@ class ObserverChangingWindowBounds : public WindowObserver {
TEST_F(WindowOcclusionTrackerTest, ChangeTrackedWindowBeforeObserveAddToRoot) {
// Create a window. Expect it to be non-occluded.
MockWindowDelegate* delegate = new MockWindowDelegate();
delegate->set_expectation(Window::OcclusionState::VISIBLE);
delegate->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window = CreateTrackedWindow(delegate, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate->is_expecting_call());
......@@ -1279,7 +1376,7 @@ TEST_F(WindowOcclusionTrackerTest,
// Create a window. Expect it to be non-occluded.
MockWindowDelegate* delegate = new MockWindowDelegate();
delegate->set_expectation(Window::OcclusionState::VISIBLE);
delegate->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window = CreateTrackedWindow(delegate, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate->is_expecting_call());
window->layer()->SetAnimator(test_controller.animator());
......@@ -1311,20 +1408,27 @@ TEST_F(WindowOcclusionTrackerTest,
// Create a tracked window. Expect it to be non-occluded.
MockWindowDelegate* delegate = new MockWindowDelegate();
delegate->set_expectation(Window::OcclusionState::VISIBLE);
delegate->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate->is_expecting_call());
// Create a non-tracked window and add an observer that deletes it when its
// stops being animated.
delegate->set_expectation(Window::OcclusionState::VISIBLE,
SkRegion(SkIRect::MakeXYWH(10, 0, 10, 10)));
Window* window = CreateUntrackedWindow(gfx::Rect(10, 0, 10, 10));
EXPECT_FALSE(delegate->is_expecting_call());
window->layer()->SetAnimator(test_controller.animator());
ObserverDestroyingWindowOnAnimationEnded observer(window);
window->layer()->GetAnimator()->AddObserver(&observer);
// Animate the window. WindowOcclusionTracker should add itself as an observer
// of its LayerAnimator (after |observer|).
// of its LayerAnimator (after |observer|). Upon beginning animation, the
// window should no longer affect the occluded region.
delegate->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
window->layer()->SetOpacity(0.5f);
EXPECT_FALSE(delegate->is_expecting_call());
// Remove the non-tracked window from its root. WindowOcclusionTracker should
// remove the window from its list of animated windows and stop observing it
......@@ -1342,48 +1446,87 @@ namespace {
class WindowDelegateHidingWindowIfOccluded : public MockWindowDelegate {
public:
WindowDelegateHidingWindowIfOccluded(Window* other_window,
MockWindowDelegate* other_delegate)
: other_window_(other_window), other_delegate_(other_delegate) {}
WindowDelegateHidingWindowIfOccluded(Window* other_window)
: other_window_(other_window) {}
// MockWindowDelegate:
void OnWindowOcclusionChanged(
Window::OcclusionState occlusion_state) override {
MockWindowDelegate::OnWindowOcclusionChanged(occlusion_state);
void OnWindowOcclusionChanged(Window::OcclusionState occlusion_state,
const SkRegion& occluded_region) override {
MockWindowDelegate::OnWindowOcclusionChanged(occlusion_state,
occluded_region);
if (occlusion_state == Window::OcclusionState::HIDDEN) {
other_window_->Hide();
other_delegate_->set_expectation(Window::OcclusionState::HIDDEN);
}
}
private:
Window* other_window_;
MockWindowDelegate* other_delegate_;
DISALLOW_COPY_AND_ASSIGN(WindowDelegateHidingWindowIfOccluded);
};
class WindowDelegateWithQueuedExpectation : public MockWindowDelegate {
public:
WindowDelegateWithQueuedExpectation() = default;
void set_queued_expectation(Window::OcclusionState occlusion_state,
const SkRegion& occluded_region) {
queued_expected_occlusion_state_ = occlusion_state;
queued_expected_occluded_region_ = occluded_region;
}
// MockWindowDelegate:
void OnWindowOcclusionChanged(Window::OcclusionState occlusion_state,
const SkRegion& occluded_region) override {
MockWindowDelegate::OnWindowOcclusionChanged(occlusion_state,
occluded_region);
if (queued_expected_occlusion_state_ != Window::OcclusionState::UNKNOWN) {
set_expectation(queued_expected_occlusion_state_,
queued_expected_occluded_region_);
queued_expected_occlusion_state_ = Window::OcclusionState::UNKNOWN;
queued_expected_occluded_region_ = SkRegion();
}
}
private:
Window::OcclusionState queued_expected_occlusion_state_ =
Window::OcclusionState::UNKNOWN;
SkRegion queued_expected_occluded_region_ = SkRegion();
DISALLOW_COPY_AND_ASSIGN(WindowDelegateWithQueuedExpectation);
};
} // 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) {
// Create a tracked window. Expect it to be visible.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
WindowDelegateWithQueuedExpectation* delegate_a =
new WindowDelegateWithQueuedExpectation();
delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_a = CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
// Create a tracked window. Expect it to be visible.
MockWindowDelegate* delegate_b =
new WindowDelegateHidingWindowIfOccluded(window_a, delegate_a);
delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
Window* window_b = CreateTrackedWindow(delegate_b, gfx::Rect(5, 5, 10, 10));
new WindowDelegateHidingWindowIfOccluded(window_a);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE,
SkRegion(SkIRect::MakeXYWH(10, 0, 10, 10)));
delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_b = CreateTrackedWindow(delegate_b, gfx::Rect(10, 0, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
// Hide the tracked window. It should be able to hide |window_a|.
delegate_b->set_expectation(Window::OcclusionState::HIDDEN);
// Hide the tracked window. It should be able to hide |window_a|. Before
// |window_a| is hidden, it will notice that the occlusion region has changed
// now that |window_b| is hidden. Then, it will be hidden by |window_b|.
delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
delegate_a->set_queued_expectation(Window::OcclusionState::HIDDEN,
SkRegion());
delegate_b->set_expectation(Window::OcclusionState::HIDDEN, SkRegion());
window_b->Hide();
EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
EXPECT_FALSE(window_a->IsVisible());
......@@ -1399,9 +1542,10 @@ class WindowDelegateDeletingWindow : public MockWindowDelegate {
void set_other_window(Window* other_window) { other_window_ = other_window; }
// MockWindowDelegate:
void OnWindowOcclusionChanged(
Window::OcclusionState occlusion_state) override {
MockWindowDelegate::OnWindowOcclusionChanged(occlusion_state);
void OnWindowOcclusionChanged(Window::OcclusionState occlusion_state,
const SkRegion& occluded_region) override {
MockWindowDelegate::OnWindowOcclusionChanged(occlusion_state,
occluded_region);
if (occlusion_state == Window::OcclusionState::OCCLUDED) {
delete other_window_;
other_window_ = nullptr;
......@@ -1422,29 +1566,42 @@ class WindowDelegateDeletingWindow : public MockWindowDelegate {
TEST_F(WindowOcclusionTrackerTest, DeleteFromOnWindowOcclusionChanged) {
// Create a tracked window. Expect it to be visible.
WindowDelegateDeletingWindow* delegate_a = new WindowDelegateDeletingWindow();
delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_a = CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
// Create a tracked window. Expect it to be visible.
MockWindowDelegate* delegate_b = new MockWindowDelegate();
delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE,
SkRegion(SkIRect::MakeXYWH(10, 0, 10, 10)));
delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_b = CreateTrackedWindow(delegate_b, gfx::Rect(10, 0, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
// Create a tracked window. Expect it to be visible.
MockWindowDelegate* delegate_c = new MockWindowDelegate();
delegate_c->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(
Window::OcclusionState::VISIBLE,
SkRegionFromSkIRects({SkIRect::MakeXYWH(10, 0, 10, 10),
SkIRect::MakeXYWH(20, 0, 10, 10)}));
delegate_b->set_expectation(Window::OcclusionState::VISIBLE,
SkRegion(SkIRect::MakeXYWH(20, 0, 10, 10)));
delegate_c->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_c = CreateTrackedWindow(delegate_c, gfx::Rect(20, 0, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
EXPECT_FALSE(delegate_c->is_expecting_call());
// |window_c| will be deleted when |window_a| is occluded.
delegate_a->set_other_window(window_c);
// Move |window_b| on top of |window_a|.
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED);
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
window_b->SetBounds(window_a->bounds());
EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
}
namespace {
......@@ -1456,9 +1613,10 @@ class WindowDelegateChangingWindowVisibility : public MockWindowDelegate {
void set_window_to_update(Window* window) { window_to_update_ = window; }
// MockWindowDelegate:
void OnWindowOcclusionChanged(
Window::OcclusionState occlusion_state) override {
MockWindowDelegate::OnWindowOcclusionChanged(occlusion_state);
void OnWindowOcclusionChanged(Window::OcclusionState occlusion_state,
const SkRegion& occluded_region) override {
MockWindowDelegate::OnWindowOcclusionChanged(occlusion_state,
occluded_region);
if (!window_to_update_)
return;
......@@ -1467,10 +1625,10 @@ class WindowDelegateChangingWindowVisibility : public MockWindowDelegate {
if (window_to_update_->IsVisible()) {
window_to_update_->Hide();
if (num_occlusion_change_ <= 3)
set_expectation(Window::OcclusionState::HIDDEN);
set_expectation(Window::OcclusionState::HIDDEN, SkRegion());
} else {
window_to_update_->Show();
set_expectation(Window::OcclusionState::VISIBLE);
set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
}
}
......@@ -1491,30 +1649,36 @@ TEST_F(WindowOcclusionTrackerTest, OcclusionStatesDontBecomeStable) {
// Create 2 superposed tracked windows.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
MockWindowDelegate* delegate_b = new MockWindowDelegate();
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED);
delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_b, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
// Create a hidden tracked window.
MockWindowDelegate* delegate_c = new MockWindowDelegate();
delegate_c->set_expectation(Window::OcclusionState::VISIBLE);
delegate_b->set_expectation(Window::OcclusionState::VISIBLE,
SkRegion(SkIRect::MakeXYWH(10, 0, 10, 10)));
delegate_c->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_c = CreateTrackedWindow(delegate_c, gfx::Rect(10, 0, 10, 10));
EXPECT_FALSE(delegate_c->is_expecting_call());
delegate_c->set_expectation(Window::OcclusionState::HIDDEN);
delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
delegate_c->set_expectation(Window::OcclusionState::HIDDEN, SkRegion());
window_c->Hide();
EXPECT_FALSE(delegate_c->is_expecting_call());
// Create a tracked window. Expect it to be non-occluded.
auto* delegate_d = new WindowDelegateChangingWindowVisibility();
delegate_d->set_expectation(Window::OcclusionState::VISIBLE);
delegate_b->set_expectation(Window::OcclusionState::VISIBLE,
SkRegion(SkIRect::MakeXYWH(20, 0, 10, 10)));
delegate_d->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_d = CreateTrackedWindow(delegate_d, gfx::Rect(20, 0, 10, 10));
EXPECT_FALSE(delegate_b->is_expecting_call());
EXPECT_FALSE(delegate_d->is_expecting_call());
// Store a pointer to |window_d| in |delegate_d|. This will cause a call to
......@@ -1526,8 +1690,9 @@ TEST_F(WindowOcclusionTrackerTest, OcclusionStatesDontBecomeStable) {
// reached, the occlusion state of all IsVisible() windows should be set to
// VISIBLE.
EXPECT_DCHECK_DEATH({
delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
delegate_d->set_expectation(Window::OcclusionState::HIDDEN);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE,
SkRegion(SkIRect::MakeXYWH(20, 0, 10, 10)));
delegate_d->set_expectation(Window::OcclusionState::HIDDEN, SkRegion());
window_d->Hide();
});
}
......@@ -1537,25 +1702,25 @@ TEST_F(WindowOcclusionTrackerTest, OcclusionStatesDontBecomeStable) {
TEST_F(WindowOcclusionTrackerTest, HideTreeBranch) {
// Create a branch of 3 tracked windows. Expect them to be visible.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_a = CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
MockWindowDelegate* delegate_b = new MockWindowDelegate();
delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_b =
CreateTrackedWindow(delegate_b, gfx::Rect(0, 10, 10, 10), window_a);
EXPECT_FALSE(delegate_b->is_expecting_call());
MockWindowDelegate* delegate_c = new MockWindowDelegate();
delegate_c->set_expectation(Window::OcclusionState::VISIBLE);
delegate_c->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_c, gfx::Rect(0, 20, 10, 10), window_b);
EXPECT_FALSE(delegate_c->is_expecting_call());
// Hide |window_b| (and hence |window_c|). Expect |window_b| and |window_c| to
// be hidden.
delegate_b->set_expectation(Window::OcclusionState::HIDDEN);
delegate_c->set_expectation(Window::OcclusionState::HIDDEN);
delegate_b->set_expectation(Window::OcclusionState::HIDDEN, SkRegion());
delegate_c->set_expectation(Window::OcclusionState::HIDDEN, SkRegion());
window_b->Hide();
EXPECT_FALSE(delegate_b->is_expecting_call());
EXPECT_FALSE(delegate_c->is_expecting_call());
......@@ -1565,13 +1730,13 @@ TEST_F(WindowOcclusionTrackerTest, HideTreeBranch) {
TEST_F(WindowOcclusionTrackerTest, WindowWithAlphaShape) {
// Create 2 superposed tracked windows.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
MockWindowDelegate* delegate_b = new MockWindowDelegate();
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED);
delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_b = CreateTrackedWindow(delegate_b, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
......@@ -1580,13 +1745,14 @@ TEST_F(WindowOcclusionTrackerTest, WindowWithAlphaShape) {
// occluded.
auto shape = std::make_unique<ui::Layer::ShapeRects>();
shape->emplace_back(0, 0, 5, 5);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
// Shaped windows are not considered opaque, so the occluded region is empty.
delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
window_b->layer()->SetAlphaShape(std::move(shape));
EXPECT_FALSE(delegate_a->is_expecting_call());
// Clear the shape for the top window. The window underneath should be
// occluded.
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED);
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
window_b->layer()->SetAlphaShape(nullptr);
EXPECT_FALSE(delegate_a->is_expecting_call());
}
......@@ -1596,18 +1762,21 @@ TEST_F(WindowOcclusionTrackerTest, WindowWithAlphaShape) {
TEST_F(WindowOcclusionTrackerTest, WindowWithParentAlphaShape) {
// Create a child and parent that cover another window.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 20, 20));
EXPECT_FALSE(delegate_a->is_expecting_call());
MockWindowDelegate* delegate_b = new MockWindowDelegate();
delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE,
SkRegion(SkIRect::MakeWH(10, 10)));
delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_b = CreateTrackedWindow(delegate_b, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
MockWindowDelegate* delegate_c = new MockWindowDelegate();
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED);
delegate_c->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
delegate_c->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_c, gfx::Rect(0, 0, 20, 20), window_b);
EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_c->is_expecting_call());
......@@ -1616,13 +1785,13 @@ TEST_F(WindowOcclusionTrackerTest, WindowWithParentAlphaShape) {
// occluded.
auto shape = std::make_unique<ui::Layer::ShapeRects>();
shape->emplace_back(0, 0, 5, 5);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
window_b->layer()->SetAlphaShape(std::move(shape));
EXPECT_FALSE(delegate_a->is_expecting_call());
// Clear the shape for |window_b|. |window_a| and |window_b| should be
// occluded.
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED);
delegate_a->set_expectation(Window::OcclusionState::OCCLUDED, SkRegion());
window_b->layer()->SetAlphaShape(nullptr);
EXPECT_FALSE(delegate_a->is_expecting_call());
}
......@@ -1636,9 +1805,10 @@ class WindowDelegateHidingWindow : public MockWindowDelegate {
void set_window_to_update(Window* window) { window_to_update_ = window; }
// MockWindowDelegate:
void OnWindowOcclusionChanged(
Window::OcclusionState occlusion_state) override {
MockWindowDelegate::OnWindowOcclusionChanged(occlusion_state);
void OnWindowOcclusionChanged(Window::OcclusionState occlusion_state,
const SkRegion& occluded_region) override {
MockWindowDelegate::OnWindowOcclusionChanged(occlusion_state,
occluded_region);
if (!window_to_update_)
return;
......@@ -1653,15 +1823,28 @@ class WindowDelegateHidingWindow : public MockWindowDelegate {
class WindowDelegateAddingAndHidingChild : public MockWindowDelegate {
public:
WindowDelegateAddingAndHidingChild(WindowOcclusionTrackerTest* test)
explicit WindowDelegateAddingAndHidingChild(WindowOcclusionTrackerTest* test)
: test_(test) {}
void set_queued_expectation(Window::OcclusionState occlusion_state,
const SkRegion& occluded_region) {
queued_expected_occlusion_state_ = occlusion_state;
queued_expected_occluded_region_ = occluded_region;
}
void set_window_to_update(Window* window) { window_to_update_ = window; }
// MockWindowDelegate:
void OnWindowOcclusionChanged(
Window::OcclusionState occlusion_state) override {
MockWindowDelegate::OnWindowOcclusionChanged(occlusion_state);
void OnWindowOcclusionChanged(Window::OcclusionState occlusion_state,
const SkRegion& occluded_region) override {
MockWindowDelegate::OnWindowOcclusionChanged(occlusion_state,
occluded_region);
if (queued_expected_occlusion_state_ != Window::OcclusionState::UNKNOWN) {
set_expectation(queued_expected_occlusion_state_,
queued_expected_occluded_region_);
queued_expected_occlusion_state_ = Window::OcclusionState::UNKNOWN;
queued_expected_occluded_region_ = SkRegion();
}
if (!window_to_update_)
return;
......@@ -1677,6 +1860,9 @@ class WindowDelegateAddingAndHidingChild : public MockWindowDelegate {
private:
WindowOcclusionTrackerTest* test_;
Window* window_to_update_ = nullptr;
Window::OcclusionState queued_expected_occlusion_state_ =
Window::OcclusionState::UNKNOWN;
SkRegion queued_expected_occluded_region_ = SkRegion();
DISALLOW_COPY_AND_ASSIGN(WindowDelegateAddingAndHidingChild);
};
......@@ -1691,22 +1877,27 @@ TEST_F(WindowOcclusionTrackerTest,
root_window()->env()->GetWindowOcclusionTracker());
auto* delegate_a = new WindowDelegateAddingAndHidingChild(this);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_a = CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
auto* delegate_b = new WindowDelegateHidingWindow();
delegate_b->set_expectation(Window::OcclusionState::VISIBLE);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE,
SkRegion(SkIRect::MakeXYWH(0, 10, 10, 10)));
delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_b = CreateTrackedWindow(delegate_b, gfx::Rect(0, 10, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
// When |window_b| is hidden, it will hide |window_a|. |window_a| will in turn
// add a child to itself and hide it.
delegate_a->set_window_to_update(window_a);
delegate_b->set_window_to_update(window_a);
delegate_a->set_expectation(Window::OcclusionState::HIDDEN);
delegate_b->set_expectation(Window::OcclusionState::HIDDEN);
// Initially A is marked as visible with no potential occlusion.
delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
delegate_a->set_queued_expectation(Window::OcclusionState::HIDDEN,
SkRegion());
delegate_b->set_expectation(Window::OcclusionState::HIDDEN, SkRegion());
// Hiding a child to |window_a| and hiding it shouldn't cause occlusion to be
// recomputed too many times (i.e. the call below shouldn't DCHECK).
window_b->Hide();
......@@ -1714,4 +1905,116 @@ TEST_F(WindowOcclusionTrackerTest,
EXPECT_FALSE(delegate_b->is_expecting_call());
}
// Verify that hiding a window changes the occlusion region to show that the
// window is fully occluded.
TEST_F(WindowOcclusionTrackerTest,
HideWindowChangesOcclusionRegionToBeFullyOccluded) {
MockWindowDelegate* delegate_a = new MockWindowDelegate();
delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_a = CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
delegate_a->set_expectation(Window::OcclusionState::HIDDEN, SkRegion());
window_a->Hide();
EXPECT_FALSE(delegate_a->is_expecting_call());
}
// 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) {
// Create window a. Expect it to be non-occluded.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 20, 20));
EXPECT_FALSE(delegate_a->is_expecting_call());
// Create window b, occluding window a partially.
MockWindowDelegate* delegate_b = new MockWindowDelegate();
delegate_a->set_expectation(Window::OcclusionState::VISIBLE,
SkRegion(SkIRect::MakeXYWH(6, 7, 8, 9)));
delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_b = CreateTrackedWindow(delegate_b, gfx::Rect(6, 7, 8, 9));
EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
// Hiding window b should stop occluding window a partially.
delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
delegate_b->set_expectation(Window::OcclusionState::HIDDEN, SkRegion());
window_b->Hide();
EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
}
// Verify that windows with alpha shape do not affect occlusion regions.
TEST_F(WindowOcclusionTrackerTest,
WindowWithAlphaShapeDoesNotPartiallyOccludeOtherWindows) {
// Create window a. Expect it to be non-occluded.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 20, 20));
EXPECT_FALSE(delegate_a->is_expecting_call());
// Create window b, occluding window a partially.
MockWindowDelegate* delegate_b = new MockWindowDelegate();
delegate_a->set_expectation(Window::OcclusionState::VISIBLE,
SkRegion(SkIRect::MakeXYWH(6, 7, 8, 9)));
delegate_b->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
Window* window_b = CreateTrackedWindow(delegate_b, gfx::Rect(6, 7, 8, 9));
EXPECT_FALSE(delegate_a->is_expecting_call());
EXPECT_FALSE(delegate_b->is_expecting_call());
// Set a shape for window b. The window underneath should no longer be
// partially occluded.
auto shape = std::make_unique<ui::Layer::ShapeRects>();
shape->emplace_back(0, 0, 5, 5);
// Shaped windows are not considered opaque, so the occluded region is empty.
delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
window_b->layer()->SetAlphaShape(std::move(shape));
EXPECT_FALSE(delegate_a->is_expecting_call());
// Clear the shape for the top window. The window underneath should be
// occluded.
delegate_a->set_expectation(Window::OcclusionState::VISIBLE,
SkRegion(SkIRect::MakeXYWH(6, 7, 8, 9)));
window_b->layer()->SetAlphaShape(nullptr);
EXPECT_FALSE(delegate_a->is_expecting_call());
}
// Verify that a window can be occluded by multiple other windows.
TEST_F(WindowOcclusionTrackerTest, WindowCanBeOccludedByMultipleWindows) {
// Create window a. Expect it to be non-occluded.
MockWindowDelegate* delegate_a = new MockWindowDelegate();
delegate_a->set_expectation(Window::OcclusionState::VISIBLE, SkRegion());
CreateTrackedWindow(delegate_a, gfx::Rect(0, 0, 10, 10));
EXPECT_FALSE(delegate_a->is_expecting_call());
SkRegion window_a_occlusion = SkRegion(SkIRect::MakeXYWH(9, 9, 5, 5));
delegate_a->set_expectation(Window::OcclusionState::VISIBLE,
window_a_occlusion);
CreateUntrackedWindow(gfx::Rect(9, 9, 5, 5));
EXPECT_FALSE(delegate_a->is_expecting_call());
window_a_occlusion.op(SkIRect::MakeXYWH(-4, -4, 5, 5),
SkRegion::Op::kUnion_Op);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE,
window_a_occlusion);
CreateUntrackedWindow(gfx::Rect(-4, -4, 5, 5));
EXPECT_FALSE(delegate_a->is_expecting_call());
window_a_occlusion.op(SkIRect::MakeXYWH(9, -4, 5, 5),
SkRegion::Op::kUnion_Op);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE,
window_a_occlusion);
CreateUntrackedWindow(gfx::Rect(9, -4, 5, 5));
EXPECT_FALSE(delegate_a->is_expecting_call());
window_a_occlusion.op(SkIRect::MakeXYWH(5, 5, 2, 3), SkRegion::Op::kUnion_Op);
delegate_a->set_expectation(Window::OcclusionState::VISIBLE,
window_a_occlusion);
CreateUntrackedWindow(gfx::Rect(5, 5, 2, 3));
EXPECT_FALSE(delegate_a->is_expecting_call());
}
} // namespace aura
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment