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 "chrome/browser/ui/views/apps/native_app_window_views.h"
8 #include "ui/aura/root_window.h"
9 #include "ui/aura/test/aura_test_base.h"
10 #include "ui/aura/window.h"
11 #include "ui/views/controls/webview/webview.h"
12 #include "ui/wm/public/easy_resize_window_targeter.h"
14 class ShapedAppWindowTargeterTest
: public aura::test::AuraTestBase
{
16 ShapedAppWindowTargeterTest()
20 virtual ~ShapedAppWindowTargeterTest() {}
22 views::Widget
* widget() { return widget_
.get(); }
24 apps::NativeAppWindow
* app_window() { return &app_window_
; }
25 NativeAppWindowViews
* app_window_views() { return &app_window_
; }
28 virtual void SetUp() OVERRIDE
{
29 aura::test::AuraTestBase::SetUp();
30 widget_
.reset(new views::Widget
);
31 views::Widget::InitParams
params(views::Widget::InitParams::TYPE_WINDOW
);
32 params
.remove_standard_frame
= true;
33 params
.bounds
= gfx::Rect(30, 30, 100, 100);
34 params
.context
= root_window();
35 params
.ownership
= views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
36 widget_
->Init(params
);
38 app_window_
.web_view_
= &web_view_
;
39 app_window_
.window_
= widget_
.get();
44 virtual void TearDown() OVERRIDE
{
46 aura::test::AuraTestBase::TearDown();
50 views::WebView web_view_
;
51 scoped_ptr
<views::Widget
> widget_
;
52 NativeAppWindowViews app_window_
;
54 DISALLOW_COPY_AND_ASSIGN(ShapedAppWindowTargeterTest
);
57 TEST_F(ShapedAppWindowTargeterTest
, HitTestBasic
) {
58 aura::Window
* window
= widget()->GetNativeWindow();
60 // Without any custom shapes, the event should be targeted correctly to the
62 ui::MouseEvent
move(ui::ET_MOUSE_MOVED
,
63 gfx::Point(40, 40), gfx::Point(40, 40),
64 ui::EF_NONE
, ui::EF_NONE
);
65 ui::EventDispatchDetails details
= dispatcher()->OnEventFromSource(&move
);
66 ASSERT_FALSE(details
.dispatcher_destroyed
);
67 EXPECT_EQ(window
, move
.target());
70 scoped_ptr
<SkRegion
> region(new SkRegion
);
71 region
->op(SkIRect::MakeXYWH(40, 0, 20, 100), SkRegion::kUnion_Op
);
72 region
->op(SkIRect::MakeXYWH(0, 40, 100, 20), SkRegion::kUnion_Op
);
73 app_window()->UpdateShape(region
.Pass());
75 // With the custom shape, the events that don't fall within the custom shape
76 // will go through to the root window.
77 ui::MouseEvent
move(ui::ET_MOUSE_MOVED
,
78 gfx::Point(40, 40), gfx::Point(40, 40),
79 ui::EF_NONE
, ui::EF_NONE
);
80 ui::EventDispatchDetails details
= dispatcher()->OnEventFromSource(&move
);
81 ASSERT_FALSE(details
.dispatcher_destroyed
);
82 EXPECT_EQ(root_window(), move
.target());
84 // But events within the shape will still reach the window.
85 ui::MouseEvent
move2(ui::ET_MOUSE_MOVED
,
86 gfx::Point(80, 80), gfx::Point(80, 80),
87 ui::EF_NONE
, ui::EF_NONE
);
88 details
= dispatcher()->OnEventFromSource(&move2
);
89 ASSERT_FALSE(details
.dispatcher_destroyed
);
90 EXPECT_EQ(window
, move2
.target());
94 TEST_F(ShapedAppWindowTargeterTest
, HitTestOnlyForShapedWindow
) {
95 // Install a window-targeter on the root window that allows a window to
96 // receive events outside of its bounds. Verify that this window-targeter is
97 // active unless the window has a custom shape.
98 gfx::Insets
inset(-30, -30, -30, -30);
99 root_window()->SetEventTargeter(scoped_ptr
<ui::EventTargeter
>(
100 new wm::EasyResizeWindowTargeter(root_window(), inset
, inset
)));
102 aura::Window
* window
= widget()->GetNativeWindow();
104 // Without any custom shapes, an event within the window bounds should be
105 // targeted correctly to the window.
106 ui::MouseEvent
move(ui::ET_MOUSE_MOVED
,
107 gfx::Point(40, 40), gfx::Point(40, 40),
108 ui::EF_NONE
, ui::EF_NONE
);
109 ui::EventDispatchDetails details
= dispatcher()->OnEventFromSource(&move
);
110 ASSERT_FALSE(details
.dispatcher_destroyed
);
111 EXPECT_EQ(window
, move
.target());
114 // Without any custom shapes, an event that falls just outside the window
115 // bounds should also be targeted correctly to the window, because of the
116 // targeter installed on the root-window.
117 ui::MouseEvent
move(ui::ET_MOUSE_MOVED
,
118 gfx::Point(10, 10), gfx::Point(10, 10),
119 ui::EF_NONE
, ui::EF_NONE
);
120 ui::EventDispatchDetails details
= dispatcher()->OnEventFromSource(&move
);
121 ASSERT_FALSE(details
.dispatcher_destroyed
);
122 EXPECT_EQ(window
, move
.target());
125 scoped_ptr
<SkRegion
> region(new SkRegion
);
126 region
->op(SkIRect::MakeXYWH(40, 0, 20, 100), SkRegion::kUnion_Op
);
127 region
->op(SkIRect::MakeXYWH(0, 40, 100, 20), SkRegion::kUnion_Op
);
128 app_window()->UpdateShape(region
.Pass());
130 // With the custom shape, the events that don't fall within the custom shape
131 // will go through to the root window.
132 ui::MouseEvent
move(ui::ET_MOUSE_MOVED
,
133 gfx::Point(10, 10), gfx::Point(10, 10),
134 ui::EF_NONE
, ui::EF_NONE
);
135 ui::EventDispatchDetails details
= dispatcher()->OnEventFromSource(&move
);
136 ASSERT_FALSE(details
.dispatcher_destroyed
);
137 EXPECT_EQ(root_window(), move
.target());
140 // Remove the custom shape. This should restore the behaviour of targeting the
141 // app window for events just outside its bounds.
142 app_window()->UpdateShape(scoped_ptr
<SkRegion
>());
144 ui::MouseEvent
move(ui::ET_MOUSE_MOVED
,
145 gfx::Point(10, 10), gfx::Point(10, 10),
146 ui::EF_NONE
, ui::EF_NONE
);
147 ui::EventDispatchDetails details
= dispatcher()->OnEventFromSource(&move
);
148 ASSERT_FALSE(details
.dispatcher_destroyed
);
149 EXPECT_EQ(window
, move
.target());