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
|
// Copyright 2014 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 <string>
#include "ash/magnifier/magnification_controller.h"
#include "ash/screen_util.h"
#include "ash/shell.h"
#include "base/command_line.h"
#include "base/macros.h"
#include "base/timer/timer.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/accessibility/magnification_manager.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/browser_test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace chromeos {
namespace {
const char kDataURIPrefix[] = "data:text/html;charset=utf-8,";
const char kTestHtmlContent1[] =
"<body style=\"margin-top:0;margin-left:0\">"
"<button type=\"button\" name=\"test_button_1\" id=\"test_button\" "
"style=\"margin-left:200;margin-top:200;width:100;height:50\">"
"Big Button 1</button>"
"</body>";
const char kTestHtmlContent2[] =
"<body style=\"margin-top:0;margin-left:0\">"
"<button type=\"button\" name=\"test_button_1\" id=\"test_button\" "
"style=\"margin-left:200;margin-top:200;width:100;height:50\">"
"Big Button 1</button>"
"</body>";
aura::Window* GetRootWindow() {
return ash::Shell::GetPrimaryRootWindow();
}
ash::MagnificationController* GetMagnificationController() {
return ash::Shell::GetInstance()->magnification_controller();
}
bool IsMagnifierEnabled() {
return MagnificationManager::Get()->IsMagnifierEnabled();
}
void SetMagnifierEnabled(bool enabled) {
MagnificationManager::Get()->SetMagnifierEnabled(true);
}
void MoveMagnifierWindow(int x, int y) {
GetMagnificationController()->MoveWindow(x, y, false);
}
gfx::Rect GetViewPort() {
return GetMagnificationController()->GetViewportRect();
}
class MagnifierAnimationWaiter {
public:
explicit MagnifierAnimationWaiter(ash::MagnificationController* controller)
: controller_(controller) {}
void Wait() {
base::RepeatingTimer check_timer;
check_timer.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(10), this,
&MagnifierAnimationWaiter::OnTimer);
runner_ = new content::MessageLoopRunner;
runner_->Run();
}
private:
void OnTimer() {
DCHECK(runner_.get());
if (!controller_->IsOnAnimationForTesting()) {
runner_->Quit();
}
}
ash::MagnificationController* controller_; // not owned
scoped_refptr<content::MessageLoopRunner> runner_;
DISALLOW_COPY_AND_ASSIGN(MagnifierAnimationWaiter);
};
} // namespace
class MagnificationControllerTest : public InProcessBrowserTest {
protected:
MagnificationControllerTest() {}
~MagnificationControllerTest() override {}
void SetUpCommandLine(base::CommandLine* command_line) override {
InProcessBrowserTest::SetUpCommandLine(command_line);
// Make screens sufficiently wide to host 2 browsers side by side.
command_line->AppendSwitchASCII("ash-host-window-bounds", "1200x800");
}
void SetUpOnMainThread() override {
SetMagnifierEnabled(true);
// Confirms that magnifier is enabled.
EXPECT_TRUE(IsMagnifierEnabled());
EXPECT_EQ(2.0f, GetMagnificationController()->GetScale());
// MagnificationController moves the magnifier window with animation
// when the magnifier is set to be enabled. It will move the mouse cursor
// when the animation completes. Wait until the animation completes, so that
// the mouse movement won't affect the position of magnifier window later.
MagnifierAnimationWaiter waiter(GetMagnificationController());
waiter.Wait();
base::RunLoop().RunUntilIdle();
}
content::WebContents* GetWebContents() {
return browser()->tab_strip_model()->GetActiveWebContents();
}
void ExecuteScriptAndExtractInt(const std::string& script, int* result) {
ASSERT_TRUE(content::ExecuteScriptAndExtractInt(
GetWebContents(),
"window.domAutomationController.send(" + script + ");", result));
}
void ExecuteScript(const std::string& script) {
ASSERT_TRUE(content::ExecuteScript(GetWebContents(), script));
}
gfx::Rect GetControlBoundsInRoot(const std::string& field_id) {
ExecuteScript("var element = document.getElementById('" + field_id +
"');"
"var bounds = element.getBoundingClientRect();");
int top, left, width, height;
ExecuteScriptAndExtractInt("bounds.top", &top);
ExecuteScriptAndExtractInt("bounds.left", &left);
ExecuteScriptAndExtractInt("bounds.width", &width);
ExecuteScriptAndExtractInt("bounds.height", &height);
gfx::Rect rect(top, left, width, height);
content::RenderWidgetHostView* view =
GetWebContents()->GetRenderWidgetHostView();
gfx::Rect view_bounds_in_screen = view->GetViewBounds();
gfx::Point origin = rect.origin();
origin.Offset(view_bounds_in_screen.x(), view_bounds_in_screen.y());
gfx::Rect rect_in_screen(origin.x(), origin.y(), rect.width(),
rect.height());
return ash::ScreenUtil::ConvertRectFromScreen(GetRootWindow(),
rect_in_screen);
}
void SetFocusOnElement(const std::string& element_id) {
ExecuteScript("document.getElementById('" + element_id + "').focus();");
}
private:
DISALLOW_COPY_AND_ASSIGN(MagnificationControllerTest);
};
IN_PROC_BROWSER_TEST_F(MagnificationControllerTest,
FollowFocusOnWebPageButtonNotIntersected) {
DCHECK(IsMagnifierEnabled());
ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(
browser(), GURL(std::string(kDataURIPrefix) + kTestHtmlContent1)));
// Move the magnifier window to not intersect with the button.
const gfx::Rect button_bounds = GetControlBoundsInRoot("test_button");
MoveMagnifierWindow(button_bounds.right() + 100,
button_bounds.bottom() + 100);
EXPECT_FALSE(GetViewPort().Intersects(button_bounds));
// Set the focus on the button.
SetFocusOnElement("test_button");
// Verify the magnifier window is moved to contain the focused button,
// and the button is centered at the magnifier window.
EXPECT_TRUE(GetViewPort().Contains(button_bounds));
EXPECT_EQ(GetViewPort().CenterPoint(), button_bounds.CenterPoint());
}
IN_PROC_BROWSER_TEST_F(MagnificationControllerTest,
FollowFocusOnWebPageButtonIntersected) {
DCHECK(IsMagnifierEnabled());
ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(
browser(), GURL(std::string(kDataURIPrefix) + kTestHtmlContent1)));
// Move the magnifier window to intersect with the button.
const gfx::Rect button_bounds = GetControlBoundsInRoot("test_button");
MoveMagnifierWindow(button_bounds.CenterPoint().x(),
button_bounds.CenterPoint().y());
EXPECT_TRUE(GetViewPort().Intersects(button_bounds));
// Set the focus on the button.
SetFocusOnElement("test_button");
// Verify the magnifier window is moved to contain the focused button,
// and the button is centered at the magnifier window.
EXPECT_TRUE(GetViewPort().Contains(button_bounds));
EXPECT_EQ(GetViewPort().CenterPoint(), button_bounds.CenterPoint());
}
IN_PROC_BROWSER_TEST_F(MagnificationControllerTest,
FollowFocusOnWebButtonContained) {
DCHECK(IsMagnifierEnabled());
ASSERT_NO_FATAL_FAILURE(ui_test_utils::NavigateToURL(
browser(), GURL(std::string(kDataURIPrefix) + kTestHtmlContent2)));
// Move magnifier window to contain the button.
const gfx::Rect button_bounds = GetControlBoundsInRoot("test_button");
MoveMagnifierWindow(button_bounds.x() - 100, button_bounds.y() - 100);
const gfx::Rect view_port_before_focus = GetViewPort();
EXPECT_TRUE(view_port_before_focus.Contains(button_bounds));
// Set the focus on the button.
SetFocusOnElement("test_button");
// Verify the magnifier window is not moved and still contains the button.
const gfx::Rect view_port_after_focus = GetViewPort();
EXPECT_TRUE(view_port_after_focus.Contains(button_bounds));
EXPECT_EQ(view_port_before_focus, view_port_after_focus);
}
} // namespace chromeos
|