Commit c76adeae authored by Ryan Daum's avatar Ryan Daum Committed by Commit Bot

[chromecast] Port PartialMagnificationController to cast.

Start of support for screen magnification on chromecast. Consists of:

   * A port of PartialMagnificationController from Ash to Cast. Note
     that the first patchset is a direct copy, with modifications in
     subsequent patch sets, so a diff with patchset 1 will show the
     modifications made.

   * A base interface (MagnificationController) for implementations,
     as we will probably port fullscreen magnification as well.

   * Installation of the PartialMagnificationController on the root
     window via the window manager, but currently disabled.

Bug: internal b/110481596
Bug: internal b/110532452
Test: manual and unit test
Change-Id: Ia72f9b662304f5b5b3864c7fdfa7012677bfe883
Reviewed-on: https://chromium-review.googlesource.com/1111904
Commit-Queue: Ryan Daum <rdaum@chromium.org>
Reviewed-by: default avatarAlex Sakhartchouk <alexst@chromium.org>
Cr-Commit-Position: refs/heads/master@{#570046}
parent 2cbbb359
...@@ -37,6 +37,9 @@ cast_source_set("graphics") { ...@@ -37,6 +37,9 @@ cast_source_set("graphics") {
"accessibility/focus_ring_controller.h", "accessibility/focus_ring_controller.h",
"accessibility/focus_ring_layer.cc", "accessibility/focus_ring_layer.cc",
"accessibility/focus_ring_layer.h", "accessibility/focus_ring_layer.h",
"accessibility/magnification_controller.h",
"accessibility/partial_magnification_controller.cc",
"accessibility/partial_magnification_controller.h",
"cast_focus_client_aura.cc", "cast_focus_client_aura.cc",
"cast_focus_client_aura.h", "cast_focus_client_aura.h",
"cast_system_gesture_event_handler.cc", "cast_system_gesture_event_handler.cc",
...@@ -100,6 +103,7 @@ if (use_aura && !is_cast_audio_only) { ...@@ -100,6 +103,7 @@ if (use_aura && !is_cast_audio_only) {
test("cast_graphics_unittests") { test("cast_graphics_unittests") {
sources = [ sources = [
"accessibility/accessibility_focus_ring_controller_unittest.cc", "accessibility/accessibility_focus_ring_controller_unittest.cc",
"accessibility/partial_magnification_controller_unittest.cc",
"cast_focus_client_aura_test.cc", "cast_focus_client_aura_test.cc",
"cast_system_gesture_event_handler_test.cc", "cast_system_gesture_event_handler_test.cc",
"cast_views_test.cc", "cast_views_test.cc",
...@@ -114,6 +118,7 @@ if (use_aura && !is_cast_audio_only) { ...@@ -114,6 +118,7 @@ if (use_aura && !is_cast_audio_only) {
"//ui/aura", "//ui/aura",
"//ui/aura:test_support", "//ui/aura:test_support",
"//ui/base:test_support", "//ui/base:test_support",
"//ui/display/manager:manager",
"//ui/events:test_support", "//ui/events:test_support",
"//ui/gfx", "//ui/gfx",
"//ui/gl:test_support", "//ui/gl:test_support",
......
// Copyright (c) 2018 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.
#ifndef CHROMECAST_GRAPHICS_ACCESSIBILITY_MAGNIFICATION_CONTROLLER_H_
#define CHROMECAST_GRAPHICS_ACCESSIBILITY_MAGNIFICATION_CONTROLLER_H_
namespace chromecast {
// Interface for implementations of the screen magnification feature.
class MagnificationController {
public:
MagnificationController() = default;
virtual ~MagnificationController() = default;
// Turns magnifier feature on or off.
virtual void SetEnabled(bool enabled) = 0;
// Adjust the ratio of the scale of magnification.
virtual void SetMagnificationScale(float magnification_scale) = 0;
};
} // namespace chromecast
#endif //
// Copyright (c) 2018 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.
#ifndef CHROMECAST_GRAPHICS_ACCESSIBILITY_PARTIAL_MAGNIFICATION_CONTROLLER_H_
#define CHROMECAST_GRAPHICS_ACCESSIBILITY_PARTIAL_MAGNIFICATION_CONTROLLER_H_
#include <memory>
#include "base/macros.h"
#include "chromecast/graphics/accessibility/magnification_controller.h"
#include "ui/aura/window.h"
#include "ui/aura/window_observer.h"
#include "ui/events/event_handler.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/size.h"
#include "ui/views/widget/widget_observer.h"
namespace ui {
class Layer;
} // namespace ui
namespace chromecast {
// Controls the chromecast screen magnifier, which is a small area of the screen
// which is zoomed in. The zoomed area follows the mouse cursor when enabled.
class PartialMagnificationController : public MagnificationController,
public ui::EventHandler,
public aura::WindowObserver,
public views::WidgetObserver {
public:
explicit PartialMagnificationController(aura::Window* root_window);
~PartialMagnificationController() override;
// Turns the partial screen magnifier feature on or off.
// Note that the magnifier itself is displayed when it is both enabled
// and active. Magnification becomes active on a finger press.
void SetEnabled(bool enabled) override;
// Adjust the scale of magnification.
void SetMagnificationScale(float magnification_scale) override;
// Switch PartialMagnified RootWindow to |new_root_window|. This does
// following:
// - Remove the magnifier from the current root window.
// - Create a magnifier in the new root_window |new_root_window|.
// - Switch the target window from current window to |new_root_window|.
void SwitchTargetRootWindowIfNeeded(aura::Window* new_root_window);
private:
friend class PartialMagnificationControllerTestApi;
class BorderRenderer;
class ContentMask;
// ui::EventHandler:
void OnTouchEvent(ui::TouchEvent* event) override;
// WindowObserver:
void OnWindowDestroying(aura::Window* window) override;
// WidgetObserver:
void OnWidgetDestroying(views::Widget* widget) override;
// Enables or disables the actual magnifier window.
void SetActive(bool active);
// Create or close the magnifier window.
void CreateMagnifierWindow(aura::Window* root_window);
void CloseMagnifierWindow();
// Removes this as an observer of the zoom widget and the root window.
void RemoveZoomWidgetObservers();
float magnification_scale_;
bool is_enabled_ = false;
bool is_active_ = false;
aura::Window* root_window_;
// The host widget is the root parent for all of the layers. The widget's
// location follows the mouse, which causes the layers to also move.
views::Widget* host_widget_ = nullptr;
// Draws the background with a zoom filter applied.
std::unique_ptr<ui::Layer> zoom_layer_;
// Draws an outline that is overlayed on top of |zoom_layer_|.
std::unique_ptr<ui::Layer> border_layer_;
// Draws a multicolored black/white/black border on top of |border_layer_|.
// Also draws a shadow around the border. This must be ordered after
// |border_layer_| so that it gets destroyed after |border_layer_|, otherwise
// |border_layer_| will have a pointer to a deleted delegate.
std::unique_ptr<BorderRenderer> border_renderer_;
// Masks the content of |zoom_layer_| so that only a circle is magnified.
std::unique_ptr<ContentMask> zoom_mask_;
// Masks the content of |border_layer_| so that only a circle outline is
// drawn.
std::unique_ptr<ContentMask> border_mask_;
DISALLOW_COPY_AND_ASSIGN(PartialMagnificationController);
};
} // namespace chromecast
#endif // CHROMECAST_GRAPHICS_ACCESSIBILITY_PARTIAL_MAGNIFICATION_CONTROLLER_H_
// Copyright 2018 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 "chromecast/graphics/accessibility/partial_magnification_controller.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/aura/test/aura_test_base.h"
#include "ui/aura/test/event_generator_delegate_aura.h"
#include "ui/aura/test/test_window_delegate.h"
#include "ui/display/manager/display_manager.h"
#include "ui/events/test/event_generator.h"
#include "ui/views/widget/widget.h"
#include "ui/wm/core/default_screen_position_client.h"
namespace chromecast {
class CastTestWindowDelegate : public aura::test::TestWindowDelegate {
public:
CastTestWindowDelegate() : key_code_(ui::VKEY_UNKNOWN) {}
~CastTestWindowDelegate() override {}
// Overridden from TestWindowDelegate:
void OnKeyEvent(ui::KeyEvent* event) override {
key_code_ = event->key_code();
}
ui::KeyboardCode key_code() { return key_code_; }
private:
ui::KeyboardCode key_code_;
DISALLOW_COPY_AND_ASSIGN(CastTestWindowDelegate);
};
class TestEventGeneratorDelegate
: public aura::test::EventGeneratorDelegateAura {
public:
explicit TestEventGeneratorDelegate(aura::Window* root_window)
: root_window_(root_window) {}
~TestEventGeneratorDelegate() override = default;
// EventGeneratorDelegateAura overrides:
aura::WindowTreeHost* GetHostAt(const gfx::Point& point) const override {
return root_window_->GetHost();
}
aura::client::ScreenPositionClient* GetScreenPositionClient(
const aura::Window* window) const override {
return aura::client::GetScreenPositionClient(root_window_);
}
private:
aura::Window* root_window_;
DISALLOW_COPY_AND_ASSIGN(TestEventGeneratorDelegate);
};
// Wrapper for PartialMagnificationController that exposes internal state to
// test functions.
class PartialMagnificationControllerTestApi {
public:
explicit PartialMagnificationControllerTestApi(
PartialMagnificationController* controller)
: controller_(controller) {}
~PartialMagnificationControllerTestApi() = default;
bool is_enabled() const { return controller_->is_enabled_; }
bool is_active() const { return controller_->is_active_; }
views::Widget* host_widget() const { return controller_->host_widget_; }
gfx::Point GetWidgetOrigin() const {
CHECK(host_widget());
return host_widget()->GetWindowBoundsInScreen().origin();
}
private:
PartialMagnificationController* controller_;
DISALLOW_ASSIGN(PartialMagnificationControllerTestApi);
};
class PartialMagnificationControllerTest : public aura::test::AuraTestBase {
public:
PartialMagnificationControllerTest() = default;
~PartialMagnificationControllerTest() override = default;
void SetUp() override {
aura::test::AuraTestBase::SetUp();
screen_position_client_.reset(new wm::DefaultScreenPositionClient());
aura::client::SetScreenPositionClient(root_window(),
screen_position_client_.get());
controller_ =
std::make_unique<PartialMagnificationController>(root_window());
}
protected:
PartialMagnificationController* GetController() const {
return controller_.get();
}
PartialMagnificationControllerTestApi GetTestApi() const {
return PartialMagnificationControllerTestApi(controller_.get());
}
ui::test::EventGenerator& GetEventGenerator() {
if (!event_generator_) {
event_generator_.reset(new ui::test::EventGenerator(
new TestEventGeneratorDelegate(root_window())));
}
return *event_generator_.get();
}
private:
std::unique_ptr<ui::test::EventGenerator> event_generator_;
std::unique_ptr<aura::client::ScreenPositionClient> screen_position_client_;
CastTestWindowDelegate test_window_delegate_;
std::unique_ptr<PartialMagnificationController> controller_;
DISALLOW_COPY_AND_ASSIGN(PartialMagnificationControllerTest);
};
// The magnifier should not show up immediately after being enabled.
TEST_F(PartialMagnificationControllerTest, InactiveByDefault) {
GetController()->SetEnabled(true);
EXPECT_FALSE(GetTestApi().is_active());
EXPECT_EQ(GetTestApi().host_widget(), nullptr);
}
// The magnifier should show up only after a pointer is pressed while enabled.
TEST_F(PartialMagnificationControllerTest, ActiveOnPointerDown) {
// While disabled no magnifier shows up.
GetEventGenerator().PressTouch();
EXPECT_FALSE(GetTestApi().is_active());
EXPECT_FALSE(GetTestApi().host_widget());
GetEventGenerator().ReleaseTouch();
// While enabled the magnifier is only active while the pointer is down.
GetController()->SetEnabled(true);
GetEventGenerator().PressTouch();
EXPECT_TRUE(GetTestApi().is_active());
EXPECT_NE(GetTestApi().host_widget(), nullptr);
GetEventGenerator().ReleaseTouch();
EXPECT_FALSE(GetTestApi().is_active());
EXPECT_EQ(GetTestApi().host_widget(), nullptr);
}
// Turning the magnifier off while it is active destroys the window.
TEST_F(PartialMagnificationControllerTest, DisablingDisablesActive) {
GetController()->SetEnabled(true);
GetEventGenerator().PressTouch();
EXPECT_TRUE(GetTestApi().is_active());
GetController()->SetEnabled(false);
EXPECT_FALSE(GetTestApi().is_active());
EXPECT_EQ(GetTestApi().host_widget(), nullptr);
}
// The magnifier is always located at finger.
TEST_F(PartialMagnificationControllerTest, MagnifierFollowsFinger) {
GetController()->SetEnabled(true);
// The window does not have to be centered on the press; compute the initial
// window placement offset. Use a Vector2d for the + operator overload.
GetEventGenerator().PressTouch();
gfx::Vector2d offset(GetTestApi().GetWidgetOrigin().x(),
GetTestApi().GetWidgetOrigin().y());
// Move the pointer around, make sure the window follows it.
GetEventGenerator().MoveTouch(gfx::Point(32, 32));
EXPECT_EQ(GetEventGenerator().current_location() + offset,
GetTestApi().GetWidgetOrigin());
GetEventGenerator().MoveTouch(gfx::Point(0, 10));
EXPECT_EQ(GetEventGenerator().current_location() + offset,
GetTestApi().GetWidgetOrigin());
GetEventGenerator().MoveTouch(gfx::Point(10, 0));
EXPECT_EQ(GetEventGenerator().current_location() + offset,
GetTestApi().GetWidgetOrigin());
GetEventGenerator().ReleaseTouch();
// Make sure the window is initially placed correctly.
GetEventGenerator().set_current_location(gfx::Point(50, 20));
EXPECT_FALSE(GetTestApi().is_active());
GetEventGenerator().PressTouch();
EXPECT_EQ(GetEventGenerator().current_location() + offset,
GetTestApi().GetWidgetOrigin());
}
} // namespace chromecast
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment