Commit 29032e48 authored by Minju Kim's avatar Minju Kim Committed by Chromium LUCI CQ

Make rounded corner of browser frame from NonClientView::GetWindowMask

crrev.com/c/2578501 introduces
PlatformWindowDelegate::GetWindowMaskForWindowShape and updates
window region by the window mask in ozone/wayland.
This CL is the implementation to make the corner of the browser frame
rounded from the window mask.
It is done by XShape in x11, but there is no equivalent extension
of XShape in wayland.

In this CL,
1. Introduce WindowShapeUpdater to update |ui::Layer::alpha_shape_|
   for the rounded corner of window shape from
   NonClientView::GetWindowMask.
   - When bounds changes, ui::Layer::alpha_shape_ is updated according
     to the ShapeRects converted from NonClientView::GetWindowMask.
   - UpdateWindowTransparency when ui::Layer::alpha_shape_ is updated.

2. Set transparent:true to the compositor when NonClientView has
   window mask.
   Otherwise, AppendQuadsToFillScreen to always fill the entire
   screen in LayerTreeHostImpl.

Bug: 1126828
Change-Id: I3a712b8c5f33f9fd32bd2cd5e6ee8664732e3ca3
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2419056Reviewed-by: default avatarScott Violet <sky@chromium.org>
Commit-Queue: MINJU KIM <mkim@igalia.com>
Cr-Commit-Position: refs/heads/master@{#841784}
parent 0b548ee5
......@@ -826,6 +826,8 @@ component("views") {
"widget/desktop_aura/desktop_drag_drop_client_ozone.h",
"widget/desktop_aura/desktop_window_tree_host_platform.cc",
"widget/desktop_aura/window_move_client_platform.cc",
"widget/desktop_aura/window_shape_updater.cc",
"widget/desktop_aura/window_shape_updater.h",
]
}
if (use_atk) {
......
......@@ -28,6 +28,7 @@
#include "ui/views/corewm/tooltip_aura.h"
#include "ui/views/widget/desktop_aura/desktop_drag_drop_client_ozone.h"
#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
#include "ui/views/widget/desktop_aura/window_shape_updater.h"
#include "ui/views/widget/widget_aura_utils.h"
#include "ui/views/window/native_frame_view.h"
#include "ui/wm/core/window_util.h"
......@@ -199,7 +200,13 @@ void DesktopWindowTreeHostPlatform::OnNativeWidgetCreated(
native_widget_delegate_->OnNativeWidgetCreated();
}
void DesktopWindowTreeHostPlatform::OnWidgetInitDone() {}
void DesktopWindowTreeHostPlatform::OnWidgetInitDone() {
// WindowShape is updated from ShapeRects transformed from
// NonClientView::GetWindowMask. We can guarantee that |NonClientView| is
// created OnWidgetInitDone.
WindowShapeUpdater::CreateWindowShapeUpdater(
this, this->desktop_native_widget_aura());
}
void DesktopWindowTreeHostPlatform::OnActiveWindowChanged(bool active) {}
......@@ -437,6 +444,8 @@ gfx::Rect DesktopWindowTreeHostPlatform::GetWorkAreaBoundsInScreen() const {
void DesktopWindowTreeHostPlatform::SetShape(
std::unique_ptr<Widget::ShapeRects> native_shape) {
// TODO(crbug.com/1158733) : When supporting PlatformWindow::SetShape,
// Calls ui::Layer::SetAlphaShape and sets |is_shape_explicitly_set_| to true.
platform_window()->SetShape(std::move(native_shape), GetRootTransform());
}
......@@ -559,7 +568,10 @@ bool DesktopWindowTreeHostPlatform::ShouldUseNativeFrame() const {
}
bool DesktopWindowTreeHostPlatform::ShouldWindowContentsBeTransparent() const {
return platform_window()->ShouldWindowContentsBeTransparent();
return platform_window()->ShouldWindowContentsBeTransparent() ||
const_cast<DesktopWindowTreeHostPlatform*>(this)
->GetWindowMaskForWindowShape(GetBoundsInPixels().size())
.has_value();
}
void DesktopWindowTreeHostPlatform::FrameTypeChanged() {
......
......@@ -42,6 +42,8 @@ class VIEWS_EXPORT DesktopWindowTreeHostPlatform
aura::Window* GetContentWindow();
const aura::Window* GetContentWindow() const;
bool is_shape_explicitly_set() const { return is_shape_explicitly_set_; }
// DesktopWindowTreeHost:
void Init(const Widget::InitParams& params) override;
void OnNativeWidgetCreated(const Widget::InitParams& params) override;
......@@ -176,6 +178,10 @@ class VIEWS_EXPORT DesktopWindowTreeHostPlatform
// Used for tab dragging in move loop requests.
WindowMoveClientPlatform window_move_client_;
// ui::Layer::SetAlphaShape can be set from either SetShape or default window
// mask. When explicitly setting from SetShape, |explicitly_set_shape_:true|.
bool is_shape_explicitly_set_ = false;
base::WeakPtrFactory<DesktopWindowTreeHostPlatform> close_widget_factory_{
this};
......
......@@ -167,6 +167,37 @@ TEST_F(DesktopWindowTreeHostPlatformTest,
EXPECT_TRUE(widget->GetNativeWindow()->IsVisible());
}
// Tests that the window shape is updated from the
// |NonClientView::GetWindowMask|.
TEST_F(DesktopWindowTreeHostPlatformTest, UpdateWindowShapeFromWindowMask) {
std::unique_ptr<Widget> widget = CreateWidgetWithNativeWidget();
widget->Show();
auto* host_platform = DesktopWindowTreeHostPlatform::GetHostForWidget(
widget->GetNativeWindow()->GetHost()->GetAcceleratedWidget());
ASSERT_TRUE(host_platform);
auto* content_window =
DesktopWindowTreeHostPlatform::GetContentWindowForWidget(
widget->GetNativeWindow()->GetHost()->GetAcceleratedWidget());
ASSERT_TRUE(content_window);
// alpha_shape for the layer of content window is updated from the
// |NonClientView::GetWindowMask|.
EXPECT_TRUE(host_platform
->GetWindowMaskForWindowShape(content_window->bounds().size())
.has_value());
EXPECT_TRUE(content_window->layer()->alpha_shape());
// When fullscreen mode, alpha_shape is set to empty since there is no
// |NonClientView::GetWindowMask|.
host_platform->SetFullscreen(true);
widget->SetBounds(gfx::Rect(800, 800));
EXPECT_FALSE(
host_platform
->GetWindowMaskForWindowShape(content_window->bounds().size())
.has_value());
EXPECT_FALSE(content_window->layer()->alpha_shape());
}
// A Widget that allows setting the min/max size for the widget.
class CustomSizeWidget : public Widget {
public:
......
// Copyright 2021 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/views/widget/desktop_aura/window_shape_updater.h"
#include "ui/gfx/skia_util.h"
#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
#include "ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h"
namespace {
std::unique_ptr<ui::Layer::ShapeRects> ConvertToShapeRects(const SkPath& path) {
// Converts to ShapeRects from SkPath.
auto shape_rects = std::make_unique<ui::Layer::ShapeRects>();
SkRegion clip_region;
clip_region.setRect(path.getBounds().round());
SkRegion region;
region.setPath(path, clip_region);
for (SkRegion::Iterator it(region); !it.done(); it.next())
shape_rects->push_back(gfx::SkIRectToRect(it.rect()));
return shape_rects;
}
} // namespace
namespace views {
// static
WindowShapeUpdater* WindowShapeUpdater::CreateWindowShapeUpdater(
DesktopWindowTreeHostPlatform* tree_host,
DesktopNativeWidgetAura* native_widget_aura) {
return new WindowShapeUpdater(tree_host, native_widget_aura);
}
WindowShapeUpdater::WindowShapeUpdater(
DesktopWindowTreeHostPlatform* tree_host,
DesktopNativeWidgetAura* native_widget_aura)
: tree_host_(tree_host), native_widget_aura_(native_widget_aura) {
tree_host_->GetContentWindow()->AddObserver(this);
UpdateWindowShapeFromWindowMask(tree_host_->GetContentWindow());
}
void WindowShapeUpdater::OnWindowBoundsChanged(
aura::Window* window,
const gfx::Rect& old_bounds,
const gfx::Rect& new_bounds,
ui::PropertyChangeReason reason) {
UpdateWindowShapeFromWindowMask(window);
}
void WindowShapeUpdater::OnWindowDestroying(aura::Window* window) {
window->RemoveObserver(this);
delete this;
}
void WindowShapeUpdater::UpdateWindowShapeFromWindowMask(aura::Window* window) {
// If |ui::Layer::alpha_shape_| is set explicitly from SetShape,
// we don't need to set default window mask from non_client_view.
if (tree_host_->is_shape_explicitly_set())
return;
// WindowTransparency should be updated as well when the window shape is
// changed. When a window mask exists, transparent should be true to prevent
// compositor from filling the entire screen in AppendQuadsToFillScreen.
// Otherwise, transparent should be false.
native_widget_aura_->UpdateWindowTransparency();
base::Optional<SkPath> path =
tree_host_->GetWindowMaskForWindowShape(window->bounds().size());
if (path.has_value()) {
// SetAlphaShape to the layer of |content_window_|
window->layer()->SetAlphaShape(ConvertToShapeRects(path.value()));
} else {
window->layer()->SetAlphaShape(nullptr);
}
}
} // namespace views
// Copyright 2021 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_VIEWS_WIDGET_DESKTOP_AURA_WINDOW_SHAPE_UPDATER_H_
#define UI_VIEWS_WIDGET_DESKTOP_AURA_WINDOW_SHAPE_UPDATER_H_
#include <memory>
#include "ui/aura/window_observer.h"
#include "ui/compositor/layer.h"
namespace views {
class DesktopNativeWidgetAura;
class DesktopWindowTreeHostPlatform;
// Class to observe the window bounds changed to update window shape
// for the rounded corner of the browser frame.
class WindowShapeUpdater : public aura::WindowObserver {
public:
static WindowShapeUpdater* CreateWindowShapeUpdater(
DesktopWindowTreeHostPlatform* tree_host,
DesktopNativeWidgetAura* native_widget_aura);
private:
WindowShapeUpdater(DesktopWindowTreeHostPlatform* tree_host,
DesktopNativeWidgetAura* native_widget_aura);
WindowShapeUpdater(const WindowShapeUpdater&) = delete;
WindowShapeUpdater& operator=(const WindowShapeUpdater&) = delete;
~WindowShapeUpdater() override = default;
// aura::WindowObserver:
void OnWindowBoundsChanged(aura::Window* window,
const gfx::Rect& old_bounds,
const gfx::Rect& new_bounds,
ui::PropertyChangeReason reason) override;
void OnWindowDestroying(aura::Window* window) override;
void UpdateWindowShapeFromWindowMask(aura::Window* window);
DesktopWindowTreeHostPlatform* tree_host_ = nullptr;
DesktopNativeWidgetAura* native_widget_aura_ = nullptr;
};
} // namespace views
#endif // UI_VIEWS_WIDGET_DESKTOP_AURA_WINDOW_SHAPE_UPDATER_H_
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