Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / ui / views / apps / shaped_app_window_targeter_unittest.cc
blob96a2790b6ad014fbfc71678572c46c08adc79721
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/ui/views/apps/shaped_app_window_targeter.h"
7 #include "apps/ui/views/app_window_frame_view.h"
8 #include "chrome/browser/ui/views/apps/chrome_native_app_window_views_aura.h"
9 #include "ui/aura/test/aura_test_base.h"
10 #include "ui/aura/window.h"
11 #include "ui/aura/window_event_dispatcher.h"
12 #include "ui/events/event_utils.h"
13 #include "ui/views/controls/webview/webview.h"
14 #include "ui/wm/core/default_activation_client.h"
15 #include "ui/wm/core/easy_resize_window_targeter.h"
17 class ShapedAppWindowTargeterTest : public aura::test::AuraTestBase {
18 public:
19 ShapedAppWindowTargeterTest()
20 : web_view_(NULL) {
23 ~ShapedAppWindowTargeterTest() override {}
25 views::Widget* widget() { return widget_.get(); }
27 extensions::NativeAppWindow* app_window() { return &app_window_; }
28 ChromeNativeAppWindowViewsAura* app_window_views() { return &app_window_; }
30 protected:
31 void SetUp() override {
32 aura::test::AuraTestBase::SetUp();
33 new wm::DefaultActivationClient(root_window());
34 widget_.reset(new views::Widget);
35 views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
36 params.remove_standard_frame = true;
37 params.bounds = gfx::Rect(30, 30, 100, 100);
38 params.context = root_window();
39 params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
40 widget_->Init(params);
42 app_window_.set_web_view_for_testing(&web_view_);
43 app_window_.set_window_for_testing(widget_.get());
45 widget_->Show();
48 void TearDown() override {
49 widget_.reset();
50 aura::test::AuraTestBase::TearDown();
53 private:
54 views::WebView web_view_;
55 scoped_ptr<views::Widget> widget_;
56 ChromeNativeAppWindowViewsAura app_window_;
58 DISALLOW_COPY_AND_ASSIGN(ShapedAppWindowTargeterTest);
61 TEST_F(ShapedAppWindowTargeterTest, HitTestBasic) {
62 aura::Window* window = widget()->GetNativeWindow();
64 // Without any custom shapes, the event should be targeted correctly to the
65 // window.
66 ui::MouseEvent move(ui::ET_MOUSE_MOVED, gfx::Point(40, 40),
67 gfx::Point(40, 40), ui::EventTimeForNow(), ui::EF_NONE,
68 ui::EF_NONE);
69 ui::EventDispatchDetails details =
70 event_processor()->OnEventFromSource(&move);
71 ASSERT_FALSE(details.dispatcher_destroyed);
72 EXPECT_EQ(window, move.target());
75 scoped_ptr<SkRegion> region(new SkRegion);
76 region->op(SkIRect::MakeXYWH(0, 0, 0, 0), SkRegion::kUnion_Op);
77 app_window()->UpdateShape(region.Pass());
79 // With an empty custom shape, all events within the window should fall
80 // through to the root window.
81 ui::MouseEvent move(ui::ET_MOUSE_MOVED, gfx::Point(40, 40),
82 gfx::Point(40, 40), ui::EventTimeForNow(), ui::EF_NONE,
83 ui::EF_NONE);
84 ui::EventDispatchDetails details =
85 event_processor()->OnEventFromSource(&move);
86 ASSERT_FALSE(details.dispatcher_destroyed);
87 EXPECT_EQ(root_window(), move.target());
90 // Window shape (global coordinates)
91 // 30 70 90 130
92 // 30 + +-----+
93 // . | | <- mouse move (40,40)
94 // 70 +--------+ +---------+
95 // | . | <- mouse move (80,80)
96 // 90 +--------+ +---------+
97 // | |
98 // 130 +-----+
99 region.reset(new SkRegion);
100 region->op(SkIRect::MakeXYWH(40, 0, 20, 100), SkRegion::kUnion_Op);
101 region->op(SkIRect::MakeXYWH(0, 40, 100, 20), SkRegion::kUnion_Op);
102 app_window()->UpdateShape(region.Pass());
104 // With the custom shape, the events that don't fall within the custom shape
105 // will go through to the root window.
106 ui::MouseEvent move(ui::ET_MOUSE_MOVED, gfx::Point(40, 40),
107 gfx::Point(40, 40), ui::EventTimeForNow(), ui::EF_NONE,
108 ui::EF_NONE);
109 ui::EventDispatchDetails details =
110 event_processor()->OnEventFromSource(&move);
111 ASSERT_FALSE(details.dispatcher_destroyed);
112 EXPECT_EQ(root_window(), move.target());
114 // But events within the shape will still reach the window.
115 ui::MouseEvent move2(ui::ET_MOUSE_MOVED, gfx::Point(80, 80),
116 gfx::Point(80, 80), ui::EventTimeForNow(), ui::EF_NONE,
117 ui::EF_NONE);
118 details = event_processor()->OnEventFromSource(&move2);
119 ASSERT_FALSE(details.dispatcher_destroyed);
120 EXPECT_EQ(window, move2.target());
124 TEST_F(ShapedAppWindowTargeterTest, HitTestOnlyForShapedWindow) {
125 // Install a window-targeter on the root window that allows a window to
126 // receive events outside of its bounds. Verify that this window-targeter is
127 // active unless the window has a custom shape.
128 gfx::Insets inset(-30, -30, -30, -30);
129 root_window()->SetEventTargeter(scoped_ptr<ui::EventTargeter>(
130 new wm::EasyResizeWindowTargeter(root_window(), inset, inset)));
132 aura::Window* window = widget()->GetNativeWindow();
134 // Without any custom shapes, an event within the window bounds should be
135 // targeted correctly to the window.
136 ui::MouseEvent move(ui::ET_MOUSE_MOVED, gfx::Point(40, 40),
137 gfx::Point(40, 40), ui::EventTimeForNow(), ui::EF_NONE,
138 ui::EF_NONE);
139 ui::EventDispatchDetails details =
140 event_processor()->OnEventFromSource(&move);
141 ASSERT_FALSE(details.dispatcher_destroyed);
142 EXPECT_EQ(window, move.target());
145 // Without any custom shapes, an event that falls just outside the window
146 // bounds should also be targeted correctly to the window, because of the
147 // targeter installed on the root-window.
148 ui::MouseEvent move(ui::ET_MOUSE_MOVED, gfx::Point(10, 10),
149 gfx::Point(10, 10), ui::EventTimeForNow(), ui::EF_NONE,
150 ui::EF_NONE);
151 ui::EventDispatchDetails details =
152 event_processor()->OnEventFromSource(&move);
153 ASSERT_FALSE(details.dispatcher_destroyed);
154 EXPECT_EQ(window, move.target());
157 scoped_ptr<SkRegion> region(new SkRegion);
158 region->op(SkIRect::MakeXYWH(40, 0, 20, 100), SkRegion::kUnion_Op);
159 region->op(SkIRect::MakeXYWH(0, 40, 100, 20), SkRegion::kUnion_Op);
160 app_window()->UpdateShape(region.Pass());
162 // With the custom shape, the events that don't fall within the custom shape
163 // will go through to the root window.
164 ui::MouseEvent move(ui::ET_MOUSE_MOVED, gfx::Point(10, 10),
165 gfx::Point(10, 10), ui::EventTimeForNow(), ui::EF_NONE,
166 ui::EF_NONE);
167 ui::EventDispatchDetails details =
168 event_processor()->OnEventFromSource(&move);
169 ASSERT_FALSE(details.dispatcher_destroyed);
170 EXPECT_EQ(root_window(), move.target());
173 // Remove the custom shape. This should restore the behaviour of targeting the
174 // app window for events just outside its bounds.
175 app_window()->UpdateShape(scoped_ptr<SkRegion>());
177 ui::MouseEvent move(ui::ET_MOUSE_MOVED, gfx::Point(10, 10),
178 gfx::Point(10, 10), ui::EventTimeForNow(), ui::EF_NONE,
179 ui::EF_NONE);
180 ui::EventDispatchDetails details =
181 event_processor()->OnEventFromSource(&move);
182 ASSERT_FALSE(details.dispatcher_destroyed);
183 EXPECT_EQ(window, move.target());
187 // Tests targeting of events on a window with an EasyResizeWindowTargeter
188 // installed on its container.
189 TEST_F(ShapedAppWindowTargeterTest, ResizeInsetsWithinBounds) {
190 aura::Window* window = widget()->GetNativeWindow();
192 // An event in the center of the window should always have
193 // |window| as its target.
194 ui::MouseEvent move(ui::ET_MOUSE_MOVED, gfx::Point(80, 80),
195 gfx::Point(80, 80), ui::EventTimeForNow(), ui::EF_NONE,
196 ui::EF_NONE);
197 ui::EventDispatchDetails details =
198 event_processor()->OnEventFromSource(&move);
199 ASSERT_FALSE(details.dispatcher_destroyed);
200 EXPECT_EQ(window, move.target());
203 // Without an EasyResizeTargeter on the container, an event
204 // inside the window and within 5px of an edge should have
205 // |window| as its target.
206 ui::MouseEvent move(ui::ET_MOUSE_MOVED, gfx::Point(32, 37),
207 gfx::Point(32, 37), ui::EventTimeForNow(), ui::EF_NONE,
208 ui::EF_NONE);
209 ui::EventDispatchDetails details =
210 event_processor()->OnEventFromSource(&move);
211 ASSERT_FALSE(details.dispatcher_destroyed);
212 EXPECT_EQ(window, move.target());
215 #if !defined(OS_CHROMEOS)
216 // The non standard app frame has a easy resize targetter installed.
217 scoped_ptr<views::NonClientFrameView> frame(
218 app_window_views()->CreateNonStandardAppFrame());
220 // Ensure that the window has an event targeter (there should be an
221 // EasyResizeWindowTargeter installed).
222 EXPECT_TRUE(static_cast<ui::EventTarget*>(window)->GetEventTargeter());
225 // An event in the center of the window should always have
226 // |window| as its target.
227 // TODO(mgiuca): This isn't really testing anything (note that it has the
228 // same expectation as the border case below). In the real environment, the
229 // target will actually be the RenderWidgetHostViewAura's window that is the
230 // child of the child of |window|, whereas in the border case it *will* be
231 // |window|. However, since this test environment does not have a
232 // RenderWidgetHostViewAura, we cannot differentiate the two cases. Fix
233 // the test environment so that the test can assert that non-border events
234 // bubble down to a child of |window|.
235 ui::MouseEvent move(ui::ET_MOUSE_MOVED, gfx::Point(80, 80),
236 gfx::Point(80, 80), ui::EventTimeForNow(), ui::EF_NONE,
237 ui::EF_NONE);
238 ui::EventDispatchDetails details =
239 event_processor()->OnEventFromSource(&move);
240 ASSERT_FALSE(details.dispatcher_destroyed);
241 EXPECT_EQ(window, move.target());
244 // With an EasyResizeTargeter on the container, an event
245 // inside the window and within 5px of an edge should have
246 // |window| as its target.
247 ui::MouseEvent move(ui::ET_MOUSE_MOVED, gfx::Point(32, 37),
248 gfx::Point(32, 37), ui::EventTimeForNow(), ui::EF_NONE,
249 ui::EF_NONE);
250 ui::EventDispatchDetails details =
251 event_processor()->OnEventFromSource(&move);
252 ASSERT_FALSE(details.dispatcher_destroyed);
253 EXPECT_EQ(window, move.target());
255 #endif // defined (OS_CHROMEOS)