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.
#include "chromecast/graphics/accessibility/partial_magnification_controller.h"
#include "third_party/skia/include/core/SkDrawLooper.h"
#include "ui/aura/window.h"
#include "ui/aura/window_event_dispatcher.h"
#include "ui/aura/window_tree_host.h"
#include "ui/compositor/layer.h"
#include "ui/compositor/paint_recorder.h"
#include "ui/events/event.h"
#include "ui/events/event_constants.h"
#include "ui/gfx/shadow_value.h"
#include "ui/gfx/skia_paint_util.h"
#include "ui/views/widget/widget.h"
#include "ui/wm/core/coordinate_conversion.h"
namespace chromecast {
namespace {
// Default ratio of magnifier scale.
const float kDefaultMagnificationScale = 2.f;
// Radius of the magnifying glass in DIP. This does not include the thickness
// of the magnifying glass shadow and border.
const int kMagnifierRadius = 188;
// Size of the border around the magnifying glass in DIP.
const int kBorderSize = 10;
// Thickness of the outline around magnifying glass border in DIP.
const int kBorderOutlineThickness = 1;
// Thickness of the shadow around the magnifying glass in DIP.
const int kShadowThickness = 24;
// Offset of the shadow around the magnifying glass in DIP. One of the shadows
// is lowered a bit, so we have to include |kShadowOffset| in our calculations
// to compensate.
const int kShadowOffset = 24;
// The color of the border and its outlines. The border has an outline on both
// sides, producing a black/white/black ring.
const SkColor kBorderColor = SkColorSetARGB(204, 255, 255, 255);
const SkColor kBorderOutlineColor = SkColorSetARGB(51, 0, 0, 0);
// The colors of the two shadow around the magnifiying glass.
const SkColor kTopShadowColor = SkColorSetARGB(26, 0, 0, 0);
const SkColor kBottomShadowColor = SkColorSetARGB(61, 0, 0, 0);
// Inset on the zoom filter.
const int kZoomInset = 0;
// Vertical offset between the center of the magnifier and the tip of the
// pointer.
const int kVerticalOffset = 0;
// Name of the magnifier window.
const char kPartialMagniferWindowName[] = "PartialMagnifierWindow";
gfx::Size GetWindowSize() {
// The diameter of the window is the diameter of the magnifier, border and
// shadow combined. We apply |kShadowOffset| on all sides even though the
// shadow is only thicker on the bottom so as to keep the circle centered in
// the view and keep calculations (border rendering and content masking)
// simpler.
int window_diameter =
(kMagnifierRadius + kBorderSize + kShadowThickness + kShadowOffset) * 2;
return gfx::Size(window_diameter, window_diameter);
}
gfx::Rect GetBounds(gfx::Point mouse) {
gfx::Size size = GetWindowSize();
gfx::Point origin(mouse.x() - (size.width() / 2),
mouse.y() - (size.height() / 2) - kVerticalOffset);
return gfx::Rect(origin, size);
}
} // namespace
// The content mask provides a clipping layer for the magnification window so we
// can show a circular magnifier.
class PartialMagnificationController::ContentMask : public ui::LayerDelegate {
public:
// If |is_border| is true, the circle will be a stroke. This is useful if we
// wish to clip a border.
ContentMask(bool is_border, gfx::Size mask_bounds)
: layer_(ui::LAYER_TEXTURED), is_border_(is_border) {
layer_.set_delegate(this);
layer_.SetFillsBoundsOpaquely(false);
layer_.SetBounds(gfx::Rect(mask_bounds));
}
~ContentMask() override { layer_.set_delegate(nullptr); }
ui::Layer* layer() { return &layer_; }
private:
// ui::LayerDelegate:
void OnPaintLayer(const ui::PaintContext& context) override {
ui::PaintRecorder recorder(context, layer()->size());
cc::PaintFlags flags;
flags.setAlpha(255);
flags.setAntiAlias(true);
// Stroke is used for clipping the border which consists of the rendered
// border |kBorderSize| and the magnifier shadow |kShadowThickness| and
// |kShadowOffset|.
flags.setStrokeWidth(kBorderSize + kShadowThickness + kShadowOffset);
flags.setStyle(is_border_ ? cc::PaintFlags::kStroke_Style
: cc::PaintFlags::kFill_Style);
// If we want to clip the magnifier zone use the magnifiers radius.
// Otherwise we want to clip the border, shadow and shadow offset so we
// start
// at the halfway point of the stroke width.
gfx::Rect rect(layer()->bounds().size());
int clipping_radius = kMagnifierRadius;
if (is_border_)
clipping_radius += (kShadowThickness + kShadowOffset + kBorderSize) / 2;
recorder.canvas()->DrawCircle(rect.CenterPoint(), clipping_radius, flags);
}
void OnDeviceScaleFactorChanged(float old_device_scale_factor,
float new_device_scale_factor) override {
// Redrawing will take care of scale factor change.
}
ui::Layer layer_;
bool is_border_;
DISALLOW_COPY_AND_ASSIGN(ContentMask);
};
// The border renderer draws the border as well as outline on both the outer and
// inner radius to increase visibility. The border renderer also handles drawing
// the shadow.
class PartialMagnificationController::BorderRenderer
: public ui::LayerDelegate {
public:
explicit BorderRenderer(const gfx::Rect& window_bounds)
: magnifier_window_bounds_(window_bounds) {
magnifier_shadows_.push_back(gfx::ShadowValue(
gfx::Vector2d(0, kShadowOffset), kShadowThickness, kBottomShadowColor));
magnifier_shadows_.push_back(gfx::ShadowValue(
gfx::Vector2d(0, 0), kShadowThickness, kTopShadowColor));
}
~BorderRenderer() override = default;
private:
// ui::LayerDelegate:
void OnPaintLayer(const ui::PaintContext& context) override {
ui::PaintRecorder recorder(context, magnifier_window_bounds_.size());
// Draw the shadow.
cc::PaintFlags shadow_flags;
shadow_flags.setAntiAlias(true);
shadow_flags.setColor(SK_ColorTRANSPARENT);
shadow_flags.setLooper(gfx::CreateShadowDrawLooper(magnifier_shadows_));
gfx::Rect shadow_bounds(magnifier_window_bounds_.size());
recorder.canvas()->DrawCircle(
shadow_bounds.CenterPoint(),
shadow_bounds.width() / 2 - kShadowThickness - kShadowOffset,
shadow_flags);
cc::PaintFlags border_flags;
border_flags.setAntiAlias(true);
border_flags.setStyle(cc::PaintFlags::kStroke_Style);
// The radius of the magnifier and its border.
const int magnifier_radius = kMagnifierRadius + kBorderSize;
// Draw the inner border.
border_flags.setStrokeWidth(kBorderSize);
border_flags.setColor(kBorderColor);
recorder.canvas()->DrawCircle(magnifier_window_bounds_.CenterPoint(),
magnifier_radius - kBorderSize / 2,
border_flags);
// Draw border outer outline and then draw the border inner outline.
border_flags.setStrokeWidth(kBorderOutlineThickness);
border_flags.setColor(kBorderOutlineColor);
recorder.canvas()->DrawCircle(
magnifier_window_bounds_.CenterPoint(),
magnifier_radius - kBorderOutlineThickness / 2, border_flags);
recorder.canvas()->DrawCircle(
magnifier_window_bounds_.CenterPoint(),
magnifier_radius - kBorderSize + kBorderOutlineThickness / 2,
border_flags);
}
void OnDeviceScaleFactorChanged(float old_device_scale_factor,
float new_device_scale_factor) override {}
gfx::Rect magnifier_window_bounds_;
std::vector<gfx::ShadowValue> magnifier_shadows_;
DISALLOW_COPY_AND_ASSIGN(BorderRenderer);
};
PartialMagnificationController::PartialMagnificationController(
aura::Window* root_window)
: magnification_scale_(kDefaultMagnificationScale),
root_window_(root_window) {
root_window_->AddPreTargetHandler(this);
}
PartialMagnificationController::~PartialMagnificationController() {
CloseMagnifierWindow();
root_window_->RemovePreTargetHandler(this);
}
void PartialMagnificationController::SetEnabled(bool enabled) {
is_enabled_ = enabled;
SetActive(false);
}
void PartialMagnificationController::SwitchTargetRootWindowIfNeeded(
aura::Window* new_root_window) {
if (host_widget_ &&
new_root_window == host_widget_->GetNativeView()->GetRootWindow())
return;
if (!new_root_window)
new_root_window = root_window_;
if (is_enabled_ && is_active_) {
CloseMagnifierWindow();
CreateMagnifierWindow(new_root_window);
}
}
void PartialMagnificationController::OnWindowDestroying(aura::Window* window) {
CloseMagnifierWindow();
aura::Window* new_root_window = root_window_;
if (new_root_window != window)
SwitchTargetRootWindowIfNeeded(new_root_window);
}
void PartialMagnificationController::OnWidgetDestroying(views::Widget* widget) {
DCHECK_EQ(widget, host_widget_);
RemoveZoomWidgetObservers();
host_widget_ = nullptr;
}
void PartialMagnificationController::SetActive(bool active) {
// Fail if we're trying to activate while disabled.
DCHECK(is_enabled_ || !active);
is_active_ = active;
if (is_active_) {
CreateMagnifierWindow(root_window_);
} else {
CloseMagnifierWindow();
}
}
void PartialMagnificationController::OnTouchEvent(ui::TouchEvent* event) {
if (!is_enabled_) {
return;
}
// Compute the event location in screen space.
aura::Window* target = static_cast<aura::Window*>(event->target());
aura::Window* event_root = target->GetRootWindow();
gfx::Point screen_point = event->root_location();
wm::ConvertPointToScreen(event_root, &screen_point);
// TODO(rdaum): Touch pressed is probably not what we want here, we'll
// probably want a specific gesture for dragging the magnifier around.
if (event->type() == ui::ET_TOUCH_PRESSED) {
SetActive(true);
}
if (event->type() == ui::ET_TOUCH_RELEASED)
SetActive(false);
if (!is_active_)
return;
// If the previous root window was detached host_widget_ will be null;
// reconstruct it. We also need to change the root window if the cursor has
// crossed display boundries.
SwitchTargetRootWindowIfNeeded(root_window_);
// If that failed for any reason return.
if (!host_widget_) {
SetActive(false);
return;
}
// Remap point from where it was captured to the display it is actually on.
gfx::Point point = event->root_location();
aura::Window::ConvertPointToTarget(
event_root, host_widget_->GetNativeView()->GetRootWindow(), &point);
host_widget_->SetBounds(GetBounds(point));
}
void PartialMagnificationController::CreateMagnifierWindow(
aura::Window* root_window) {
if (host_widget_ || !root_window)
return;
root_window->AddObserver(this);
gfx::Point mouse(
root_window->GetHost()->dispatcher()->GetLastMouseLocationInRoot());
host_widget_ = new views::Widget;
views::Widget::InitParams params(
views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
params.activatable = views::Widget::InitParams::ACTIVATABLE_NO;
params.accept_events = false;
params.bounds = GetBounds(mouse);
params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
params.parent = root_window;
host_widget_->Init(params);
host_widget_->set_focus_on_creation(false);
host_widget_->Show();
aura::Window* window = host_widget_->GetNativeView();
window->SetName(kPartialMagniferWindowName);
ui::Layer* root_layer = host_widget_->GetNativeView()->layer();
zoom_layer_.reset(new ui::Layer(ui::LayerType::LAYER_SOLID_COLOR));
zoom_layer_->SetBounds(gfx::Rect(GetWindowSize()));
zoom_layer_->SetBackgroundZoom(magnification_scale_, kZoomInset);
root_layer->Add(zoom_layer_.get());
border_layer_.reset(new ui::Layer(ui::LayerType::LAYER_TEXTURED));
border_layer_->SetBounds(gfx::Rect(GetWindowSize()));
border_renderer_.reset(new BorderRenderer(gfx::Rect(GetWindowSize())));
border_layer_->set_delegate(border_renderer_.get());
border_layer_->SetFillsBoundsOpaquely(false);
root_layer->Add(border_layer_.get());
border_mask_.reset(new ContentMask(true, GetWindowSize()));
border_layer_->SetMaskLayer(border_mask_->layer());
zoom_mask_.reset(new ContentMask(false, GetWindowSize()));
zoom_layer_->SetMaskLayer(zoom_mask_->layer());
host_widget_->AddObserver(this);
}
void PartialMagnificationController::CloseMagnifierWindow() {
if (host_widget_) {
RemoveZoomWidgetObservers();
host_widget_->Close();
host_widget_ = nullptr;
}
}
void PartialMagnificationController::RemoveZoomWidgetObservers() {
DCHECK(host_widget_);
host_widget_->RemoveObserver(this);
aura::Window* root_window = host_widget_->GetNativeView()->GetRootWindow();
DCHECK(root_window);
root_window->RemoveObserver(this);
}
void PartialMagnificationController::SetMagnificationScale(
float magnification_scale) {
magnification_scale_ = magnification_scale;
// TODO(rdaum): This is probably going to require a redraw/refresh if the
// magnifier is currently visible.
}
} // namespace chromecast
// 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