forked from chromium/chromium
-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathconstrained_window_views_unittest.cc
259 lines (217 loc) · 9.73 KB
/
constrained_window_views_unittest.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
// Copyright 2013 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 "components/constrained_window/constrained_window_views.h"
#include <memory>
#include "base/macros.h"
#include "build/build_config.h"
#include "components/constrained_window/constrained_window_views_client.h"
#include "components/web_modal/test_web_contents_modal_dialog_host.h"
#include "ui/display/display.h"
#include "ui/display/screen.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/views/test/test_views.h"
#include "ui/views/test/views_test_base.h"
#include "ui/views/widget/widget.h"
#include "ui/views/window/dialog_delegate.h"
using views::Widget;
namespace constrained_window {
namespace {
// Dummy client that returns a null modal dialog host and host view.
class TestConstrainedWindowViewsClient
: public constrained_window::ConstrainedWindowViewsClient {
public:
TestConstrainedWindowViewsClient() = default;
TestConstrainedWindowViewsClient(const TestConstrainedWindowViewsClient&) =
delete;
TestConstrainedWindowViewsClient& operator=(
const TestConstrainedWindowViewsClient&) = delete;
// ConstrainedWindowViewsClient:
web_modal::ModalDialogHost* GetModalDialogHost(
gfx::NativeWindow parent) override {
return nullptr;
}
gfx::NativeView GetDialogHostView(gfx::NativeWindow parent) override {
return nullptr;
}
};
// ViewsDelegate to provide context to dialog creation functions such as
// CreateBrowserModalDialogViews() which do not allow InitParams to be set, and
// pass a null |context| argument to DialogDelegate::CreateDialogWidget().
class TestViewsDelegateWithContext : public views::TestViewsDelegate {
public:
TestViewsDelegateWithContext() = default;
TestViewsDelegateWithContext(const TestViewsDelegateWithContext&) = delete;
TestViewsDelegateWithContext& operator=(const TestViewsDelegateWithContext&) =
delete;
void set_context(gfx::NativeWindow context) { context_ = context; }
// ViewsDelegate:
void OnBeforeWidgetInit(
views::Widget::InitParams* params,
views::internal::NativeWidgetDelegate* delegate) override {
if (!params->context)
params->context = context_;
TestViewsDelegate::OnBeforeWidgetInit(params, delegate);
}
private:
gfx::NativeWindow context_ = nullptr;
};
class ConstrainedWindowViewsTest : public views::ViewsTestBase {
public:
ConstrainedWindowViewsTest() = default;
ConstrainedWindowViewsTest(const ConstrainedWindowViewsTest&) = delete;
ConstrainedWindowViewsTest& operator=(const ConstrainedWindowViewsTest&) =
delete;
~ConstrainedWindowViewsTest() override = default;
void SetUp() override {
auto views_delegate = std::make_unique<TestViewsDelegateWithContext>();
// set_views_delegate() must be called before SetUp(), and GetContext() is
// null before that, so take a reference.
TestViewsDelegateWithContext* views_delegate_weak = views_delegate.get();
set_views_delegate(std::move(views_delegate));
views::ViewsTestBase::SetUp();
views_delegate_weak->set_context(GetContext());
delegate_ = std::make_unique<views::DialogDelegate>();
auto contents = std::make_unique<views::StaticSizedView>();
contents_ = delegate_->SetContentsView(std::move(contents));
dialog_ = views::DialogDelegate::CreateDialogWidget(delegate_.get(),
GetContext(), nullptr);
dialog_host_ = std::make_unique<web_modal::TestWebContentsModalDialogHost>(
dialog_->GetNativeView());
dialog_host_->set_max_dialog_size(gfx::Size(5000, 5000));
// Make sure the dialog size is dominated by the preferred size of the
// contents.
gfx::Size preferred_size = dialog()->GetRootView()->GetPreferredSize();
preferred_size.Enlarge(500, 500);
contents_->SetPreferredSize(preferred_size);
}
void TearDown() override {
contents_ = nullptr;
dialog_host_.reset();
dialog_->CloseNow();
ViewsTestBase::TearDown();
}
gfx::Size GetDialogSize() {
return dialog()->GetRootView()->GetBoundsInScreen().size();
}
views::DialogDelegate* delegate() { return delegate_.get(); }
views::View* contents() { return contents_; }
web_modal::TestWebContentsModalDialogHost* dialog_host() {
return dialog_host_.get();
}
Widget* dialog() { return dialog_; }
private:
std::unique_ptr<views::DialogDelegate> delegate_;
views::View* contents_ = nullptr;
std::unique_ptr<web_modal::TestWebContentsModalDialogHost> dialog_host_;
Widget* dialog_ = nullptr;
};
} // namespace
// Make sure a dialog that increases its preferred size grows on the next
// position update.
TEST_F(ConstrainedWindowViewsTest, GrowModalDialogSize) {
UpdateWidgetModalDialogPosition(dialog(), dialog_host());
gfx::Size expected_size = GetDialogSize();
gfx::Size preferred_size = contents()->GetPreferredSize();
expected_size.Enlarge(50, 50);
preferred_size.Enlarge(50, 50);
contents()->SetPreferredSize(preferred_size);
UpdateWidgetModalDialogPosition(dialog(), dialog_host());
EXPECT_EQ(expected_size.ToString(), GetDialogSize().ToString());
}
// Make sure a dialog that reduces its preferred size shrinks on the next
// position update.
TEST_F(ConstrainedWindowViewsTest, ShrinkModalDialogSize) {
UpdateWidgetModalDialogPosition(dialog(), dialog_host());
gfx::Size expected_size = GetDialogSize();
gfx::Size preferred_size = contents()->GetPreferredSize();
expected_size.Enlarge(-50, -50);
preferred_size.Enlarge(-50, -50);
contents()->SetPreferredSize(preferred_size);
UpdateWidgetModalDialogPosition(dialog(), dialog_host());
EXPECT_EQ(expected_size.ToString(), GetDialogSize().ToString());
}
// Make sure browser modal dialogs are not affected by restrictions on web
// content modal dialog maximum sizes.
TEST_F(ConstrainedWindowViewsTest, MaximumBrowserDialogSize) {
UpdateWidgetModalDialogPosition(dialog(), dialog_host());
gfx::Size dialog_size = GetDialogSize();
gfx::Size max_dialog_size = dialog_size;
max_dialog_size.Enlarge(-50, -50);
dialog_host()->set_max_dialog_size(max_dialog_size);
UpdateWidgetModalDialogPosition(dialog(), dialog_host());
EXPECT_EQ(dialog_size.ToString(), GetDialogSize().ToString());
}
// Web content modal dialogs should not get a size larger than what the dialog
// host gives as the maximum size.
TEST_F(ConstrainedWindowViewsTest, MaximumWebContentsDialogSize) {
UpdateWebContentsModalDialogPosition(dialog(), dialog_host());
gfx::Size full_dialog_size = GetDialogSize();
gfx::Size max_dialog_size = full_dialog_size;
max_dialog_size.Enlarge(-50, -50);
dialog_host()->set_max_dialog_size(max_dialog_size);
UpdateWebContentsModalDialogPosition(dialog(), dialog_host());
// The top border of the dialog is intentionally drawn outside the area
// specified by the dialog host, so add it to the size the dialog is expected
// to occupy.
gfx::Size expected_size = max_dialog_size;
expected_size.Enlarge(
0, dialog()->non_client_view()->frame_view()->GetInsets().top());
EXPECT_EQ(expected_size.ToString(), GetDialogSize().ToString());
// Increasing the maximum dialog size should bring the dialog back to its
// original size.
max_dialog_size.Enlarge(100, 100);
dialog_host()->set_max_dialog_size(max_dialog_size);
UpdateWebContentsModalDialogPosition(dialog(), dialog_host());
EXPECT_EQ(full_dialog_size.ToString(), GetDialogSize().ToString());
}
// Ensure CreateBrowserModalDialogViews() works correctly with a null parent.
// Flaky on Win10. https://crbug.com/1009182
#if defined(OS_WIN)
#define MAYBE_NullModalParent DISABLED_NullModalParent
#else
#define MAYBE_NullModalParent NullModalParent
#endif
TEST_F(ConstrainedWindowViewsTest, MAYBE_NullModalParent) {
// Use desktop widgets (except on ChromeOS) for extra coverage.
test_views_delegate()->set_use_desktop_native_widgets(true);
SetConstrainedWindowViewsClient(
std::make_unique<TestConstrainedWindowViewsClient>());
auto delegate = std::make_unique<views::DialogDelegate>();
delegate->SetModalType(ui::MODAL_TYPE_WINDOW);
views::Widget* widget =
CreateBrowserModalDialogViews(delegate.get(), nullptr);
widget->Show();
EXPECT_TRUE(widget->IsVisible());
widget->CloseNow();
}
// Make sure dialogs presented off-screen are properly clamped to the nearest
// screen.
TEST_F(ConstrainedWindowViewsTest, ClampDialogToNearestDisplay) {
// Make sure the dialog will fit fully on the display
contents()->SetPreferredSize(gfx::Size(200, 100));
// First, make sure the host and dialog are sized and positioned.
UpdateWebContentsModalDialogPosition(dialog(), dialog_host());
const display::Screen* screen = display::Screen::GetScreen();
const display::Display display = screen->GetPrimaryDisplay();
// Within the tests there is only 1 display. Error if that ever changes.
EXPECT_EQ(screen->GetNumDisplays(), 1);
const gfx::Rect extents = display.work_area();
// Move the host completely off the screen.
views::Widget* host_widget =
views::Widget::GetWidgetForNativeView(dialog_host()->GetHostView());
gfx::Rect host_bounds = host_widget->GetWindowBoundsInScreen();
host_bounds.set_origin(gfx::Point(extents.right(), extents.bottom()));
host_widget->SetBounds(host_bounds);
// Make sure the host is fully off the screen.
EXPECT_FALSE(extents.Intersects(host_widget->GetWindowBoundsInScreen()));
// Now reposition the modal dialog into the display.
UpdateWebContentsModalDialogPosition(dialog(), dialog_host());
const gfx::Rect dialog_bounds = dialog()->GetRootView()->GetBoundsInScreen();
// The dialog should now be fully on the display.
EXPECT_TRUE(extents.Contains(dialog_bounds));
}
} // namespace constrained_window