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.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/views/controls/webview/webview.h"
13 #include "ui/wm/core/default_activation_client.h"
14 #include "ui/wm/core/easy_resize_window_targeter.h"
16 class ShapedAppWindowTargeterTest
: public aura::test::AuraTestBase
{
18 ShapedAppWindowTargeterTest()
22 virtual ~ShapedAppWindowTargeterTest() {}
24 views::Widget
* widget() { return widget_
.get(); }
26 apps::NativeAppWindow
* app_window() { return &app_window_
; }
27 ChromeNativeAppWindowViews
* app_window_views() { return &app_window_
; }
30 virtual void SetUp() OVERRIDE
{
31 aura::test::AuraTestBase::SetUp();
32 new wm::DefaultActivationClient(root_window());
33 widget_
.reset(new views::Widget
);
34 views::Widget::InitParams
params(views::Widget::InitParams::TYPE_WINDOW
);
35 params
.remove_standard_frame
= true;
36 params
.bounds
= gfx::Rect(30, 30, 100, 100);
37 params
.context
= root_window();
38 params
.ownership
= views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
39 widget_
->Init(params
);
41 app_window_
.set_web_view_for_testing(&web_view_
);
42 app_window_
.set_window_for_testing(widget_
.get());
47 virtual void TearDown() OVERRIDE
{
49 aura::test::AuraTestBase::TearDown();
53 views::WebView web_view_
;
54 scoped_ptr
<views::Widget
> widget_
;
55 ChromeNativeAppWindowViews app_window_
;
57 DISALLOW_COPY_AND_ASSIGN(ShapedAppWindowTargeterTest
);
60 TEST_F(ShapedAppWindowTargeterTest
, HitTestBasic
) {
61 aura::Window
* window
= widget()->GetNativeWindow();
63 // Without any custom shapes, the event should be targeted correctly to the
65 ui::MouseEvent
move(ui::ET_MOUSE_MOVED
,
66 gfx::Point(40, 40), gfx::Point(40, 40),
67 ui::EF_NONE
, ui::EF_NONE
);
68 ui::EventDispatchDetails details
=
69 event_processor()->OnEventFromSource(&move
);
70 ASSERT_FALSE(details
.dispatcher_destroyed
);
71 EXPECT_EQ(window
, move
.target());
74 scoped_ptr
<SkRegion
> region(new SkRegion
);
75 region
->op(SkIRect::MakeXYWH(40, 0, 20, 100), SkRegion::kUnion_Op
);
76 region
->op(SkIRect::MakeXYWH(0, 40, 100, 20), SkRegion::kUnion_Op
);
77 app_window()->UpdateShape(region
.Pass());
79 // With the custom shape, the events that don't fall within the custom shape
80 // will go through to the root window.
81 ui::MouseEvent
move(ui::ET_MOUSE_MOVED
,
82 gfx::Point(40, 40), gfx::Point(40, 40),
83 ui::EF_NONE
, 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());
89 // But events within the shape will still reach the window.
90 ui::MouseEvent
move2(ui::ET_MOUSE_MOVED
,
91 gfx::Point(80, 80), gfx::Point(80, 80),
92 ui::EF_NONE
, ui::EF_NONE
);
93 details
= event_processor()->OnEventFromSource(&move2
);
94 ASSERT_FALSE(details
.dispatcher_destroyed
);
95 EXPECT_EQ(window
, move2
.target());
99 TEST_F(ShapedAppWindowTargeterTest
, HitTestOnlyForShapedWindow
) {
100 // Install a window-targeter on the root window that allows a window to
101 // receive events outside of its bounds. Verify that this window-targeter is
102 // active unless the window has a custom shape.
103 gfx::Insets
inset(-30, -30, -30, -30);
104 root_window()->SetEventTargeter(scoped_ptr
<ui::EventTargeter
>(
105 new wm::EasyResizeWindowTargeter(root_window(), inset
, inset
)));
107 aura::Window
* window
= widget()->GetNativeWindow();
109 // Without any custom shapes, an event within the window bounds should be
110 // targeted correctly to the window.
111 ui::MouseEvent
move(ui::ET_MOUSE_MOVED
,
112 gfx::Point(40, 40), gfx::Point(40, 40),
113 ui::EF_NONE
, ui::EF_NONE
);
114 ui::EventDispatchDetails details
=
115 event_processor()->OnEventFromSource(&move
);
116 ASSERT_FALSE(details
.dispatcher_destroyed
);
117 EXPECT_EQ(window
, move
.target());
120 // Without any custom shapes, an event that falls just outside the window
121 // bounds should also be targeted correctly to the window, because of the
122 // targeter installed on the root-window.
123 ui::MouseEvent
move(ui::ET_MOUSE_MOVED
,
124 gfx::Point(10, 10), gfx::Point(10, 10),
125 ui::EF_NONE
, ui::EF_NONE
);
126 ui::EventDispatchDetails details
=
127 event_processor()->OnEventFromSource(&move
);
128 ASSERT_FALSE(details
.dispatcher_destroyed
);
129 EXPECT_EQ(window
, move
.target());
132 scoped_ptr
<SkRegion
> region(new SkRegion
);
133 region
->op(SkIRect::MakeXYWH(40, 0, 20, 100), SkRegion::kUnion_Op
);
134 region
->op(SkIRect::MakeXYWH(0, 40, 100, 20), SkRegion::kUnion_Op
);
135 app_window()->UpdateShape(region
.Pass());
137 // With the custom shape, the events that don't fall within the custom shape
138 // will go through to the root window.
139 ui::MouseEvent
move(ui::ET_MOUSE_MOVED
,
140 gfx::Point(10, 10), gfx::Point(10, 10),
141 ui::EF_NONE
, ui::EF_NONE
);
142 ui::EventDispatchDetails details
=
143 event_processor()->OnEventFromSource(&move
);
144 ASSERT_FALSE(details
.dispatcher_destroyed
);
145 EXPECT_EQ(root_window(), move
.target());
148 // Remove the custom shape. This should restore the behaviour of targeting the
149 // app window for events just outside its bounds.
150 app_window()->UpdateShape(scoped_ptr
<SkRegion
>());
152 ui::MouseEvent
move(ui::ET_MOUSE_MOVED
,
153 gfx::Point(10, 10), gfx::Point(10, 10),
154 ui::EF_NONE
, ui::EF_NONE
);
155 ui::EventDispatchDetails details
=
156 event_processor()->OnEventFromSource(&move
);
157 ASSERT_FALSE(details
.dispatcher_destroyed
);
158 EXPECT_EQ(window
, move
.target());
162 // Tests targeting of events on a window with an EasyResizeWindowTargeter
163 // installed on its container.
164 TEST_F(ShapedAppWindowTargeterTest
, ResizeInsetsWithinBounds
) {
165 aura::Window
* window
= widget()->GetNativeWindow();
167 // An event in the center of the window should always have
168 // |window| as its target.
169 ui::MouseEvent
move(ui::ET_MOUSE_MOVED
,
170 gfx::Point(80, 80), gfx::Point(80, 80),
171 ui::EF_NONE
, ui::EF_NONE
);
172 ui::EventDispatchDetails details
=
173 event_processor()->OnEventFromSource(&move
);
174 ASSERT_FALSE(details
.dispatcher_destroyed
);
175 EXPECT_EQ(window
, move
.target());
178 // Without an EasyResizeTargeter on the container, an event
179 // inside the window and within 5px of an edge should have
180 // |window| as its target.
181 ui::MouseEvent
move(ui::ET_MOUSE_MOVED
,
182 gfx::Point(32, 37), gfx::Point(32, 37),
183 ui::EF_NONE
, ui::EF_NONE
);
184 ui::EventDispatchDetails details
=
185 event_processor()->OnEventFromSource(&move
);
186 ASSERT_FALSE(details
.dispatcher_destroyed
);
187 EXPECT_EQ(window
, move
.target());
190 #if !defined(OS_CHROMEOS)
191 // The non standard app frame has a easy resize targetter installed.
192 scoped_ptr
<apps::AppWindowFrameView
> frame(
193 app_window_views()->CreateNonStandardAppFrame());
195 // Ensure that the window has an event targeter (there should be an
196 // EasyResizeWindowTargeter installed).
197 EXPECT_TRUE(static_cast<ui::EventTarget
*>(window
)->GetEventTargeter());
200 // An event in the center of the window should always have
201 // |window| as its target.
202 // TODO(mgiuca): This isn't really testing anything (note that it has the
203 // same expectation as the border case below). In the real environment, the
204 // target will actually be the RenderWidgetHostViewAura's window that is the
205 // child of the child of |window|, whereas in the border case it *will* be
206 // |window|. However, since this test environment does not have a
207 // RenderWidgetHostViewAura, we cannot differentiate the two cases. Fix
208 // the test environment so that the test can assert that non-border events
209 // bubble down to a child of |window|.
210 ui::MouseEvent
move(ui::ET_MOUSE_MOVED
,
211 gfx::Point(80, 80), gfx::Point(80, 80),
212 ui::EF_NONE
, ui::EF_NONE
);
213 ui::EventDispatchDetails details
=
214 event_processor()->OnEventFromSource(&move
);
215 ASSERT_FALSE(details
.dispatcher_destroyed
);
216 EXPECT_EQ(window
, move
.target());
219 // With an EasyResizeTargeter on the container, an event
220 // inside the window and within 5px of an edge should have
221 // |window| as its target.
222 ui::MouseEvent
move(ui::ET_MOUSE_MOVED
,
223 gfx::Point(32, 37), gfx::Point(32, 37),
224 ui::EF_NONE
, ui::EF_NONE
);
225 ui::EventDispatchDetails details
=
226 event_processor()->OnEventFromSource(&move
);
227 ASSERT_FALSE(details
.dispatcher_destroyed
);
228 EXPECT_EQ(window
, move
.target());
230 #endif // defined (OS_CHROMEOS)