Commit 7a024b0d authored by Scott Violet's avatar Scott Violet Committed by Commit Bot

chromeos: makes EasyResizeWindowTargeter apply a hit mask if appropriate

EasyResizeWindowTargeter may be used to shrink the region of a window
you can interact with (the shelf uses this in certain modes). For mus
we only support this with a hit-test mask. This patch wires up
EasyResizeWindowTargeter to use a hit-test mask when necessary.

BUG=775223
TEST=covered by test

Change-Id: I3e1b494e890f0f8366ce4a8a1fc64f839a61542f
Reviewed-on: https://chromium-review.googlesource.com/826032
Commit-Queue: Scott Violet <sky@chromium.org>
Reviewed-by: default avatarElliot Glaysher <erg@chromium.org>
Cr-Commit-Position: refs/heads/master@{#524019}
parent 723f17c7
...@@ -91,6 +91,10 @@ void WindowPortMus::SetExtendedHitRegionForChildren( ...@@ -91,6 +91,10 @@ void WindowPortMus::SetExtendedHitRegionForChildren(
touch_insets); touch_insets);
} }
void WindowPortMus::SetHitTestMask(const base::Optional<gfx::Rect>& rect) {
window_tree_client_->SetHitTestMask(this, rect);
}
void WindowPortMus::Embed( void WindowPortMus::Embed(
ui::mojom::WindowTreeClientPtr client, ui::mojom::WindowTreeClientPtr client,
uint32_t flags, uint32_t flags,
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "base/logging.h" #include "base/logging.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/optional.h"
#include "components/viz/client/client_layer_tree_frame_sink.h" #include "components/viz/client/client_layer_tree_frame_sink.h"
#include "components/viz/common/surfaces/surface_info.h" #include "components/viz/common/surfaces/surface_info.h"
#include "services/ui/public/interfaces/cursor/cursor.mojom.h" #include "services/ui/public/interfaces/cursor/cursor.mojom.h"
...@@ -85,6 +86,9 @@ class AURA_EXPORT WindowPortMus : public WindowPort, public WindowMus { ...@@ -85,6 +86,9 @@ class AURA_EXPORT WindowPortMus : public WindowPort, public WindowMus {
void SetExtendedHitRegionForChildren(const gfx::Insets& mouse_insets, void SetExtendedHitRegionForChildren(const gfx::Insets& mouse_insets,
const gfx::Insets& touch_insets); const gfx::Insets& touch_insets);
// See description in mojom for details on this.
void SetHitTestMask(const base::Optional<gfx::Rect>& rect);
// Embeds a new client in this Window. See WindowTreeClient::Embed() for // Embeds a new client in this Window. See WindowTreeClient::Embed() for
// details on arguments. // details on arguments.
void Embed(ui::mojom::WindowTreeClientPtr client, void Embed(ui::mojom::WindowTreeClientPtr client,
......
...@@ -361,6 +361,18 @@ void WindowTreeClient::SetImeVisibility(WindowMus* window, ...@@ -361,6 +361,18 @@ void WindowTreeClient::SetImeVisibility(WindowMus* window,
tree_->SetImeVisibility(window->server_id(), visible, std::move(state)); tree_->SetImeVisibility(window->server_id(), visible, std::move(state));
} }
void WindowTreeClient::SetHitTestMask(
WindowMus* window,
const base::Optional<gfx::Rect>& mask_rect) {
base::Optional<gfx::Rect> out_rect = base::nullopt;
if (mask_rect) {
out_rect = gfx::ConvertRectToPixel(window->GetDeviceScaleFactor(),
mask_rect.value());
}
tree_->SetHitTestMask(window->server_id(), out_rect);
}
void WindowTreeClient::Embed( void WindowTreeClient::Embed(
Window* window, Window* window,
ui::mojom::WindowTreeClientPtr client, ui::mojom::WindowTreeClientPtr client,
...@@ -2240,20 +2252,6 @@ void WindowTreeClient::OnWindowTreeHostClientAreaWillChange( ...@@ -2240,20 +2252,6 @@ void WindowTreeClient::OnWindowTreeHostClientAreaWillChange(
additional_client_areas_in_pixel); additional_client_areas_in_pixel);
} }
void WindowTreeClient::OnWindowTreeHostHitTestMaskWillChange(
WindowTreeHostMus* window_tree_host,
const base::Optional<gfx::Rect>& mask_rect) {
WindowMus* window = WindowMus::Get(window_tree_host->window());
base::Optional<gfx::Rect> out_rect = base::nullopt;
if (mask_rect) {
out_rect = gfx::ConvertRectToPixel(window->GetDeviceScaleFactor(),
mask_rect.value());
}
tree_->SetHitTestMask(window->server_id(), out_rect);
}
void WindowTreeClient::OnWindowTreeHostSetOpacity( void WindowTreeClient::OnWindowTreeHostSetOpacity(
WindowTreeHostMus* window_tree_host, WindowTreeHostMus* window_tree_host,
float opacity) { float opacity) {
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/observer_list.h" #include "base/observer_list.h"
#include "base/optional.h"
#include "base/single_thread_task_runner.h" #include "base/single_thread_task_runner.h"
#include "components/viz/common/surfaces/parent_local_surface_id_allocator.h" #include "components/viz/common/surfaces/parent_local_surface_id_allocator.h"
#include "mojo/public/cpp/bindings/associated_binding.h" #include "mojo/public/cpp/bindings/associated_binding.h"
...@@ -146,6 +147,7 @@ class AURA_EXPORT WindowTreeClient ...@@ -146,6 +147,7 @@ class AURA_EXPORT WindowTreeClient
void SetImeVisibility(WindowMus* window, void SetImeVisibility(WindowMus* window,
bool visible, bool visible,
ui::mojom::TextInputStatePtr state); ui::mojom::TextInputStatePtr state);
void SetHitTestMask(WindowMus* window, const base::Optional<gfx::Rect>& rect);
// Embeds a new client in |window|. |flags| is a bitmask of the values defined // Embeds a new client in |window|. |flags| is a bitmask of the values defined
// by kEmbedFlag*; 0 gives default behavior. |callback| is called to indicate // by kEmbedFlag*; 0 gives default behavior. |callback| is called to indicate
...@@ -548,9 +550,6 @@ class AURA_EXPORT WindowTreeClient ...@@ -548,9 +550,6 @@ class AURA_EXPORT WindowTreeClient
WindowTreeHostMus* window_tree_host, WindowTreeHostMus* window_tree_host,
const gfx::Insets& client_area, const gfx::Insets& client_area,
const std::vector<gfx::Rect>& additional_client_areas) override; const std::vector<gfx::Rect>& additional_client_areas) override;
void OnWindowTreeHostHitTestMaskWillChange(
WindowTreeHostMus* window_tree_host,
const base::Optional<gfx::Rect>& mask_rect) override;
void OnWindowTreeHostSetOpacity(WindowTreeHostMus* window_tree_host, void OnWindowTreeHostSetOpacity(WindowTreeHostMus* window_tree_host,
float opacity) override; float opacity) override;
void OnWindowTreeHostDeactivateWindow( void OnWindowTreeHostDeactivateWindow(
......
...@@ -130,10 +130,6 @@ void WindowTreeHostMus::SetClientArea( ...@@ -130,10 +130,6 @@ void WindowTreeHostMus::SetClientArea(
additional_client_area); additional_client_area);
} }
void WindowTreeHostMus::SetHitTestMask(const base::Optional<gfx::Rect>& rect) {
delegate_->OnWindowTreeHostHitTestMaskWillChange(this, rect);
}
void WindowTreeHostMus::SetOpacity(float value) { void WindowTreeHostMus::SetOpacity(float value) {
delegate_->OnWindowTreeHostSetOpacity(this, value); delegate_->OnWindowTreeHostSetOpacity(this, value);
} }
......
...@@ -52,10 +52,6 @@ class AURA_EXPORT WindowTreeHostMus : public WindowTreeHostPlatform { ...@@ -52,10 +52,6 @@ class AURA_EXPORT WindowTreeHostMus : public WindowTreeHostPlatform {
void SetClientArea(const gfx::Insets& insets, void SetClientArea(const gfx::Insets& insets,
const std::vector<gfx::Rect>& additional_client_area); const std::vector<gfx::Rect>& additional_client_area);
// Sets the hit test mask on the underlying mus window. Pass base::nullopt to
// clear.
void SetHitTestMask(const base::Optional<gfx::Rect>& rect);
// Sets the opacity of the underlying mus window. // Sets the opacity of the underlying mus window.
void SetOpacity(float value); void SetOpacity(float value);
......
...@@ -37,11 +37,6 @@ class AURA_EXPORT WindowTreeHostMusDelegate { ...@@ -37,11 +37,6 @@ class AURA_EXPORT WindowTreeHostMusDelegate {
const gfx::Insets& client_area, const gfx::Insets& client_area,
const std::vector<gfx::Rect>& additional_client_areas) = 0; const std::vector<gfx::Rect>& additional_client_areas) = 0;
// Called when the hit test mask is about to be cleared.
virtual void OnWindowTreeHostHitTestMaskWillChange(
WindowTreeHostMus* window_tree_host,
const base::Optional<gfx::Rect>& mask_rect) = 0;
// Called when the opacity is changed client side. // Called when the opacity is changed client side.
virtual void OnWindowTreeHostSetOpacity(WindowTreeHostMus* window_tree_host, virtual void OnWindowTreeHostSetOpacity(WindowTreeHostMus* window_tree_host,
float opacity) = 0; float opacity) = 0;
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include "ui/aura/mus/window_tree_host_mus.h" #include "ui/aura/mus/window_tree_host_mus.h"
#include "base/memory/ptr_util.h" #include "base/memory/ptr_util.h"
#include "ui/aura/mus/window_port_mus.h"
#include "ui/aura/mus/window_tree_host_mus_init_params.h" #include "ui/aura/mus/window_tree_host_mus_init_params.h"
#include "ui/aura/test/aura_mus_test_base.h" #include "ui/aura/test/aura_mus_test_base.h"
#include "ui/aura/test/mus/test_window_tree.h" #include "ui/aura/test/mus/test_window_tree.h"
...@@ -30,11 +31,12 @@ TEST_F(WindowTreeHostMusTest, SetHitTestMask) { ...@@ -30,11 +31,12 @@ TEST_F(WindowTreeHostMusTest, SetHitTestMask) {
EXPECT_FALSE(window_tree()->last_hit_test_mask().has_value()); EXPECT_FALSE(window_tree()->last_hit_test_mask().has_value());
gfx::Rect mask(10, 10, 10, 10); gfx::Rect mask(10, 10, 10, 10);
window_tree_host_mus->SetHitTestMask(mask); WindowPortMus::Get(window_tree_host_mus->window())->SetHitTestMask(mask);
ASSERT_TRUE(window_tree()->last_hit_test_mask().has_value()); ASSERT_TRUE(window_tree()->last_hit_test_mask().has_value());
EXPECT_EQ(mask, window_tree()->last_hit_test_mask()); EXPECT_EQ(mask, window_tree()->last_hit_test_mask());
window_tree_host_mus->SetHitTestMask(base::nullopt); WindowPortMus::Get(window_tree_host_mus->window())
->SetHitTestMask(base::nullopt);
ASSERT_FALSE(window_tree()->last_hit_test_mask().has_value()); ASSERT_FALSE(window_tree()->last_hit_test_mask().has_value());
} }
......
...@@ -253,7 +253,7 @@ void DesktopWindowTreeHostMus::SendClientAreaToServer() { ...@@ -253,7 +253,7 @@ void DesktopWindowTreeHostMus::SendClientAreaToServer() {
void DesktopWindowTreeHostMus::SendHitTestMaskToServer() { void DesktopWindowTreeHostMus::SendHitTestMaskToServer() {
if (!native_widget_delegate_->HasHitTestMask()) { if (!native_widget_delegate_->HasHitTestMask()) {
SetHitTestMask(base::nullopt); aura::WindowPortMus::Get(window())->SetHitTestMask(base::nullopt);
return; return;
} }
...@@ -262,7 +262,7 @@ void DesktopWindowTreeHostMus::SendHitTestMaskToServer() { ...@@ -262,7 +262,7 @@ void DesktopWindowTreeHostMus::SendHitTestMaskToServer() {
// TODO(jamescook): Use the full path for the mask. // TODO(jamescook): Use the full path for the mask.
gfx::Rect mask_rect = gfx::Rect mask_rect =
gfx::ToEnclosingRect(gfx::SkRectToRectF(mask_path.getBounds())); gfx::ToEnclosingRect(gfx::SkRectToRectF(mask_path.getBounds()));
SetHitTestMask(mask_rect); aura::WindowPortMus::Get(window())->SetHitTestMask(mask_rect);
} }
bool DesktopWindowTreeHostMus::IsFocusClientInstalledOnFocusSynchronizer() bool DesktopWindowTreeHostMus::IsFocusClientInstalledOnFocusSynchronizer()
......
...@@ -125,6 +125,7 @@ test("wm_unittests") { ...@@ -125,6 +125,7 @@ test("wm_unittests") {
"core/compound_event_filter_unittest.cc", "core/compound_event_filter_unittest.cc",
"core/coordinate_conversion_unittest.cc", "core/coordinate_conversion_unittest.cc",
"core/cursor_manager_unittest.cc", "core/cursor_manager_unittest.cc",
"core/easy_resize_window_targeter_unittest.cc",
"core/focus_controller_unittest.cc", "core/focus_controller_unittest.cc",
"core/shadow_controller_unittest.cc", "core/shadow_controller_unittest.cc",
"core/shadow_unittest.cc", "core/shadow_unittest.cc",
......
...@@ -23,17 +23,65 @@ namespace { ...@@ -23,17 +23,65 @@ namespace {
// Returns an insets whose values are all negative or 0. Any positive value is // Returns an insets whose values are all negative or 0. Any positive value is
// forced to 0. // forced to 0.
gfx::Insets InsetsWithOnlyNegativeValues(const gfx::Insets& insets) { gfx::Insets InsetsWithOnlyNegativeValues(const gfx::Insets& insets) {
if (insets.top() > 0 || insets.left() > 0 || insets.right() > 0 ||
insets.bottom() > 0) {
// See TODO at call site.
NOTIMPLEMENTED_LOG_ONCE();
}
return gfx::Insets(std::min(0, insets.top()), std::min(0, insets.left()), return gfx::Insets(std::min(0, insets.top()), std::min(0, insets.left()),
std::min(0, insets.bottom()), std::min(0, insets.right())); std::min(0, insets.bottom()), std::min(0, insets.right()));
} }
gfx::Insets InsetsWithOnlyPositiveValues(const gfx::Insets& insets) {
return gfx::Insets(std::max(0, insets.top()), std::max(0, insets.left()),
std::max(0, insets.bottom()), std::max(0, insets.right()));
}
} // namespace } // namespace
// HitMaskSetter is responsible for setting the hit-test mask on a Window.
class EasyResizeWindowTargeter::HitMaskSetter : public aura::WindowObserver {
public:
explicit HitMaskSetter(aura::Window* window) : window_(window) {
window_->AddObserver(this);
}
~HitMaskSetter() override {
if (window_) {
aura::WindowPortMus::Get(window_)->SetHitTestMask(base::nullopt);
window_->RemoveObserver(this);
}
}
void SetHitMaskInsets(const gfx::Insets& insets) {
if (insets == insets_)
return;
insets_ = insets;
ApplyHitTestMask();
}
private:
void ApplyHitTestMask() {
base::Optional<gfx::Rect> hit_test_mask(
gfx::Rect(window_->bounds().size()));
hit_test_mask->Inset(insets_);
aura::WindowPortMus::Get(window_)->SetHitTestMask(hit_test_mask);
}
// aura::WindowObserver:
void OnWindowDestroying(aura::Window* window) override {
window_->RemoveObserver(this);
window_ = nullptr;
}
void OnWindowBoundsChanged(aura::Window* window,
const gfx::Rect& old_bounds,
const gfx::Rect& new_bounds,
ui::PropertyChangeReason reason) override {
ApplyHitTestMask();
}
private:
aura::Window* window_;
gfx::Insets insets_;
DISALLOW_COPY_AND_ASSIGN(HitMaskSetter);
};
EasyResizeWindowTargeter::EasyResizeWindowTargeter( EasyResizeWindowTargeter::EasyResizeWindowTargeter(
aura::Window* container, aura::Window* container,
const gfx::Insets& mouse_extend, const gfx::Insets& mouse_extend,
...@@ -52,8 +100,6 @@ void EasyResizeWindowTargeter::OnSetInsets( ...@@ -52,8 +100,6 @@ void EasyResizeWindowTargeter::OnSetInsets(
return; return;
// Mus only accepts 0 or negative values, force all values to fit that. // Mus only accepts 0 or negative values, force all values to fit that.
// TODO: figure out how best to deal with positive values, see
// http://crbug.com/775223
const gfx::Insets effective_last_mouse_extend = const gfx::Insets effective_last_mouse_extend =
InsetsWithOnlyNegativeValues(last_mouse_extend); InsetsWithOnlyNegativeValues(last_mouse_extend);
const gfx::Insets effective_last_touch_extend = const gfx::Insets effective_last_touch_extend =
...@@ -62,14 +108,23 @@ void EasyResizeWindowTargeter::OnSetInsets( ...@@ -62,14 +108,23 @@ void EasyResizeWindowTargeter::OnSetInsets(
InsetsWithOnlyNegativeValues(mouse_extend()); InsetsWithOnlyNegativeValues(mouse_extend());
const gfx::Insets effective_touch_extend = const gfx::Insets effective_touch_extend =
InsetsWithOnlyNegativeValues(touch_extend()); InsetsWithOnlyNegativeValues(touch_extend());
if (effective_last_touch_extend == effective_touch_extend && if (effective_last_touch_extend != effective_touch_extend ||
effective_last_mouse_extend == effective_mouse_extend) { effective_last_mouse_extend != effective_mouse_extend) {
return; aura::WindowPortMus::Get(container_)
->SetExtendedHitRegionForChildren(effective_mouse_extend,
effective_touch_extend);
} }
aura::WindowPortMus::Get(container_) // Positive values equate to a hit test mask.
->SetExtendedHitRegionForChildren(effective_mouse_extend, const gfx::Insets positive_mouse_insets =
effective_touch_extend); InsetsWithOnlyPositiveValues(mouse_extend());
if (positive_mouse_insets.IsEmpty()) {
hit_mask_setter_.reset();
} else {
if (!hit_mask_setter_)
hit_mask_setter_ = std::make_unique<HitMaskSetter>(container_);
hit_mask_setter_->SetHitMaskInsets(positive_mouse_insets);
}
} }
bool EasyResizeWindowTargeter::EventLocationInsideBounds( bool EasyResizeWindowTargeter::EventLocationInsideBounds(
......
...@@ -31,6 +31,8 @@ class WM_CORE_EXPORT EasyResizeWindowTargeter : public aura::WindowTargeter { ...@@ -31,6 +31,8 @@ class WM_CORE_EXPORT EasyResizeWindowTargeter : public aura::WindowTargeter {
const gfx::Insets& last_touch_extend) override; const gfx::Insets& last_touch_extend) override;
private: private:
class HitMaskSetter;
// aura::WindowTargeter: // aura::WindowTargeter:
// Delegates to WindowTargeter's impl and prevents overriding in subclasses. // Delegates to WindowTargeter's impl and prevents overriding in subclasses.
bool EventLocationInsideBounds(aura::Window* target, bool EventLocationInsideBounds(aura::Window* target,
...@@ -42,6 +44,8 @@ class WM_CORE_EXPORT EasyResizeWindowTargeter : public aura::WindowTargeter { ...@@ -42,6 +44,8 @@ class WM_CORE_EXPORT EasyResizeWindowTargeter : public aura::WindowTargeter {
aura::Window* container_; aura::Window* container_;
std::unique_ptr<HitMaskSetter> hit_mask_setter_;
DISALLOW_COPY_AND_ASSIGN(EasyResizeWindowTargeter); DISALLOW_COPY_AND_ASSIGN(EasyResizeWindowTargeter);
}; };
......
// Copyright 2017 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/wm/core/easy_resize_window_targeter.h"
#include "ui/aura/mus/window_port_mus.h"
#include "ui/aura/test/aura_mus_test_base.h"
#include "ui/aura/test/mus/test_window_tree.h"
#include "ui/aura/window.h"
#include "ui/compositor/layer_type.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/gfx/geometry/rect.h"
namespace wm {
namespace {
class TestEasyResizeWindowTargeter : public EasyResizeWindowTargeter {
public:
explicit TestEasyResizeWindowTargeter(aura::Window* window)
: EasyResizeWindowTargeter(window, gfx::Insets(), gfx::Insets()) {}
~TestEasyResizeWindowTargeter() override = default;
void SetInsets(const gfx::Insets& mouse_extend,
const gfx::Insets& touch_extend) {
EasyResizeWindowTargeter::SetInsets(mouse_extend, touch_extend);
}
private:
DISALLOW_COPY_AND_ASSIGN(TestEasyResizeWindowTargeter);
};
} // namespace
using EasyResizeWindowTargeterTest = aura::test::AuraMusClientTestBase;
TEST_F(EasyResizeWindowTargeterTest, SetHitTestMask) {
aura::Window window(nullptr);
window.Init(ui::LAYER_NOT_DRAWN);
TestEasyResizeWindowTargeter window_targeter(&window);
const gfx::Rect bounds1 = gfx::Rect(10, 20, 200, 300);
window.SetBounds(bounds1);
const gfx::Insets insets1(1, 2, 3, 4);
window_targeter.SetInsets(insets1, insets1);
ASSERT_TRUE(window_tree()->last_hit_test_mask().has_value());
EXPECT_EQ(gfx::Rect(insets1.left(), insets1.top(),
bounds1.width() - insets1.width(),
bounds1.height() - insets1.height()),
*window_tree()->last_hit_test_mask());
// Adjusting the bounds should trigger resetting the mask.
const gfx::Rect bounds2 = gfx::Rect(10, 20, 300, 400);
window.SetBounds(bounds2);
ASSERT_TRUE(window_tree()->last_hit_test_mask().has_value());
EXPECT_EQ(gfx::Rect(insets1.left(), insets1.top(),
bounds2.width() - insets1.width(),
bounds2.height() - insets1.height()),
*window_tree()->last_hit_test_mask());
// Empty insets should reset the mask.
window_targeter.SetInsets(gfx::Insets(), gfx::Insets());
EXPECT_FALSE(window_tree()->last_hit_test_mask().has_value());
const gfx::Insets insets2(-1, 3, 4, 5);
const gfx::Insets effective_insets2(0, 3, 4, 5);
window_targeter.SetInsets(insets2, insets2);
ASSERT_TRUE(window_tree()->last_hit_test_mask().has_value());
EXPECT_EQ(gfx::Rect(effective_insets2.left(), effective_insets2.top(),
bounds2.width() - effective_insets2.width(),
bounds2.height() - effective_insets2.height()),
*window_tree()->last_hit_test_mask());
}
} // namespace wm
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