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(
touch_insets);
}
void WindowPortMus::SetHitTestMask(const base::Optional<gfx::Rect>& rect) {
window_tree_client_->SetHitTestMask(this, rect);
}
void WindowPortMus::Embed(
ui::mojom::WindowTreeClientPtr client,
uint32_t flags,
......
......@@ -13,6 +13,7 @@
#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/optional.h"
#include "components/viz/client/client_layer_tree_frame_sink.h"
#include "components/viz/common/surfaces/surface_info.h"
#include "services/ui/public/interfaces/cursor/cursor.mojom.h"
......@@ -85,6 +86,9 @@ class AURA_EXPORT WindowPortMus : public WindowPort, public WindowMus {
void SetExtendedHitRegionForChildren(const gfx::Insets& mouse_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
// details on arguments.
void Embed(ui::mojom::WindowTreeClientPtr client,
......
......@@ -361,6 +361,18 @@ void WindowTreeClient::SetImeVisibility(WindowMus* window,
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(
Window* window,
ui::mojom::WindowTreeClientPtr client,
......@@ -2240,20 +2252,6 @@ void WindowTreeClient::OnWindowTreeHostClientAreaWillChange(
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(
WindowTreeHostMus* window_tree_host,
float opacity) {
......
......@@ -18,6 +18,7 @@
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/optional.h"
#include "base/single_thread_task_runner.h"
#include "components/viz/common/surfaces/parent_local_surface_id_allocator.h"
#include "mojo/public/cpp/bindings/associated_binding.h"
......@@ -146,6 +147,7 @@ class AURA_EXPORT WindowTreeClient
void SetImeVisibility(WindowMus* window,
bool visible,
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
// by kEmbedFlag*; 0 gives default behavior. |callback| is called to indicate
......@@ -548,9 +550,6 @@ class AURA_EXPORT WindowTreeClient
WindowTreeHostMus* window_tree_host,
const gfx::Insets& client_area,
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,
float opacity) override;
void OnWindowTreeHostDeactivateWindow(
......
......@@ -130,10 +130,6 @@ void WindowTreeHostMus::SetClientArea(
additional_client_area);
}
void WindowTreeHostMus::SetHitTestMask(const base::Optional<gfx::Rect>& rect) {
delegate_->OnWindowTreeHostHitTestMaskWillChange(this, rect);
}
void WindowTreeHostMus::SetOpacity(float value) {
delegate_->OnWindowTreeHostSetOpacity(this, value);
}
......
......@@ -52,10 +52,6 @@ class AURA_EXPORT WindowTreeHostMus : public WindowTreeHostPlatform {
void SetClientArea(const gfx::Insets& insets,
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.
void SetOpacity(float value);
......
......@@ -37,11 +37,6 @@ class AURA_EXPORT WindowTreeHostMusDelegate {
const gfx::Insets& client_area,
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.
virtual void OnWindowTreeHostSetOpacity(WindowTreeHostMus* window_tree_host,
float opacity) = 0;
......
......@@ -5,6 +5,7 @@
#include "ui/aura/mus/window_tree_host_mus.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/test/aura_mus_test_base.h"
#include "ui/aura/test/mus/test_window_tree.h"
......@@ -30,11 +31,12 @@ TEST_F(WindowTreeHostMusTest, SetHitTestMask) {
EXPECT_FALSE(window_tree()->last_hit_test_mask().has_value());
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());
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());
}
......
......@@ -253,7 +253,7 @@ void DesktopWindowTreeHostMus::SendClientAreaToServer() {
void DesktopWindowTreeHostMus::SendHitTestMaskToServer() {
if (!native_widget_delegate_->HasHitTestMask()) {
SetHitTestMask(base::nullopt);
aura::WindowPortMus::Get(window())->SetHitTestMask(base::nullopt);
return;
}
......@@ -262,7 +262,7 @@ void DesktopWindowTreeHostMus::SendHitTestMaskToServer() {
// TODO(jamescook): Use the full path for the mask.
gfx::Rect mask_rect =
gfx::ToEnclosingRect(gfx::SkRectToRectF(mask_path.getBounds()));
SetHitTestMask(mask_rect);
aura::WindowPortMus::Get(window())->SetHitTestMask(mask_rect);
}
bool DesktopWindowTreeHostMus::IsFocusClientInstalledOnFocusSynchronizer()
......
......@@ -125,6 +125,7 @@ test("wm_unittests") {
"core/compound_event_filter_unittest.cc",
"core/coordinate_conversion_unittest.cc",
"core/cursor_manager_unittest.cc",
"core/easy_resize_window_targeter_unittest.cc",
"core/focus_controller_unittest.cc",
"core/shadow_controller_unittest.cc",
"core/shadow_unittest.cc",
......
......@@ -23,17 +23,65 @@ namespace {
// Returns an insets whose values are all negative or 0. Any positive value is
// forced to 0.
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()),
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
// 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(
aura::Window* container,
const gfx::Insets& mouse_extend,
......@@ -52,8 +100,6 @@ void EasyResizeWindowTargeter::OnSetInsets(
return;
// 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 =
InsetsWithOnlyNegativeValues(last_mouse_extend);
const gfx::Insets effective_last_touch_extend =
......@@ -62,14 +108,23 @@ void EasyResizeWindowTargeter::OnSetInsets(
InsetsWithOnlyNegativeValues(mouse_extend());
const gfx::Insets effective_touch_extend =
InsetsWithOnlyNegativeValues(touch_extend());
if (effective_last_touch_extend == effective_touch_extend &&
effective_last_mouse_extend == effective_mouse_extend) {
return;
if (effective_last_touch_extend != effective_touch_extend ||
effective_last_mouse_extend != effective_mouse_extend) {
aura::WindowPortMus::Get(container_)
->SetExtendedHitRegionForChildren(effective_mouse_extend,
effective_touch_extend);
}
aura::WindowPortMus::Get(container_)
->SetExtendedHitRegionForChildren(effective_mouse_extend,
effective_touch_extend);
// Positive values equate to a hit test mask.
const gfx::Insets positive_mouse_insets =
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(
......
......@@ -31,6 +31,8 @@ class WM_CORE_EXPORT EasyResizeWindowTargeter : public aura::WindowTargeter {
const gfx::Insets& last_touch_extend) override;
private:
class HitMaskSetter;
// aura::WindowTargeter:
// Delegates to WindowTargeter's impl and prevents overriding in subclasses.
bool EventLocationInsideBounds(aura::Window* target,
......@@ -42,6 +44,8 @@ class WM_CORE_EXPORT EasyResizeWindowTargeter : public aura::WindowTargeter {
aura::Window* container_;
std::unique_ptr<HitMaskSetter> hit_mask_setter_;
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