diff options
author | yoshiki@chromium.org <yoshiki@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-04-24 07:39:36 +0000 |
---|---|---|
committer | yoshiki@chromium.org <yoshiki@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-04-24 07:39:36 +0000 |
commit | 0ec58349766d2e02997baa3bf10e65aebb81c1fa (patch) | |
tree | 05adf36c4327adb06a8d3d133fe1d92164eaffd3 /ash | |
parent | c694dbe24b86dc875cac1a229c559365955581a3 (diff) | |
download | chromium_src-0ec58349766d2e02997baa3bf10e65aebb81c1fa.zip chromium_src-0ec58349766d2e02997baa3bf10e65aebb81c1fa.tar.gz chromium_src-0ec58349766d2e02997baa3bf10e65aebb81c1fa.tar.bz2 |
Let Magnifier, UI Scaling and Rotation use AshRootWindowTransformer to create transform matrix.
This patch enables us to use simultaneously these features.
BUG=223983, 230979
TEST=ash_unittests and aura_unittests passes.
R=oshima@chromium.org
NOTRY=True
# NOTRYing for trybots are already passed.
Review URL: https://chromiumcodereview.appspot.com/13634002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@196077 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ash')
-rw-r--r-- | ash/ash.gyp | 2 | ||||
-rw-r--r-- | ash/ash_root_window_transformer.cc | 151 | ||||
-rw-r--r-- | ash/ash_root_window_transformer.h | 17 | ||||
-rw-r--r-- | ash/ash_root_window_transformer_unittest.cc | 405 | ||||
-rw-r--r-- | ash/display/display_controller.cc | 65 | ||||
-rw-r--r-- | ash/magnifier/magnification_controller.cc | 41 | ||||
-rw-r--r-- | ash/magnifier/magnification_controller_unittest.cc | 2 |
7 files changed, 583 insertions, 100 deletions
diff --git a/ash/ash.gyp b/ash/ash.gyp index d38804c..156e0e0 100644 --- a/ash/ash.gyp +++ b/ash/ash.gyp @@ -616,6 +616,7 @@ 'accelerators/accelerator_filter_unittest.cc', 'accelerators/accelerator_table_unittest.cc', 'accelerators/nested_dispatcher_controller_unittest.cc', + 'ash_root_window_transformer_unittest.cc', 'desktop_background/desktop_background_controller_unittest.cc', 'dip_unittest.cc', 'display/display_controller_unittest.cc', @@ -707,6 +708,7 @@ ['exclude', 'accelerators/nested_dispatcher_controller_unittest.cc'], ['exclude', 'wm/drag_window_resizer_unittest.cc'], # Can't resize on Windows Ash. http://crbug.com/165962 + ['exclude', 'ash_root_window_transformer_unittest.cc'], ['exclude', 'magnifier/magnification_controller_unittest.cc'], ['exclude', 'wm/workspace/workspace_window_resizer_unittest.cc'], ], diff --git a/ash/ash_root_window_transformer.cc b/ash/ash_root_window_transformer.cc index e0aa26c..fa8a8a3 100644 --- a/ash/ash_root_window_transformer.cc +++ b/ash/ash_root_window_transformer.cc @@ -4,38 +4,143 @@ #include "ash/ash_root_window_transformer.h" +#include <cmath> + +#include "ash/display/display_info.h" +#include "ash/display/display_manager.h" +#include "ash/magnifier/magnification_controller.h" +#include "ash/shell.h" +#include "third_party/skia/include/utils/SkMatrix44.h" #include "ui/aura/root_window.h" +#include "ui/aura/window_property.h" #include "ui/compositor/dip_util.h" +#include "ui/gfx/display.h" #include "ui/gfx/size_conversions.h" +#include "ui/gfx/transform.h" + +DECLARE_WINDOW_PROPERTY_TYPE(gfx::Display::Rotation); namespace ash { +namespace { + +DEFINE_WINDOW_PROPERTY_KEY(gfx::Display::Rotation, kRotationPropertyKey, + gfx::Display::ROTATE_0); + +// Round near zero value to zero. +void RoundNearZero(gfx::Transform* transform) { + const float kEpsilon = 0.001f; + SkMatrix44& matrix = transform->matrix(); + for (int x = 0; x < 4; ++x) { + for (int y = 0; y < 4; ++y) { + if (std::abs(SkMScalarToFloat(matrix.get(x, y))) < kEpsilon) + matrix.set(x, y, SkFloatToMScalar(0.0f)); + } + } +} + +gfx::Transform CreateRotationTransform(aura::RootWindow* root_window, + const gfx::Display& display) { + internal::DisplayInfo info = + Shell::GetInstance()->display_manager()->GetDisplayInfo(display.id()); + + // TODO(oshima): Add animation. (crossfade+rotation, or just cross-fade) +#if defined(OS_WIN) + // Windows 8 bots refused to resize the host window, and + // updating the transform results in incorrectly resizing + // the root window. Don't apply the transform unless + // necessary so that unit tests pass on win8 bots. + if (info.rotation() == root_window->GetProperty(kRotationPropertyKey)) + return gfx::Transform(); + root_window->SetProperty(kRotationPropertyKey, info.rotation()); +#endif + + gfx::Transform rotate; + // The origin is (0, 0), so the translate width/height must be reduced by + // 1 pixel. + float one_pixel = 1.0f / display.device_scale_factor(); + switch (info.rotation()) { + case gfx::Display::ROTATE_0: + break; + case gfx::Display::ROTATE_90: + rotate.Translate(display.bounds().height() - one_pixel, 0); + rotate.Rotate(90); + break; + case gfx::Display::ROTATE_270: + rotate.Translate(0, display.bounds().width() - one_pixel); + rotate.Rotate(270); + break; + case gfx::Display::ROTATE_180: + rotate.Translate(display.bounds().width() - one_pixel, + display.bounds().height() - one_pixel); + rotate.Rotate(180); + break; + } + + RoundNearZero(&rotate); + return rotate; +} -AshRootWindowTransformer::AshRootWindowTransformer( - aura::RootWindow* root, - const gfx::Transform& transform, - const gfx::Insets& host_insets, - float root_window_scale) - : root_window_(root), - transform_(transform), - root_window_scale_(root_window_scale), - host_insets_(host_insets) { - root_window_->layer()->SetForceRenderSurface(root_window_scale_ != 1.0f); - - gfx::Transform translate; - - if (host_insets.top() != 0 || host_insets.left() != 0) { - float device_scale_factor = ui::GetDeviceScaleFactor(root_window_->layer()); - float x_offset = host_insets.left() / device_scale_factor; - float y_offset = host_insets.top() / device_scale_factor; - translate.Translate(x_offset, y_offset); +gfx::Transform CreateMagnifierTransform(aura::RootWindow* root_window) { + MagnificationController* magnifier = + Shell::GetInstance()->magnification_controller(); + float magnifier_scale = 1.f; + gfx::Point magnifier_offset; + if (magnifier && magnifier->IsEnabled()) { + magnifier_scale = magnifier->GetScale(); + magnifier_offset = magnifier->GetWindowPosition(); + } + gfx::Transform transform; + if (magnifier_scale != 1.f) { + transform.Scale(magnifier_scale, magnifier_scale); + transform.Translate(-magnifier_offset.x(), -magnifier_offset.y()); } - float inverted_scale = 1.0f / root_window_scale_; - translate.Scale(inverted_scale, inverted_scale); - transform_ = translate * transform; + return transform; +} +gfx::Transform CreateOverscanAndUIScaleTransform(aura::RootWindow* root_window, + const gfx::Display& display) { + internal::DisplayInfo info = + Shell::GetInstance()->display_manager()->GetDisplayInfo(display.id()); + gfx::Insets insets = info.GetOverscanInsetsInPixel(); + float scale = info.ui_scale(); + + gfx::Transform transform; + if (insets.top() != 0 || insets.left() != 0) { + float device_scale_factor = ui::GetDeviceScaleFactor(root_window->layer()); + float x_offset = insets.left() / device_scale_factor; + float y_offset = insets.top() / device_scale_factor; + transform.Translate(x_offset, y_offset); + } + float inverted_scale = 1.0f / scale; + transform.Scale(inverted_scale, inverted_scale); + return transform; +} + +} // namespace + +AshRootWindowTransformer::AshRootWindowTransformer(aura::RootWindow* root, + const gfx::Display& display) + : root_window_(root) { + root_window_bounds_transform_ = + CreateOverscanAndUIScaleTransform(root, display) * + CreateRotationTransform(root, display); + transform_ = root_window_bounds_transform_ * CreateMagnifierTransform(root); CHECK(transform_.GetInverse(&invert_transform_)); + + internal::DisplayInfo info = Shell::GetInstance()-> + display_manager()->GetDisplayInfo(display.id()); + root_window_ui_scale_ = info.ui_scale(); + host_insets_ = info.GetOverscanInsetsInPixel(); + MagnificationController* magnifier = + Shell::GetInstance()->magnification_controller(); + + bool scaled = (root_window_ui_scale_ != 1.f) || + (magnifier && magnifier->GetScale() != 1.f); + root_window_->layer()->SetForceRenderSurface(scaled); } +AshRootWindowTransformer::~AshRootWindowTransformer() {} + gfx::Transform AshRootWindowTransformer::GetTransform() const { return transform_; } @@ -50,12 +155,12 @@ gfx::Rect AshRootWindowTransformer::GetRootWindowBounds( bounds.Inset(host_insets_); bounds = ui::ConvertRectToDIP(root_window_->layer(), bounds); gfx::RectF new_bounds(bounds); - root_window_->layer()->transform().TransformRect(&new_bounds); + root_window_bounds_transform_.TransformRect(&new_bounds); // Apply |root_window_scale_| twice as the downscaling // is already applied once in |SetTransformInternal()|. // TODO(oshima): This is a bit ugly. Consider specifying // the pseudo host resolution instead. - new_bounds.Scale(root_window_scale_ * root_window_scale_); + new_bounds.Scale(root_window_ui_scale_ * root_window_ui_scale_); // Ignore the origin because RootWindow's insets are handled by // the transform. // Floor the size because the bounds is no longer aligned to diff --git a/ash/ash_root_window_transformer.h b/ash/ash_root_window_transformer.h index d8b7900..424a6cf 100644 --- a/ash/ash_root_window_transformer.h +++ b/ash/ash_root_window_transformer.h @@ -7,6 +7,7 @@ #include "ash/ash_export.h" #include "base/basictypes.h" +#include "base/memory/scoped_ptr.h" #include "ui/aura/root_window_transformer.h" #include "ui/gfx/insets.h" #include "ui/gfx/transform.h" @@ -15,15 +16,17 @@ namespace aura { class RootWindow; } +namespace gfx { +class Display; +} + namespace ash { // RootWindowTransformer for ash environment. class ASH_EXPORT AshRootWindowTransformer : public aura::RootWindowTransformer { public: AshRootWindowTransformer(aura::RootWindow* root, - const gfx::Transform& transform, - const gfx::Insets& insets, - float root_window_scale); + const gfx::Display& display); // aura::RootWindowTransformer overrides: virtual gfx::Transform GetTransform() const OVERRIDE; virtual gfx::Transform GetInverseTransform() const OVERRIDE; @@ -32,7 +35,7 @@ class ASH_EXPORT AshRootWindowTransformer : public aura::RootWindowTransformer { virtual gfx::Insets GetHostInsets() const OVERRIDE; private: - virtual ~AshRootWindowTransformer() {} + virtual ~AshRootWindowTransformer(); aura::RootWindow* root_window_; gfx::Transform transform_; @@ -42,11 +45,15 @@ class ASH_EXPORT AshRootWindowTransformer : public aura::RootWindowTransformer { // |gfx::Transform::GetInverse|. gfx::Transform invert_transform_; + // The transform of the root window bounds. This is used to calculate + // the size of root window. + gfx::Transform root_window_bounds_transform_; + // The scale of the root window. This is used to expand the // area of the root window (useful in HighDPI display). // Note that this should not be confused with the device scale // factor, which specfies the pixel density of the display. - float root_window_scale_; + float root_window_ui_scale_; gfx::Insets host_insets_; diff --git a/ash/ash_root_window_transformer_unittest.cc b/ash/ash_root_window_transformer_unittest.cc new file mode 100644 index 0000000..c4a1d1e --- /dev/null +++ b/ash/ash_root_window_transformer_unittest.cc @@ -0,0 +1,405 @@ +// Copyright (c) 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"ash/ash_root_window_transformer.h" + +#include "ash/display/display_controller.h" +#include "ash/display/display_info.h" +#include "ash/display/display_manager.h" +#include "ash/launcher/launcher.h" +#include "ash/magnifier/magnification_controller.h" +#include "ash/screen_ash.h" +#include "ash/shelf/shelf_widget.h" +#include "ash/shell.h" +#include "ash/test/ash_test_base.h" +#include "ash/test/cursor_manager_test_api.h" +#include "base/synchronization/waitable_event.h" +#include "ui/aura/env.h" +#include "ui/aura/root_window.h" +#include "ui/aura/test/event_generator.h" +#include "ui/aura/window_tracker.h" +#include "ui/base/events/event_handler.h" +#include "ui/gfx/display.h" +#include "ui/gfx/rect_conversions.h" +#include "ui/gfx/screen.h" +#include "ui/views/widget/widget.h" + +namespace ash { +namespace test { + +namespace { + +const char kDesktopBackgroundView[] = "DesktopBackgroundView"; + +class TestEventHandler : public ui::EventHandler { + public: + TestEventHandler() : target_root_(NULL), + touch_radius_x_(0.0), + touch_radius_y_(0.0), + scroll_x_offset_(0.0), + scroll_y_offset_(0.0), + scroll_x_offset_ordinal_(0.0), + scroll_y_offset_ordinal_(0.0) {} + virtual ~TestEventHandler() {} + + virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE { + if (event->flags() & ui::EF_IS_SYNTHESIZED) + return; + aura::Window* target = static_cast<aura::Window*>(event->target()); + mouse_location_ = event->root_location(); + target_root_ = target->GetRootWindow(); + event->StopPropagation(); + } + + virtual void OnTouchEvent(ui::TouchEvent* event) OVERRIDE { + aura::Window* target = static_cast<aura::Window*>(event->target()); + // Only record when the target is the background which covers + // entire root window. + if (target->name() != kDesktopBackgroundView) + return; + touch_radius_x_ = event->radius_x(); + touch_radius_y_ = event->radius_y(); + event->StopPropagation(); + } + + virtual void OnScrollEvent(ui::ScrollEvent* event) OVERRIDE { + aura::Window* target = static_cast<aura::Window*>(event->target()); + // Only record when the target is the background which covers + // entire root window. + if (target->name() != kDesktopBackgroundView) + return; + + if (event->type() == ui::ET_SCROLL) { + scroll_x_offset_ = event->x_offset(); + scroll_y_offset_ = event->y_offset(); + scroll_x_offset_ordinal_ = event->x_offset_ordinal(); + scroll_y_offset_ordinal_ = event->y_offset_ordinal(); + } + event->StopPropagation(); + } + + std::string GetLocationAndReset() { + std::string result = mouse_location_.ToString(); + mouse_location_.SetPoint(0, 0); + target_root_ = NULL; + return result; + } + + float touch_radius_x() const { return touch_radius_x_; } + float touch_radius_y() const { return touch_radius_y_; } + float scroll_x_offset() const { return scroll_x_offset_; } + float scroll_y_offset() const { return scroll_y_offset_; } + float scroll_x_offset_ordinal() const { return scroll_x_offset_ordinal_; } + float scroll_y_offset_ordinal() const { return scroll_y_offset_ordinal_; } + + private: + gfx::Point mouse_location_; + aura::RootWindow* target_root_; + + float touch_radius_x_; + float touch_radius_y_; + float scroll_x_offset_; + float scroll_y_offset_; + float scroll_x_offset_ordinal_; + float scroll_y_offset_ordinal_; + + DISALLOW_COPY_AND_ASSIGN(TestEventHandler); +}; + +gfx::Display::Rotation GetStoredRotation(int64 id) { + return Shell::GetInstance()->display_manager()->GetDisplayInfo(id).rotation(); +} + +float GetStoredUIScale(int64 id) { + return Shell::GetInstance()->display_manager()->GetDisplayInfo(id).ui_scale(); +} + +void MoveMouseToInHostCoord(aura::RootWindow* root_window, + int host_x, + int host_y) { + gfx::Point move_point(host_x, host_y); + ui::MouseEvent mouseev(ui::ET_MOUSE_MOVED, move_point, move_point, 0); + root_window->AsRootWindowHostDelegate()->OnHostMouseEvent(&mouseev); +} + +} // namespace + +typedef test::AshTestBase AshRootWindowTransformerTest; + +#if defined(OS_WIN) +// On Win8 bots, the host window can't be resized and +// SetTransform updates the window using the orignal host window +// size. +#define MAYBE_RotateAndMagnify DISABLED_RotateAndMagniy +#define MAYBE_ScaleAndMagnify DISABLED_ScaleAndMagnify +#define MAYBE_TouchScaleAndMagnify DISABLED_TouchScaleAndMagnify +#define MAYBE_ConvertHostToRootCoords DISABLED_ConvertHostToRootCoords +#else +#define MAYBE_RotateAndMagnify RotateAndMagniy +#define MAYBE_ScaleAndMagnify ScaleAndMagnify +#define MAYBE_TouchScaleAndMagnify TouchScaleAndMagnify +#define MAYBE_ConvertHostToRootCoords ConvertHostToRootCoords +#endif + +TEST_F(AshRootWindowTransformerTest, MAYBE_RotateAndMagnify) { + DisplayController* display_controller = + Shell::GetInstance()->display_controller(); + MagnificationController* magnifier = + Shell::GetInstance()->magnification_controller(); + internal::DisplayManager* display_manager = + Shell::GetInstance()->display_manager(); + + TestEventHandler event_handler; + Shell::GetInstance()->AddPreTargetHandler(&event_handler); + + UpdateDisplay("120x200,300x400*2"); + gfx::Display display1 = Shell::GetScreen()->GetPrimaryDisplay(); + int64 display2_id = ScreenAsh::GetSecondaryDisplay().id(); + + Shell::RootWindowList root_windows = Shell::GetAllRootWindows(); + aura::test::EventGenerator generator1(root_windows[0]); + aura::test::EventGenerator generator2(root_windows[1]); + + magnifier->SetEnabled(true); + EXPECT_EQ(2.0f, magnifier->GetScale()); + EXPECT_EQ("120x200", root_windows[0]->bounds().size().ToString()); + EXPECT_EQ("150x200", root_windows[1]->bounds().size().ToString()); + EXPECT_EQ("120,0 150x200", + ScreenAsh::GetSecondaryDisplay().bounds().ToString()); + generator1.MoveMouseTo(40, 80); + EXPECT_EQ("50,90", event_handler.GetLocationAndReset()); + EXPECT_EQ("50,90", + aura::Env::GetInstance()->last_mouse_location().ToString()); + EXPECT_EQ(gfx::Display::ROTATE_0, GetStoredRotation(display1.id())); + EXPECT_EQ(gfx::Display::ROTATE_0, GetStoredRotation(display2_id)); + magnifier->SetEnabled(false); + + display_manager->SetDisplayRotation(display1.id(), + gfx::Display::ROTATE_90); + // Move the cursor to the center of the first root window. + generator1.MoveMouseTo(59, 100); + + magnifier->SetEnabled(true); + EXPECT_EQ(2.0f, magnifier->GetScale()); + EXPECT_EQ("200x120", root_windows[0]->bounds().size().ToString()); + EXPECT_EQ("150x200", root_windows[1]->bounds().size().ToString()); + EXPECT_EQ("200,0 150x200", + ScreenAsh::GetSecondaryDisplay().bounds().ToString()); + generator1.MoveMouseTo(39, 120); + EXPECT_EQ("110,70", event_handler.GetLocationAndReset()); + EXPECT_EQ("110,70", + aura::Env::GetInstance()->last_mouse_location().ToString()); + EXPECT_EQ(gfx::Display::ROTATE_90, GetStoredRotation(display1.id())); + EXPECT_EQ(gfx::Display::ROTATE_0, GetStoredRotation(display2_id)); + magnifier->SetEnabled(false); + + DisplayLayout display_layout(DisplayLayout::BOTTOM, 50); + display_controller->SetLayoutForCurrentDisplays(display_layout); + EXPECT_EQ("50,120 150x200", + ScreenAsh::GetSecondaryDisplay().bounds().ToString()); + + display_manager->SetDisplayRotation(display2_id, + gfx::Display::ROTATE_270); + // Move the cursor to the center of the second root window. + generator2.MoveMouseTo(151, 199); + + magnifier->SetEnabled(true); + EXPECT_EQ("200x120", root_windows[0]->bounds().size().ToString()); + EXPECT_EQ("200x150", root_windows[1]->bounds().size().ToString()); + EXPECT_EQ("50,120 200x150", + ScreenAsh::GetSecondaryDisplay().bounds().ToString()); + generator2.MoveMouseTo(172, 219); + EXPECT_EQ("95,80", event_handler.GetLocationAndReset()); + EXPECT_EQ("169,175", + aura::Env::GetInstance()->last_mouse_location().ToString()); + EXPECT_EQ(gfx::Display::ROTATE_90, GetStoredRotation(display1.id())); + EXPECT_EQ(gfx::Display::ROTATE_270, GetStoredRotation(display2_id)); + magnifier->SetEnabled(false); + + display_manager->SetDisplayRotation(display1.id(), + gfx::Display::ROTATE_180); + // Move the cursor to the center of the first root window. + generator1.MoveMouseTo(59, 99); + + magnifier->SetEnabled(true); + EXPECT_EQ("120x200", root_windows[0]->bounds().size().ToString()); + EXPECT_EQ("200x150", root_windows[1]->bounds().size().ToString()); + // Dislay must share at least 100, so the x's offset becomes 20. + EXPECT_EQ("20,200 200x150", + ScreenAsh::GetSecondaryDisplay().bounds().ToString()); + generator1.MoveMouseTo(39, 59); + EXPECT_EQ("70,120", event_handler.GetLocationAndReset()); + EXPECT_EQ(gfx::Display::ROTATE_180, GetStoredRotation(display1.id())); + EXPECT_EQ(gfx::Display::ROTATE_270, GetStoredRotation(display2_id)); + magnifier->SetEnabled(false); + + Shell::GetInstance()->RemovePreTargetHandler(&event_handler); +} + +TEST_F(AshRootWindowTransformerTest, MAYBE_ScaleAndMagnify) { + TestEventHandler event_handler; + Shell::GetInstance()->AddPreTargetHandler(&event_handler); + + UpdateDisplay("600x400*2@1.5,500x300"); + + gfx::Display display1 = Shell::GetScreen()->GetPrimaryDisplay(); + gfx::Display::SetInternalDisplayId(display1.id()); + gfx::Display display2 = ScreenAsh::GetSecondaryDisplay(); + Shell::RootWindowList root_windows = Shell::GetAllRootWindows(); + MagnificationController* magnifier = + Shell::GetInstance()->magnification_controller(); + + magnifier->SetEnabled(true); + EXPECT_EQ(2.0f, magnifier->GetScale()); + EXPECT_EQ("0,0 450x300", display1.bounds().ToString()); + EXPECT_EQ("0,0 450x300", root_windows[0]->bounds().ToString()); + EXPECT_EQ("450,0 500x300", display2.bounds().ToString()); + EXPECT_EQ(1.5f, GetStoredUIScale(display1.id())); + EXPECT_EQ(1.0f, GetStoredUIScale(display2.id())); + + aura::test::EventGenerator generator(root_windows[0]); + generator.MoveMouseTo(500, 200); + EXPECT_EQ("299,150", event_handler.GetLocationAndReset()); + magnifier->SetEnabled(false); + + internal::DisplayManager* display_manager = + Shell::GetInstance()->display_manager(); + display_manager->SetDisplayUIScale(display1.id(), 1.25); + display1 = Shell::GetScreen()->GetPrimaryDisplay(); + display2 = ScreenAsh::GetSecondaryDisplay(); + magnifier->SetEnabled(true); + EXPECT_EQ(2.0f, magnifier->GetScale()); + EXPECT_EQ("0,0 375x250", display1.bounds().ToString()); + EXPECT_EQ("0,0 375x250", root_windows[0]->bounds().ToString()); + EXPECT_EQ("375,0 500x300", display2.bounds().ToString()); + EXPECT_EQ(1.25f, GetStoredUIScale(display1.id())); + EXPECT_EQ(1.0f, GetStoredUIScale(display2.id())); + magnifier->SetEnabled(false); + + Shell::GetInstance()->RemovePreTargetHandler(&event_handler); +} + +TEST_F(AshRootWindowTransformerTest, MAYBE_TouchScaleAndMagnify) { + TestEventHandler event_handler; + Shell::GetInstance()->AddPreTargetHandler(&event_handler); + + UpdateDisplay("200x200*2"); + gfx::Display display = Shell::GetScreen()->GetPrimaryDisplay(); + Shell::RootWindowList root_windows = Shell::GetAllRootWindows(); + aura::RootWindow* root_window = root_windows[0]; + aura::test::EventGenerator generator(root_window); + MagnificationController* magnifier = + Shell::GetInstance()->magnification_controller(); + + magnifier->SetEnabled(true); + EXPECT_FLOAT_EQ(2.0f, magnifier->GetScale()); + magnifier->SetScale(2.5f, false); + EXPECT_FLOAT_EQ(2.5f, magnifier->GetScale()); + generator.PressMoveAndReleaseTouchTo(50, 50); + // Default test touches have radius_x/y = 1.0, with device scale + // factor = 2, the scaled radius_x/y should be 0.5. + EXPECT_FLOAT_EQ(0.2, event_handler.touch_radius_x()); + EXPECT_FLOAT_EQ(0.2, event_handler.touch_radius_y()); + + generator.ScrollSequence(gfx::Point(0,0), + base::TimeDelta::FromMilliseconds(100), + 10.0, 1.0, 5, 1); + + // With device scale factor = 2, ordinal_offset * 2 = offset. + EXPECT_FLOAT_EQ(event_handler.scroll_x_offset(), + event_handler.scroll_x_offset_ordinal() * 2 * 2.5f); + EXPECT_FLOAT_EQ(event_handler.scroll_y_offset(), + event_handler.scroll_y_offset_ordinal() * 2 * 2.5f); + magnifier->SetEnabled(false); + + Shell::GetInstance()->RemovePreTargetHandler(&event_handler); +} + +TEST_F(AshRootWindowTransformerTest, MAYBE_ConvertHostToRootCoords) { + TestEventHandler event_handler; + Shell::GetInstance()->AddPreTargetHandler(&event_handler); + MagnificationController* magnifier = + Shell::GetInstance()->magnification_controller(); + + // Test 1 + UpdateDisplay("600x400*2/r@1.5"); + + gfx::Display display1 = Shell::GetScreen()->GetPrimaryDisplay(); + Shell::RootWindowList root_windows = Shell::GetAllRootWindows(); + EXPECT_EQ("0,0 300x450", display1.bounds().ToString()); + EXPECT_EQ("0,0 300x450", root_windows[0]->bounds().ToString()); + EXPECT_EQ(1.5f, GetStoredUIScale(display1.id())); + + MoveMouseToInHostCoord(root_windows[0], 300, 200); + magnifier->SetEnabled(true); + EXPECT_EQ("150,224", event_handler.GetLocationAndReset()); + EXPECT_FLOAT_EQ(2.0f, magnifier->GetScale()); + + MoveMouseToInHostCoord(root_windows[0], 300, 200); + EXPECT_EQ("150,224", event_handler.GetLocationAndReset()); + MoveMouseToInHostCoord(root_windows[0], 200, 300); + EXPECT_EQ("187,261", event_handler.GetLocationAndReset()); + MoveMouseToInHostCoord(root_windows[0], 100, 400); + EXPECT_EQ("237,299", event_handler.GetLocationAndReset()); + MoveMouseToInHostCoord(root_windows[0], 0, 0); + EXPECT_EQ("137,348", event_handler.GetLocationAndReset()); + + magnifier->SetEnabled(false); + EXPECT_FLOAT_EQ(1.0f, magnifier->GetScale()); + + // Test 2 + UpdateDisplay("600x400*2/u@1.5"); + display1 = Shell::GetScreen()->GetPrimaryDisplay(); + root_windows = Shell::GetAllRootWindows(); + EXPECT_EQ("0,0 450x300", display1.bounds().ToString()); + EXPECT_EQ("0,0 450x300", root_windows[0]->bounds().ToString()); + EXPECT_EQ(1.5f, GetStoredUIScale(display1.id())); + + MoveMouseToInHostCoord(root_windows[0], 300, 200); + magnifier->SetEnabled(true); + EXPECT_EQ("224,149", event_handler.GetLocationAndReset()); + EXPECT_FLOAT_EQ(2.0f, magnifier->GetScale()); + + MoveMouseToInHostCoord(root_windows[0], 300, 200); + EXPECT_EQ("224,148", event_handler.GetLocationAndReset()); + MoveMouseToInHostCoord(root_windows[0], 200, 300); + EXPECT_EQ("261,111", event_handler.GetLocationAndReset()); + MoveMouseToInHostCoord(root_windows[0], 100, 400); + EXPECT_EQ("299,60", event_handler.GetLocationAndReset()); + MoveMouseToInHostCoord(root_windows[0], 0, 0); + EXPECT_EQ("348,159", event_handler.GetLocationAndReset()); + + magnifier->SetEnabled(false); + EXPECT_FLOAT_EQ(1.0f, magnifier->GetScale()); + + // Test 3 + UpdateDisplay("600x400*2/l@1.5"); + display1 = Shell::GetScreen()->GetPrimaryDisplay(); + root_windows = Shell::GetAllRootWindows(); + EXPECT_EQ("0,0 300x450", display1.bounds().ToString()); + EXPECT_EQ("0,0 300x450", root_windows[0]->bounds().ToString()); + EXPECT_EQ(1.5f, GetStoredUIScale(display1.id())); + + MoveMouseToInHostCoord(root_windows[0], 300, 200); + magnifier->SetEnabled(true); + EXPECT_EQ("149,225", event_handler.GetLocationAndReset()); + EXPECT_FLOAT_EQ(2.0f, magnifier->GetScale()); + + MoveMouseToInHostCoord(root_windows[0], 300, 200); + EXPECT_EQ("148,224", event_handler.GetLocationAndReset()); + MoveMouseToInHostCoord(root_windows[0], 200, 300); + EXPECT_EQ("111,187", event_handler.GetLocationAndReset()); + MoveMouseToInHostCoord(root_windows[0], 100, 400); + EXPECT_EQ("60,149", event_handler.GetLocationAndReset()); + MoveMouseToInHostCoord(root_windows[0], 0, 0); + EXPECT_EQ("159,99", event_handler.GetLocationAndReset()); + + magnifier->SetEnabled(false); + EXPECT_FLOAT_EQ(1.0f, magnifier->GetScale()); + + Shell::GetInstance()->RemovePreTargetHandler(&event_handler); +} + +} // namespace test +} // namespace ash diff --git a/ash/display/display_controller.cc b/ash/display/display_controller.cc index cba80e2..87b22a8 100644 --- a/ash/display/display_controller.cc +++ b/ash/display/display_controller.cc @@ -54,14 +54,9 @@ #undef RootWindow #endif // defined(OS_CHROMEOS) -DECLARE_WINDOW_PROPERTY_TYPE(gfx::Display::Rotation); - namespace ash { namespace { -DEFINE_WINDOW_PROPERTY_KEY(gfx::Display::Rotation, kRotationPropertyKey, - gfx::Display::ROTATE_0); - // Primary display stored in global object as it can be // accessed after Shell is deleted. A separate display instance is created // during the shutdown instead of always keeping two display instances @@ -129,62 +124,6 @@ internal::DisplayManager* GetDisplayManager() { return Shell::GetInstance()->display_manager(); } -// Round near zero value to zero. -void RoundNearZero(gfx::Transform* transform) { - const float kEpsilon = 0.001f; - SkMatrix44& matrix = transform->matrix(); - for (int x = 0; x < 4; ++x) { - for (int y = 0; y < 4; ++y) { - if (std::abs(SkMScalarToFloat(matrix.get(x, y))) < kEpsilon) - matrix.set(x, y, SkFloatToMScalar(0.0f)); - } - } -} - -void RotateRootWindow(aura::RootWindow* root_window, - const gfx::Display& display, - const internal::DisplayInfo& info) { - // TODO(oshima): Add animation. (crossfade+rotation, or just cross-fade) -#if defined(OS_WIN) - // Windows 8 bots refused to resize the host window, and - // updating the transform results in incorrectly resizing - // the root window. Don't apply the transform unless - // necessary so that unit tests pass on win8 bots. - if (info.rotation() == root_window->GetProperty(kRotationPropertyKey)) - return; - root_window->SetProperty(kRotationPropertyKey, info.rotation()); -#endif - gfx::Transform rotate; - // The origin is (0, 0), so the translate width/height must be reduced by - // 1 pixel. - float one_pixel = 1.0f / display.device_scale_factor(); - switch (info.rotation()) { - case gfx::Display::ROTATE_0: - break; - case gfx::Display::ROTATE_90: - rotate.Translate(display.bounds().height() - one_pixel, 0); - rotate.Rotate(90); - break; - case gfx::Display::ROTATE_270: - rotate.Translate(0, display.bounds().width() - one_pixel); - rotate.Rotate(270); - break; - case gfx::Display::ROTATE_180: - rotate.Translate(display.bounds().width() - one_pixel, - display.bounds().height() - one_pixel); - rotate.Rotate(180); - break; - } - RoundNearZero(&rotate); - - scoped_ptr<aura::RootWindowTransformer> transformer( - new AshRootWindowTransformer(root_window, - rotate, - info.GetOverscanInsetsInPixel(), - info.ui_scale())); - root_window->SetRootWindowTransformer(transformer.Pass()); -} - void SetDisplayPropertiesOnHostWindow(aura::RootWindow* root, const gfx::Display& display) { internal::DisplayInfo info = @@ -226,7 +165,9 @@ void SetDisplayPropertiesOnHostWindow(aura::RootWindow* root, kCARDINAL, 100 * display.device_scale_factor()); #endif - RotateRootWindow(root, display, info); + scoped_ptr<aura::RootWindowTransformer> transformer( + new AshRootWindowTransformer(root, display)); + root->SetRootWindowTransformer(transformer.Pass()); } } // namespace diff --git a/ash/magnifier/magnification_controller.cc b/ash/magnifier/magnification_controller.cc index ba1de9e..21cb63b 100644 --- a/ash/magnifier/magnification_controller.cc +++ b/ash/magnifier/magnification_controller.cc @@ -4,12 +4,15 @@ #include "ash/magnifier/magnification_controller.h" +#include "ash/ash_root_window_transformer.h" #include "ash/display/display_controller.h" +#include "ash/display/display_manager.h" #include "ash/shell.h" #include "ash/shell_delegate.h" #include "ash/system/tray/system_tray_delegate.h" #include "ui/aura/client/cursor_client.h" #include "ui/aura/root_window.h" +#include "ui/aura/root_window_transformer.h" #include "ui/aura/window.h" #include "ui/aura/window_property.h" #include "ui/base/events/event.h" @@ -18,6 +21,7 @@ #include "ui/compositor/layer.h" #include "ui/compositor/layer_animation_observer.h" #include "ui/compositor/scoped_layer_animation_settings.h" +#include "ui/gfx/point3_f.h" #include "ui/gfx/point_conversions.h" #include "ui/gfx/point_f.h" #include "ui/gfx/rect_conversions.h" @@ -38,6 +42,14 @@ const float kScrollScaleChangeFactor = 0.05f; // |kPanningMergin| from the edge, the view-port moves. const int kPanningMergin = 100; +void MoveCursorTo(aura::RootWindow* root_window, + const gfx::Point root_location) { + gfx::Point3F host_location_3f(root_location); + root_window->layer()->transform().TransformPoint(host_location_3f); + root_window->MoveCursorToHostLoation( + gfx::ToCeiledPoint(host_location_3f.AsPointF())); +} + } // namespace namespace ash { @@ -74,6 +86,9 @@ class MagnificationControllerImpl : virtual public MagnificationController, // aura::WindowObserver overrides: virtual void OnWindowDestroying(aura::Window* root_window) OVERRIDE; + virtual void OnWindowBoundsChanged(aura::Window* window, + const gfx::Rect& old_bounds, + const gfx::Rect& new_bounds) OVERRIDE; // Redraws the magnification window with the given origin position and the // given scale. Returns true if the window is changed; otherwise, false. @@ -251,7 +266,11 @@ bool MagnificationControllerImpl::RedrawDIP(const gfx::PointF& position_in_dip, settings.SetTransitionDuration( base::TimeDelta::FromMilliseconds(animate ? 100 : 0)); - root_window_->layer()->SetTransform(transform); + gfx::Display display = + Shell::GetScreen()->GetDisplayNearestWindow(root_window_); + scoped_ptr<aura::RootWindowTransformer> transformer( + new AshRootWindowTransformer(root_window_, display)); + root_window_->SetRootWindowTransformer(transformer.Pass()); if (animate) is_on_animation_ = true; @@ -358,7 +377,7 @@ void MagnificationControllerImpl::OnMouseMove(const gfx::Point& location) { if (ret) { // If the magnified region is moved, hides the mouse cursor and moves it. if (x_diff != 0 || y_diff != 0) - root_window_->MoveCursorTo(mouse); + MoveCursorTo(root_window_, mouse); } } } @@ -381,14 +400,11 @@ void MagnificationControllerImpl::AfterAnimationMoveCursorTo( } gfx::Size MagnificationControllerImpl::GetHostSizeDIP() const { - return ui::ConvertSizeToDIP(root_window_->layer(), - root_window_->GetHostSize()); + return root_window_->bounds().size(); } gfx::RectF MagnificationControllerImpl::GetWindowRectDIP(float scale) const { - const gfx::Size size_in_dip = - ui::ConvertSizeToDIP(root_window_->layer(), - root_window_->GetHostSize()); + const gfx::Size size_in_dip = root_window_->bounds().size(); const float width = size_in_dip.width() / scale; const float height = size_in_dip.height() / scale; @@ -418,7 +434,7 @@ void MagnificationControllerImpl::OnImplicitAnimationsCompleted() { return; if (move_cursor_after_animation_) { - root_window_->MoveCursorTo(position_after_animation_); + MoveCursorTo(root_window_, position_after_animation_); move_cursor_after_animation_ = false; aura::client::CursorClient* cursor_client = @@ -448,6 +464,13 @@ void MagnificationControllerImpl::OnWindowDestroying( } } +void MagnificationControllerImpl::OnWindowBoundsChanged( + aura::Window* window, + const gfx::Rect& old_bounds, + const gfx::Rect& new_bounds) { + // TODO(yoshiki): implement here. crbug.com/230979 +} + void MagnificationControllerImpl::SwitchTargetRootWindow( aura::RootWindow* new_root_window, bool redraw_original_root_window) { @@ -526,9 +549,9 @@ void MagnificationControllerImpl::SetEnabled(bool enabled) { if (is_enabled_ && scale == scale_) return; + is_enabled_ = enabled; RedrawKeepingMousePosition(scale, true); ash::Shell::GetInstance()->delegate()->SaveScreenMagnifierScale(scale); - is_enabled_ = enabled; } else { // Do nothing, if already disabled. if (!is_enabled_) diff --git a/ash/magnifier/magnification_controller_unittest.cc b/ash/magnifier/magnification_controller_unittest.cc index 2060df4..b26ec36 100644 --- a/ash/magnifier/magnification_controller_unittest.cc +++ b/ash/magnifier/magnification_controller_unittest.cc @@ -107,7 +107,7 @@ TEST_F(MagnificationControllerTest, MagnifyAndUnmagnify) { GetMagnificationController()->SetScale(3.0f, false); EXPECT_EQ(3.0f, GetMagnificationController()->GetScale()); - EXPECT_EQ("266,200 268x200", GetViewport().ToString()); + EXPECT_EQ("266,200 267x200", GetViewport().ToString()); } TEST_F(MagnificationControllerTest, MoveWindow) { |