Commit 12ee465b authored by yoshiki iguchi's avatar yoshiki iguchi Committed by Commit Bot

Update the mask bounds when window bounds is changed

Recently the chrome pip windows have WindowStateType::PIP and behaves as
pip windows. Pip windows moves with animation but the mask bounds was
not synced with these animation. As the result, the test was flaky (see
the bug).

This CL adds the observer of window bounds and make it sure that the
layer bounds is synced with the window bounds.

Bug: 901235
Test: Ran PictureInPictureWindowControllerBrowserTest.
    EnterPictureInPictureThenFullscreen 10 times and observed no error.

Change-Id: Ide03ab1465170ccaf35af08377d3dd1df0cf7ee2
Reviewed-on: https://chromium-review.googlesource.com/c/1316986
Commit-Queue: Yoshiki Iguchi <yoshiki@chromium.org>
Reviewed-by: default avatarMitsuru Oshima <oshima@chromium.org>
Cr-Commit-Position: refs/heads/master@{#606273}
parent c4d14c85
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include "ui/aura/window.h" #include "ui/aura/window.h"
#include "ui/aura/window_delegate.h" #include "ui/aura/window_delegate.h"
#include "ui/compositor/layer_tree_owner.h" #include "ui/compositor/layer_tree_owner.h"
#include "ui/compositor/paint_recorder.h"
#include "ui/compositor/scoped_layer_animation_settings.h" #include "ui/compositor/scoped_layer_animation_settings.h"
#include "ui/display/display.h" #include "ui/display/display.h"
#include "ui/display/screen.h" #include "ui/display/screen.h"
...@@ -149,6 +150,72 @@ void MoveAllTransientChildrenToNewRoot(aura::Window* window) { ...@@ -149,6 +150,72 @@ void MoveAllTransientChildrenToNewRoot(aura::Window* window) {
} // namespace } // namespace
class WindowState::PipMask : public ui::LayerDelegate,
public aura::WindowObserver {
public:
explicit PipMask(aura::Window* window)
: layer_(ui::LAYER_TEXTURED), window_(window) {
DCHECK(window);
DCHECK(window->layer());
window_->AddObserver(this);
layer_.set_delegate(this);
layer_.SetFillsBoundsOpaquely(false);
layer_.SetBounds(window->layer()->bounds());
}
~PipMask() override {
if (window_)
window_->RemoveObserver(this);
layer_.set_delegate(nullptr);
}
ui::Layer* layer() { return &layer_; }
const aura::Window* window() const { return window_; }
private:
// ui::LayerDelegate overridden:
void OnPaintLayer(const ui::PaintContext& context) override {
cc::PaintFlags flags;
flags.setAlpha(255);
flags.setAntiAlias(true);
flags.setStyle(cc::PaintFlags::kFill_Style);
const int radius = kPipRoundedCornerRadius;
SkScalar radii[8] = {radius, radius, // top-left
radius, radius, // top-right
radius, radius, // bottom-right
radius, radius}; // bottom-left
SkPath path;
path.addRoundRect(gfx::RectToSkRect(gfx::Rect(layer()->size())), radii);
ui::PaintRecorder recorder(context, layer()->size());
recorder.canvas()->DrawPath(path, flags);
}
void OnDeviceScaleFactorChanged(float old_device_scale_factor,
float new_device_scale_factor) override {}
// aura::WindowObserver overridden:
void OnWindowBoundsChanged(aura::Window* window,
const gfx::Rect& old_bounds,
const gfx::Rect& new_bounds,
ui::PropertyChangeReason reason) override {
layer_.SetBounds(new_bounds);
}
void OnWindowDestroying(aura::Window* window) override {
window_->RemoveObserver(this);
window_ = nullptr;
}
ui::Layer layer_;
aura::Window* window_;
DISALLOW_COPY_AND_ASSIGN(PipMask);
};
constexpr base::TimeDelta WindowState::kBoundsChangeSlideDuration; constexpr base::TimeDelta WindowState::kBoundsChangeSlideDuration;
WindowState::~WindowState() { WindowState::~WindowState() {
...@@ -681,11 +748,8 @@ void WindowState::UpdatePipRoundedCorners() { ...@@ -681,11 +748,8 @@ void WindowState::UpdatePipRoundedCorners() {
gfx::Rect bounds = window()->bounds(); gfx::Rect bounds = window()->bounds();
if (layer && (!pip_mask_ || pip_mask_->layer()->size() != bounds.size())) { if (layer && (!pip_mask_ || pip_mask_->layer()->size() != bounds.size())) {
layer->SetMaskLayer(nullptr); layer->SetMaskLayer(nullptr);
pip_mask_ = views::Painter::CreatePaintedLayer( if (!pip_mask_ || window() != pip_mask_->window())
views::Painter::CreateSolidRoundRectPainter(SK_ColorBLACK, pip_mask_ = std::make_unique<PipMask>(window());
kPipRoundedCornerRadius));
pip_mask_->layer()->SetBounds(bounds);
pip_mask_->layer()->SetFillsBoundsOpaquely(false);
layer->SetFillsBoundsOpaquely(false); layer->SetFillsBoundsOpaquely(false);
layer->SetMaskLayer(pip_mask_->layer()); layer->SetMaskLayer(pip_mask_->layer());
} }
......
...@@ -35,6 +35,7 @@ enum class WindowPinType; ...@@ -35,6 +35,7 @@ enum class WindowPinType;
} }
namespace wm { namespace wm {
class InitialStateTestState;
class WindowState; class WindowState;
class WindowStateDelegate; class WindowStateDelegate;
class WindowStateObserver; class WindowStateObserver;
...@@ -352,6 +353,7 @@ class ASH_EXPORT WindowState : public aura::WindowObserver { ...@@ -352,6 +353,7 @@ class ASH_EXPORT WindowState : public aura::WindowObserver {
private: private:
friend class BaseState; friend class BaseState;
friend class DefaultState; friend class DefaultState;
friend class InitialStateTestState;
friend class ash::wm::ClientControlledState; friend class ash::wm::ClientControlledState;
friend class ash::LockWindowState; friend class ash::LockWindowState;
friend class ash::TabletModeWindowState; friend class ash::TabletModeWindowState;
...@@ -359,6 +361,10 @@ class ASH_EXPORT WindowState : public aura::WindowObserver { ...@@ -359,6 +361,10 @@ class ASH_EXPORT WindowState : public aura::WindowObserver {
FRIEND_TEST_ALL_PREFIXES(WindowAnimationsTest, CrossFadeToBounds); FRIEND_TEST_ALL_PREFIXES(WindowAnimationsTest, CrossFadeToBounds);
FRIEND_TEST_ALL_PREFIXES(WindowAnimationsTest, FRIEND_TEST_ALL_PREFIXES(WindowAnimationsTest,
CrossFadeToBoundsFromTransform); CrossFadeToBoundsFromTransform);
FRIEND_TEST_ALL_PREFIXES(WindowStateTest, PipWindowHasMaskLayer);
// Class to host the rounded mask for PIP windows.
class PipMask;
explicit WindowState(aura::Window* window); explicit WindowState(aura::Window* window);
...@@ -447,7 +453,7 @@ class ASH_EXPORT WindowState : public aura::WindowObserver { ...@@ -447,7 +453,7 @@ class ASH_EXPORT WindowState : public aura::WindowObserver {
bool allow_set_bounds_direct_ = false; bool allow_set_bounds_direct_ = false;
// Mask layer for PIP windows. // Mask layer for PIP windows.
std::unique_ptr<ui::LayerOwner> pip_mask_ = nullptr; std::unique_ptr<PipMask> pip_mask_;
// A property to save the ratio between snapped window width and display // A property to save the ratio between snapped window width and display
// workarea width. It is used to update snapped window width on // workarea width. It is used to update snapped window width on
......
...@@ -28,25 +28,6 @@ namespace ash { ...@@ -28,25 +28,6 @@ namespace ash {
namespace wm { namespace wm {
namespace { namespace {
class InitialStateTestState : public WindowState::State {
public:
explicit InitialStateTestState(WindowStateType initial_state_type)
: state_type_(initial_state_type) {}
~InitialStateTestState() override = default;
// WindowState::State overrides:
void OnWMEvent(WindowState* window_state, const WMEvent* event) override {}
WindowStateType GetType() const override { return state_type_; }
void AttachState(WindowState* window_state,
WindowState::State* previous_state) override {}
void DetachState(WindowState* window_state) override {}
private:
WindowStateType state_type_;
DISALLOW_COPY_AND_ASSIGN(InitialStateTestState);
};
class AlwaysMaximizeTestState : public WindowState::State { class AlwaysMaximizeTestState : public WindowState::State {
public: public:
explicit AlwaysMaximizeTestState(WindowStateType initial_state_type) explicit AlwaysMaximizeTestState(WindowStateType initial_state_type)
...@@ -76,6 +57,31 @@ class AlwaysMaximizeTestState : public WindowState::State { ...@@ -76,6 +57,31 @@ class AlwaysMaximizeTestState : public WindowState::State {
} // namespace } // namespace
class InitialStateTestState : public WindowState::State {
public:
explicit InitialStateTestState(WindowStateType initial_state_type)
: state_type_(initial_state_type) {}
~InitialStateTestState() override = default;
// WindowState::State overrides:
void OnWMEvent(WindowState* window_state, const WMEvent* event) override {
if (event->type() == WM_EVENT_SET_BOUNDS) {
const SetBoundsEvent* set_bounds_event =
static_cast<const SetBoundsEvent*>(event);
window_state->SetBoundsDirect(set_bounds_event->requested_bounds());
}
}
WindowStateType GetType() const override { return state_type_; }
void AttachState(WindowState* window_state,
WindowState::State* previous_state) override {}
void DetachState(WindowState* window_state) override {}
private:
WindowStateType state_type_;
DISALLOW_COPY_AND_ASSIGN(InitialStateTestState);
};
using WindowStateTest = AshTestBase; using WindowStateTest = AshTestBase;
// Test that a window gets properly snapped to the display's edges in a // Test that a window gets properly snapped to the display's edges in a
...@@ -167,6 +173,40 @@ TEST_F(WindowStateTest, PipWindowCannotSnap) { ...@@ -167,6 +173,40 @@ TEST_F(WindowStateTest, PipWindowCannotSnap) {
EXPECT_FALSE(window_state->CanSnap()); EXPECT_FALSE(window_state->CanSnap());
} }
// Test that a PIP window cannot be snapped.
TEST_F(WindowStateTest, PipWindowHasMaskLayer) {
// Prepare a PIP window.
std::unique_ptr<aura::Window> window(
CreateTestWindowInShellWithBounds(gfx::Rect(100, 100, 100, 100)));
WindowState* window_state = GetWindowState(window.get());
window_state->SetStateObject(std::unique_ptr<WindowState::State>(
new InitialStateTestState(mojom::WindowStateType::PIP)));
EXPECT_TRUE(window->layer());
// No mask layer exist at this time.
EXPECT_FALSE(window->layer()->layer_mask_layer());
// Install a mask layer.
window_state->UpdatePipRoundedCorners();
// Mask layer exists at this time.
EXPECT_TRUE(window->layer()->layer_mask_layer());
// Make sure the layer has the same bounds.
EXPECT_EQ(gfx::Rect(100, 100, 100, 100).ToString(),
window->bounds().ToString());
EXPECT_EQ(window->layer()->layer_mask_layer()->bounds().ToString(),
window->bounds().ToString());
// Change the bounds of the window.
window->SetBounds(gfx::Rect(0, 0, 150, 150));
// Make sure the layer's bounds is also changed.
EXPECT_EQ(gfx::Rect(0, 0, 150, 150).ToString(), window->bounds().ToString());
EXPECT_EQ(window->layer()->layer_mask_layer()->bounds().ToString(),
window->bounds().ToString());
}
// Test that modal window dialogs can be snapped. // Test that modal window dialogs can be snapped.
TEST_F(WindowStateTest, SnapModalWindowWithoutMaximumSizeLimit) { TEST_F(WindowStateTest, SnapModalWindowWithoutMaximumSizeLimit) {
UpdateDisplay("0+0-600x900"); UpdateDisplay("0+0-600x900");
......
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