| // 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/shell.h" |
| #include "base/command_line.h" |
| #include "base/macros.h" |
| #include "base/run_loop.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" |
| #include "ui/wm/core/coordinate_conversion.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::Get()->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 { |
| // 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()); |
| ::wm::ConvertRectFromScreen(GetRootWindow(), &rect_in_screen); |
| return 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 |