diff options
-rw-r--r-- | ash/ash.gyp | 8 | ||||
-rw-r--r-- | ash/ash_root_window_transformer.cc | 176 | ||||
-rw-r--r-- | ash/ash_root_window_transformer.h | 65 | ||||
-rw-r--r-- | ash/display/display_controller.cc | 11 | ||||
-rw-r--r-- | ash/display/display_controller.h | 2 | ||||
-rw-r--r-- | ash/display/display_manager.cc | 35 | ||||
-rw-r--r-- | ash/display/display_manager.h | 6 | ||||
-rw-r--r-- | ash/display/display_manager_unittest.cc | 54 | ||||
-rw-r--r-- | ash/display/mirror_window_controller.cc | 119 | ||||
-rw-r--r-- | ash/display/mirror_window_controller.h | 5 | ||||
-rw-r--r-- | ash/display/mirror_window_controller_unittest.cc | 52 | ||||
-rw-r--r-- | ash/display/root_window_transformers.cc | 276 | ||||
-rw-r--r-- | ash/display/root_window_transformers.h | 40 | ||||
-rw-r--r-- | ash/display/root_window_transformers_unittest.cc (renamed from ash/ash_root_window_transformer_unittest.cc) | 8 | ||||
-rw-r--r-- | ash/magnifier/magnification_controller.cc | 4 | ||||
-rw-r--r-- | ash/system/chromeos/tray_display.cc | 2 |
16 files changed, 551 insertions, 312 deletions
diff --git a/ash/ash.gyp b/ash/ash.gyp index 9120154..96e918c 100644 --- a/ash/ash.gyp +++ b/ash/ash.gyp @@ -64,8 +64,6 @@ 'accelerators/nested_dispatcher_controller.h', 'ash_constants.cc', 'ash_constants.h', - 'ash_root_window_transformer.cc', - 'ash_root_window_transformer.h', 'ash_switches.cc', 'ash_switches.h', 'cancel_mode.cc', @@ -105,6 +103,8 @@ 'display/mouse_cursor_event_filter.h', 'display/output_configurator_animation.cc', 'display/output_configurator_animation.h', + 'display/root_window_transformers.cc', + 'display/root_window_transformers.h', 'display/screen_position_controller.cc', 'display/screen_position_controller.h', 'display/shared_display_edge_indicator.cc', @@ -630,15 +630,15 @@ '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', 'display/display_error_dialog_unittest.cc', 'display/display_info_unittest.cc', + 'display/display_manager_unittest.cc', 'display/mirror_window_controller_unittest.cc', 'display/mouse_cursor_event_filter_unittest.cc', - 'display/display_manager_unittest.cc', + 'display/root_window_transformers_unittest.cc', 'display/screen_position_controller_unittest.cc', 'drag_drop/drag_drop_controller_unittest.cc', 'drag_drop/drag_drop_tracker_unittest.cc', diff --git a/ash/ash_root_window_transformer.cc b/ash/ash_root_window_transformer.cc deleted file mode 100644 index fa8a8a3..0000000 --- a/ash/ash_root_window_transformer.cc +++ /dev/null @@ -1,176 +0,0 @@ -// 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 <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; -} - -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()); - } - 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_; -} - -gfx::Transform AshRootWindowTransformer::GetInverseTransform() const { - return invert_transform_; -} - -gfx::Rect AshRootWindowTransformer::GetRootWindowBounds( - const gfx::Size& host_size) const { - gfx::Rect bounds(host_size); - bounds.Inset(host_insets_); - bounds = ui::ConvertRectToDIP(root_window_->layer(), bounds); - gfx::RectF new_bounds(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_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 - // backing pixel when |root_window_scale_| is specified - // (850 height at 1.25 scale becomes 1062.5 for example.) - return gfx::Rect(gfx::ToFlooredSize(new_bounds.size())); -} - -gfx::Insets AshRootWindowTransformer::GetHostInsets() const { - return host_insets_; -} - -} // namespace ash diff --git a/ash/ash_root_window_transformer.h b/ash/ash_root_window_transformer.h deleted file mode 100644 index 424a6cf..0000000 --- a/ash/ash_root_window_transformer.h +++ /dev/null @@ -1,65 +0,0 @@ -// 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. - -#ifndef ASH_ASH_ROOT_WINDOW_TRANSFORMER_H_ -#define ASH_ASH_ROOT_WINDOW_TRANSFORMER_H_ - -#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" - -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::Display& display); - // aura::RootWindowTransformer overrides: - virtual gfx::Transform GetTransform() const OVERRIDE; - virtual gfx::Transform GetInverseTransform() const OVERRIDE; - virtual gfx::Rect GetRootWindowBounds( - const gfx::Size& host_size) const OVERRIDE; - virtual gfx::Insets GetHostInsets() const OVERRIDE; - - private: - virtual ~AshRootWindowTransformer(); - - aura::RootWindow* root_window_; - gfx::Transform transform_; - - // The accurate representation of the inverse of the |transform_|. - // This is used to avoid computation error caused by - // |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_ui_scale_; - - gfx::Insets host_insets_; - - DISALLOW_COPY_AND_ASSIGN(AshRootWindowTransformer); -}; - -} // namespace ash - -#endif // ASH_ASH_ROOT_WINDOW_TRANSFORMER_H_ diff --git a/ash/display/display_controller.cc b/ash/display/display_controller.cc index dd6307c..f9374cd 100644 --- a/ash/display/display_controller.cc +++ b/ash/display/display_controller.cc @@ -8,10 +8,10 @@ #include <cmath> #include <map> -#include "ash/ash_root_window_transformer.h" #include "ash/ash_switches.h" #include "ash/display/display_manager.h" #include "ash/display/display_pref_util.h" +#include "ash/display/root_window_transformers.h" #include "ash/host/root_window_host_factory.h" #include "ash/root_window_controller.h" #include "ash/screen_ash.h" @@ -33,6 +33,7 @@ #include "ui/aura/client/screen_position_client.h" #include "ui/aura/env.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/aura/window_tracker.h" @@ -168,7 +169,7 @@ void SetDisplayPropertiesOnHostWindow(aura::RootWindow* root, 100 * display.device_scale_factor()); #endif scoped_ptr<aura::RootWindowTransformer> transformer( - new AshRootWindowTransformer(root, display)); + internal::CreateRootWindowTransformerForDisplay(root, display)); root->SetRootWindowTransformer(transformer.Pass()); } @@ -600,8 +601,10 @@ DisplayLayout DisplayController::GetCurrentDisplayLayout() const { DisplayIdPair DisplayController::GetCurrentDisplayIdPair() const { internal::DisplayManager* display_manager = GetDisplayManager(); const gfx::Display& primary = GetPrimaryDisplay(); - if (display_manager->IsMirrored()) - return std::make_pair(primary.id(), display_manager->mirrored_display_id()); + if (display_manager->IsMirrored()) { + return std::make_pair(primary.id(), + display_manager->mirrored_display().id()); + } const gfx::Display& secondary = ScreenAsh::GetSecondaryDisplay(); if (primary.IsInternal() || diff --git a/ash/display/display_controller.h b/ash/display/display_controller.h index d44567a..ca441cb 100644 --- a/ash/display/display_controller.h +++ b/ash/display/display_controller.h @@ -89,7 +89,7 @@ class ASH_EXPORT DisplayController : public gfx::DisplayObserver { public: // Invoked when the display configuration change is requested, // but before the change is applied to aura/ash. - virtual void OnDisplayConfigurationChanging() = 0; + virtual void OnDisplayConfigurationChanging() {} // Invoked when the all display configuration changes // have been applied. diff --git a/ash/display/display_manager.cc b/ash/display/display_manager.cc index 869517c..e257cf8 100644 --- a/ash/display/display_manager.cc +++ b/ash/display/display_manager.cc @@ -250,6 +250,7 @@ void DisplayManager::SetOverscanInsets(int64 display_id, iter != displays_.end(); ++iter) { display_info_list.push_back(GetDisplayInfo(iter->id())); } + AddMirrorDisplayInfoIfAny(&display_info_list); UpdateDisplays(display_info_list); } @@ -260,6 +261,7 @@ void DisplayManager::ClearCustomOverscanInsets(int64 display_id) { iter != displays_.end(); ++iter) { display_info_list.push_back(GetDisplayInfo(iter->id())); } + AddMirrorDisplayInfoIfAny(&display_info_list); UpdateDisplays(display_info_list); } @@ -278,6 +280,7 @@ void DisplayManager::SetDisplayRotation(int64 display_id, } display_info_list.push_back(info); } + AddMirrorDisplayInfoIfAny(&display_info_list); UpdateDisplays(display_info_list); } @@ -305,6 +308,7 @@ void DisplayManager::SetDisplayUIScale(int64 display_id, } display_info_list.push_back(info); } + AddMirrorDisplayInfoIfAny(&display_info_list); UpdateDisplays(display_info_list); } @@ -411,6 +415,7 @@ void DisplayManager::UpdateDisplays() { iter != displays_.end(); ++iter) { display_info_list.push_back(GetDisplayInfo(iter->id())); } + AddMirrorDisplayInfoIfAny(&display_info_list); UpdateDisplays(display_info_list); } @@ -432,16 +437,22 @@ void DisplayManager::UpdateDisplays( bool update_mouse_location = false; scoped_ptr<MirrorWindowUpdater> mirror_window_updater; - // TODO(oshima): We may want to use external as the source. + // Use the internal display or 1st as the mirror source, then scale + // the root window so that it matches the external display's + // resolution. This is necessary in order for scaling to work while + // mirrored. int mirrored_display_id = gfx::Display::kInvalidDisplayID; - if (software_mirroring_enabled_ && updated_display_info_list.size() == 2) - mirrored_display_id = updated_display_info_list[1].id(); + if (software_mirroring_enabled_ && new_display_info_list.size() == 2) + mirrored_display_id = new_display_info_list[1].id(); while (curr_iter != displays_.end() || new_info_iter != new_display_info_list.end()) { if (new_info_iter != new_display_info_list.end() && mirrored_display_id == new_info_iter->id()) { - InsertAndUpdateDisplayInfo(*new_info_iter); + DisplayInfo info = *new_info_iter; + info.SetOverscanInsets(true, gfx::Insets()); + InsertAndUpdateDisplayInfo(info); + mirrored_display_ = CreateDisplayFromDisplayInfoById(new_info_iter->id()); mirror_window_updater.reset( new MirrorWindowCreator(display_info_[new_info_iter->id()])); @@ -557,6 +568,7 @@ void DisplayManager::UpdateDisplays( iter != changed_display_indices.end(); ++iter) { Shell::GetInstance()->screen()->NotifyBoundsChanged(displays_[*iter]); } + mirror_window_updater.reset(); display_controller->NotifyDisplayConfigurationChanged(); if (update_mouse_location) display_controller->EnsurePointerInDisplays(); @@ -648,7 +660,7 @@ const gfx::Display& DisplayManager::GetDisplayMatching( const DisplayInfo& DisplayManager::GetDisplayInfo(int64 display_id) const { std::map<int64, DisplayInfo>::const_iterator iter = display_info_.find(display_id); - CHECK(iter != display_info_.end()); + CHECK(iter != display_info_.end()) << display_id; return iter->second; } @@ -708,6 +720,7 @@ void DisplayManager::AddRemoveDisplay() { "%d+%d-500x400", host_bounds.x(), host_bounds.bottom()))); } num_connected_displays_ = new_display_info_list.size(); + mirrored_display_ = gfx::Display(); UpdateDisplays(new_display_info_list); } @@ -721,6 +734,7 @@ void DisplayManager::ToggleDisplayScaleFactor() { display_info.device_scale_factor() == 1.0f ? 2.0f : 1.0f); new_display_info_list.push_back(display_info); } + AddMirrorDisplayInfoIfAny(&new_display_info_list); UpdateDisplays(new_display_info_list); } @@ -732,9 +746,14 @@ void DisplayManager::OnRootWindowResized(const aura::RootWindow* root, display_info_[display.id()].SetBounds( gfx::Rect(root->GetHostOrigin(), root->GetHostSize())); const gfx::Size& new_root_size = root->bounds().size(); + // It's tricky to support resizing mirror window on desktop. + if (software_mirroring_enabled_ && mirrored_display_.id() == display.id()) + return; if (old_size != new_root_size) { display.SetSize(display_info_[display.id()].size_in_pixel()); Shell::GetInstance()->screen()->NotifyBoundsChanged(display); + Shell::GetInstance()->mirror_window_controller()-> + UpdateWindow(); } } } @@ -798,6 +817,12 @@ gfx::Display& DisplayManager::FindDisplayForId(int64 id) { return GetInvalidDisplay(); } +void DisplayManager::AddMirrorDisplayInfoIfAny( + std::vector<DisplayInfo>* display_info_list) { + if (software_mirroring_enabled_ && mirrored_display_.is_valid()) + display_info_list->push_back(GetDisplayInfo(mirrored_display_.id())); +} + void DisplayManager::AddDisplayFromSpec(const std::string& spec) { DisplayInfo display_info = DisplayInfo::CreateFromSpec(spec); InsertAndUpdateDisplayInfo(display_info); diff --git a/ash/display/display_manager.h b/ash/display/display_manager.h index c7b47a8..5591b5c 100644 --- a/ash/display/display_manager.h +++ b/ash/display/display_manager.h @@ -143,7 +143,7 @@ class ASH_EXPORT DisplayManager : // Returns the mirroring status. bool IsMirrored() const; - int64 mirrored_display_id() const { return mirrored_display_.id(); } + const gfx::Display& mirrored_display() const { return mirrored_display_; } // Returns the display object nearest given |window|. const gfx::Display& GetDisplayNearestPoint( @@ -210,6 +210,10 @@ class ASH_EXPORT DisplayManager : gfx::Display& FindDisplayForRootWindow(const aura::RootWindow* root); gfx::Display& FindDisplayForId(int64 id); + // Add the mirror display's display info if the software based + // mirroring is in use. + void AddMirrorDisplayInfoIfAny(std::vector<DisplayInfo>* display_info_list); + // Refer to |CreateDisplayFromSpec| API for the format of |spec|. void AddDisplayFromSpec(const std::string& spec); diff --git a/ash/display/display_manager_unittest.cc b/ash/display/display_manager_unittest.cc index 354a73d..ae04be0 100644 --- a/ash/display/display_manager_unittest.cc +++ b/ash/display/display_manager_unittest.cc @@ -86,6 +86,12 @@ class DisplayManagerTest : public test::AshTestBase, return GetDisplayInfo(display_manager()->FindDisplayForId(id)); } + const gfx::Display GetMirroredDisplay() { + test::MirrorWindowTestApi test_api; + return Shell::GetInstance()->display_manager()-> + FindDisplayForRootWindow(test_api.GetRootWindow()); + } + // aura::DisplayObserver overrides: virtual void OnDisplayBoundsChanged(const gfx::Display& display) OVERRIDE { changed_.push_back(display); @@ -391,7 +397,7 @@ TEST_F(DisplayManagerTest, TestNativeDisplaysChanged) { EXPECT_EQ(default_bounds, display_manager()->GetDisplayAt(0)->bounds().ToString()); EXPECT_EQ(1U, display_manager()->num_connected_displays()); - EXPECT_EQ(invalid_id, display_manager()->mirrored_display_id()); + EXPECT_FALSE(display_manager()->mirrored_display().is_valid()); // External connected while primary was disconnected. display_info_list.push_back(external_display_info); @@ -402,7 +408,7 @@ TEST_F(DisplayManagerTest, TestNativeDisplaysChanged) { EXPECT_EQ("1,1 100x100", FindDisplayInfoForId(external_id).bounds_in_pixel().ToString()); EXPECT_EQ(1U, display_manager()->num_connected_displays()); - EXPECT_EQ(invalid_id, display_manager()->mirrored_display_id()); + EXPECT_FALSE(display_manager()->mirrored_display().is_valid()); EXPECT_EQ(external_id, Shell::GetScreen()->GetPrimaryDisplay().id()); // Primary connected, with different bounds. @@ -417,7 +423,7 @@ TEST_F(DisplayManagerTest, TestNativeDisplaysChanged) { EXPECT_EQ("1,1 100x100", FindDisplayInfoForId(10).bounds_in_pixel().ToString()); EXPECT_EQ(2U, display_manager()->num_connected_displays()); - EXPECT_EQ(invalid_id, display_manager()->mirrored_display_id()); + EXPECT_FALSE(display_manager()->mirrored_display().is_valid()); EXPECT_EQ(StringPrintf("x-%d", internal_display_id), display_manager()->GetDisplayNameForId(internal_display_id)); @@ -430,7 +436,7 @@ TEST_F(DisplayManagerTest, TestNativeDisplaysChanged) { EXPECT_EQ("1,1 100x100", FindDisplayInfoForId(10).bounds_in_pixel().ToString()); EXPECT_EQ(2U, display_manager()->num_connected_displays()); - EXPECT_EQ(invalid_id, display_manager()->mirrored_display_id()); + EXPECT_FALSE(display_manager()->mirrored_display().is_valid()); EXPECT_EQ(StringPrintf("x-%d", internal_display_id), display_manager()->GetDisplayNameForId(internal_display_id)); @@ -441,21 +447,21 @@ TEST_F(DisplayManagerTest, TestNativeDisplaysChanged) { EXPECT_EQ("0,0 500x500", FindDisplayForId(internal_display_id).bounds().ToString()); EXPECT_EQ(1U, display_manager()->num_connected_displays()); - EXPECT_EQ(invalid_id, display_manager()->mirrored_display_id()); + EXPECT_FALSE(display_manager()->mirrored_display().is_valid()); // External display was changed during suspend. display_info_list.push_back(external_display_info); display_manager()->OnNativeDisplaysChanged(display_info_list); EXPECT_EQ(2U, display_manager()->GetNumDisplays()); EXPECT_EQ(2U, display_manager()->num_connected_displays()); - EXPECT_EQ(invalid_id, display_manager()->mirrored_display_id()); + EXPECT_FALSE(display_manager()->mirrored_display().is_valid()); // suspend... display_info_list.clear(); display_manager()->OnNativeDisplaysChanged(display_info_list); EXPECT_EQ(2U, display_manager()->GetNumDisplays()); EXPECT_EQ(2U, display_manager()->num_connected_displays()); - EXPECT_EQ(invalid_id, display_manager()->mirrored_display_id()); + EXPECT_FALSE(display_manager()->mirrored_display().is_valid()); // and resume with different external display. display_info_list.push_back(internal_display_info); @@ -463,7 +469,7 @@ TEST_F(DisplayManagerTest, TestNativeDisplaysChanged) { display_manager()->OnNativeDisplaysChanged(display_info_list); EXPECT_EQ(2U, display_manager()->GetNumDisplays()); EXPECT_EQ(2U, display_manager()->num_connected_displays()); - EXPECT_EQ(invalid_id, display_manager()->mirrored_display_id()); + EXPECT_FALSE(display_manager()->mirrored_display().is_valid()); EXPECT_FALSE(display_manager()->IsMirrored()); // mirrored... @@ -475,7 +481,7 @@ TEST_F(DisplayManagerTest, TestNativeDisplaysChanged) { EXPECT_EQ("0,0 500x500", FindDisplayForId(internal_display_id).bounds().ToString()); EXPECT_EQ(2U, display_manager()->num_connected_displays()); - EXPECT_EQ(11U, display_manager()->mirrored_display_id()); + EXPECT_EQ(11U, display_manager()->mirrored_display().id()); EXPECT_TRUE(display_manager()->IsMirrored()); // Test display name. @@ -509,7 +515,7 @@ TEST_F(DisplayManagerTest, TestNativeDisplaysChanged) { EXPECT_EQ("1,1 100x100", FindDisplayInfoForId(external_id).bounds_in_pixel().ToString()); EXPECT_EQ(1U, display_manager()->num_connected_displays()); - EXPECT_EQ(invalid_id, display_manager()->mirrored_display_id()); + EXPECT_FALSE(display_manager()->mirrored_display().is_valid()); // Switched to another display display_info_list.clear(); @@ -520,7 +526,7 @@ TEST_F(DisplayManagerTest, TestNativeDisplaysChanged) { "0,0 500x500", FindDisplayInfoForId(internal_display_id).bounds_in_pixel().ToString()); EXPECT_EQ(1U, display_manager()->num_connected_displays()); - EXPECT_EQ(invalid_id, display_manager()->mirrored_display_id()); + EXPECT_FALSE(display_manager()->mirrored_display().is_valid()); } #if defined(OS_WIN) @@ -877,12 +883,38 @@ TEST_F(DisplayManagerTest, MAYBE_SoftwareMirroring) { EXPECT_EQ("0,0 300x400", Shell::GetScreen()->GetPrimaryDisplay().bounds().ToString()); EXPECT_EQ("400x500", test_api.GetRootWindow()->GetHostSize().ToString()); + EXPECT_EQ("300x400", test_api.GetRootWindow()->bounds().size().ToString()); EXPECT_TRUE(display_manager->IsMirrored()); display_manager->SetMirrorMode(false); EXPECT_EQ(NULL, test_api.GetRootWindow()); EXPECT_EQ(2U, display_manager->GetNumDisplays()); EXPECT_FALSE(display_manager->IsMirrored()); + + // Make sure the mirror window has the pixel size of the + // source display. + display_manager->SetMirrorMode(true); + + UpdateDisplay("300x400@0.5,400x500"); + EXPECT_EQ("300x400", test_api.GetRootWindow()->bounds().size().ToString()); + EXPECT_EQ("400x500", GetMirroredDisplay().size().ToString()); + + UpdateDisplay("310x410*2,400x500"); + EXPECT_EQ("310x410", test_api.GetRootWindow()->bounds().size().ToString()); + EXPECT_EQ("400x500", GetMirroredDisplay().size().ToString()); + + UpdateDisplay("320x420/r,400x500"); + EXPECT_EQ("320x420", test_api.GetRootWindow()->bounds().size().ToString()); + EXPECT_EQ("400x500", GetMirroredDisplay().size().ToString()); + + UpdateDisplay("330x440/r,400x500"); + EXPECT_EQ("330x440", test_api.GetRootWindow()->bounds().size().ToString()); + EXPECT_EQ("400x500", GetMirroredDisplay().size().ToString()); + + // Overscan insets are ignored. + UpdateDisplay("400x600/o,600x800/o"); + EXPECT_EQ("400x600", test_api.GetRootWindow()->bounds().size().ToString()); + EXPECT_EQ("600x800", GetMirroredDisplay().size().ToString()); } } // namespace internal diff --git a/ash/display/mirror_window_controller.cc b/ash/display/mirror_window_controller.cc index 5f691f6..1b621e7 100644 --- a/ash/display/mirror_window_controller.cc +++ b/ash/display/mirror_window_controller.cc @@ -13,12 +13,14 @@ #include "ash/display/display_info.h" #include "ash/display/display_manager.h" +#include "ash/display/root_window_transformers.h" #include "ash/host/root_window_host_factory.h" #include "ash/shell.h" #include "base/stringprintf.h" #include "ui/aura/client/capture_client.h" #include "ui/aura/env.h" #include "ui/aura/root_window.h" +#include "ui/aura/root_window_transformer.h" #include "ui/aura/window_delegate.h" #include "ui/base/cursor/cursors_aura.h" #include "ui/base/hit_test.h" @@ -72,10 +74,10 @@ class CursorWindowDelegate : public aura::WindowDelegate { // aura::WindowDelegate overrides: virtual gfx::Size GetMinimumSize() const OVERRIDE { - return cursor_image_.size(); + return size_; } virtual gfx::Size GetMaximumSize() const OVERRIDE { - return cursor_image_.size(); + return size_; } virtual void OnBoundsChanged(const gfx::Rect& old_bounds, const gfx::Rect& new_bounds) OVERRIDE { @@ -116,12 +118,25 @@ class CursorWindowDelegate : public aura::WindowDelegate { return scoped_refptr<ui::Texture>(); } - void SetCursorImage(const gfx::ImageSkia& image) { - cursor_image_ = image; + // Set the cursor image for the |display|'s scale factor. Note that + // mirror window's scale factor is always 1.0f, therefore we need to + // take 2x's image and paint as if it's 1x image. + void SetCursorImage(const gfx::ImageSkia& image, + const gfx::Display& display) { + device_scale_factor_ = + ui::GetScaleFactorFromScale(display.device_scale_factor()); + const gfx::ImageSkiaRep& image_rep = + image.GetRepresentation(device_scale_factor_); + size_ = image_rep.pixel_size(); + cursor_image_ = gfx::ImageSkia::CreateFrom1xBitmap(image_rep.sk_bitmap()); } + const gfx::Size size() const { return size_; } + private: gfx::ImageSkia cursor_image_; + ui::ScaleFactor device_scale_factor_; + gfx::Size size_; DISALLOW_COPY_AND_ASSIGN(CursorWindowDelegate); }; @@ -134,45 +149,72 @@ MirrorWindowController::MirrorWindowController() MirrorWindowController::~MirrorWindowController() { // Make sure the root window gets deleted before cursor_window_delegate. - root_window_.reset(); + Close(); } void MirrorWindowController::UpdateWindow(const DisplayInfo& display_info) { static int mirror_root_window_count = 0; - if (root_window_.get()) { - root_window_->SetHostBounds(display_info.bounds_in_pixel()); - return; - } - Shell* shell = Shell::GetInstance(); - const gfx::Rect& bounds_in_pixel = display_info.bounds_in_pixel(); - aura::RootWindow::CreateParams params(bounds_in_pixel); - params.host = shell->root_window_host_factory()-> - CreateRootWindowHost(bounds_in_pixel); - root_window_.reset(new aura::RootWindow(params)); - root_window_->SetName( - base::StringPrintf("MirrorRootWindow-%d", mirror_root_window_count++)); - root_window_->compositor()->SetBackgroundColor(SK_ColorBLACK); - // No need to remove RootWindowObserver because - // the DisplayManager object outlives RootWindow objects. - root_window_->AddRootWindowObserver(shell->display_manager()); - // TODO(oshima): TouchHUD is using idkey. - root_window_->SetProperty(internal::kDisplayIdKey, display_info.id()); - root_window_->Init(); + DisplayManager* display_manager = Shell::GetInstance()->display_manager(); + + if (!root_window_.get()) { + const gfx::Rect& bounds_in_pixel = display_info.bounds_in_pixel(); + aura::RootWindow::CreateParams params(bounds_in_pixel); + params.host = Shell::GetInstance()->root_window_host_factory()-> + CreateRootWindowHost(bounds_in_pixel); + root_window_.reset(new aura::RootWindow(params)); + root_window_->SetName( + base::StringPrintf("MirrorRootWindow-%d", mirror_root_window_count++)); + root_window_->compositor()->SetBackgroundColor(SK_ColorBLACK); + // No need to remove RootWindowObserver because + // the DisplayManager object outlives RootWindow objects. + root_window_->AddRootWindowObserver(display_manager); + // TODO(oshima): TouchHUD is using idkey. + root_window_->SetProperty(internal::kDisplayIdKey, display_info.id()); + root_window_->Init(); #if defined(USE_X11) - DisableInput(root_window_->GetAcceleratedWidget()); + DisableInput(root_window_->GetAcceleratedWidget()); #endif - aura::client::SetCaptureClient(root_window_.get(), new NoneCaptureClient()); - root_window_->ShowRootWindow(); - - cursor_window_ = new aura::Window(cursor_window_delegate_.get()); - cursor_window_->SetTransparent(true); - cursor_window_->Init(ui::LAYER_TEXTURED); - root_window_->AddChild(cursor_window_); - cursor_window_->Show(); + + aura::client::SetCaptureClient(root_window_.get(), new NoneCaptureClient()); + root_window_->ShowRootWindow(); + + // TODO(oshima): Start mirroring. + + cursor_window_ = new aura::Window(cursor_window_delegate_.get()); + cursor_window_->SetTransparent(true); + cursor_window_->Init(ui::LAYER_TEXTURED); + root_window_->AddChild(cursor_window_); + cursor_window_->Show(); + } else { + root_window_->SetProperty(internal::kDisplayIdKey, display_info.id()); + root_window_->SetHostBounds(display_info.bounds_in_pixel()); + } + + const DisplayInfo& source_display_info = display_manager->GetDisplayInfo( + Shell::GetScreen()->GetPrimaryDisplay().id()); + DCHECK(display_manager->mirrored_display().is_valid()); + scoped_ptr<aura::RootWindowTransformer> transformer( + internal::CreateRootWindowTransformerForMirroredDisplay( + source_display_info, + display_info)); + root_window_->SetRootWindowTransformer(transformer.Pass()); + + UpdateCursorLocation(); +} + +void MirrorWindowController::UpdateWindow() { + if (root_window_.get()) { + DisplayManager* display_manager = Shell::GetInstance()->display_manager(); + const DisplayInfo& mirror_display_info = display_manager->GetDisplayInfo( + display_manager->mirrored_display().id()); + UpdateWindow(mirror_display_info); + } } void MirrorWindowController::Close() { if (root_window_.get()) { + root_window_->RemoveRootWindowObserver( + Shell::GetInstance()->display_manager()); NoneCaptureClient* capture_client = static_cast<NoneCaptureClient*>( aura::client::GetCaptureClient(root_window_.get())); delete capture_client; @@ -183,7 +225,9 @@ void MirrorWindowController::Close() { void MirrorWindowController::UpdateCursorLocation() { if (cursor_window_) { + // TODO(oshima): Rotate cursor image (including hotpoint). gfx::Point point = aura::Env::GetInstance()->last_mouse_location(); + Shell::GetPrimaryRootWindow()->ConvertPointToHost(&point); point.Offset(-hot_point_.x(), -hot_point_.y()); gfx::Rect bounds = cursor_window_->bounds(); bounds.set_origin(point); @@ -196,14 +240,19 @@ void MirrorWindowController::SetMirroredCursor(gfx::NativeCursor cursor) { return; current_cursor_type_ = cursor.native_type(); int resource_id; + const gfx::Display& display = Shell::GetScreen()->GetPrimaryDisplay(); bool success = ui::GetCursorDataFor( - current_cursor_type_, 1.0, &resource_id, &hot_point_); + current_cursor_type_, + display.device_scale_factor(), + &resource_id, + &hot_point_); if (!success) return; const gfx::ImageSkia* image = ResourceBundle::GetSharedInstance().GetImageSkiaNamed(resource_id); - cursor_window_delegate_->SetCursorImage(*image); + cursor_window_delegate_->SetCursorImage(*image, display); if (cursor_window_) { + cursor_window_->SetBounds(gfx::Rect(cursor_window_delegate_->size())); cursor_window_->SchedulePaintInRect( gfx::Rect(cursor_window_->bounds().size())); UpdateCursorLocation(); diff --git a/ash/display/mirror_window_controller.h b/ash/display/mirror_window_controller.h index e7b96c7..3db86b3 100644 --- a/ash/display/mirror_window_controller.h +++ b/ash/display/mirror_window_controller.h @@ -37,6 +37,11 @@ class MirrorWindowController { // Creates the new root window if one doesn't exist. void UpdateWindow(const DisplayInfo& display_info); + // Same as above, but using existing display info + // for the mirrored display. + void UpdateWindow(); + + // Close the mirror window. void Close(); // Updates the mirrored cursor location,shape and diff --git a/ash/display/mirror_window_controller_unittest.cc b/ash/display/mirror_window_controller_unittest.cc index 4b99bdd..c15f834 100644 --- a/ash/display/mirror_window_controller_unittest.cc +++ b/ash/display/mirror_window_controller_unittest.cc @@ -22,12 +22,14 @@ typedef test::AshTestBase MirrorWindowControllerTest; #if defined(OS_WIN) // Software mirroring does not work on win. -#define MAYBE_MirrorCursor DISABLED_MirrorCursor +#define MAYBE_MirrorCursorBasic DISABLED_MirrorCursorBasic +#define MAYBE_MirrorCursorLocations DISABLED_MirrorCursorLocations #else -#define MAYBE_MirrorCursor MirrorCursor +#define MAYBE_MirrorCursorBasic MirrorCursorBasic +#define MAYBE_MirrorCursorLocations MirrorCursorLocations #endif -TEST_F(MirrorWindowControllerTest, MAYBE_MirrorCursor) { +TEST_F(MirrorWindowControllerTest, MAYBE_MirrorCursorBasic) { test::MirrorWindowTestApi test_api; aura::test::TestWindowDelegate test_window_delegate; test_window_delegate.set_window_component(HTTOP); @@ -54,6 +56,7 @@ TEST_F(MirrorWindowControllerTest, MAYBE_MirrorCursor) { gfx::Point hot_point = test_api.GetCursorHotPoint(); gfx::Point cursor_window_origin = test_api.GetCursorWindow()->bounds().origin(); + EXPECT_EQ("4,4", hot_point.ToString()); EXPECT_EQ(10 - hot_point.x(), cursor_window_origin.x()); EXPECT_EQ(10 - hot_point.y(), cursor_window_origin.y()); EXPECT_EQ(ui::kCursorNull, test_api.GetCurrentCursorType()); @@ -83,5 +86,48 @@ TEST_F(MirrorWindowControllerTest, MAYBE_MirrorCursor) { EXPECT_TRUE(test_api.GetCursorWindow()->IsVisible()); } +// Make sure that the mirror cursor's location is same as +// the source display's host location in the mirror root window's +// coordinates. +TEST_F(MirrorWindowControllerTest, MAYBE_MirrorCursorLocations) { + test::MirrorWindowTestApi test_api; + DisplayManager* display_manager = Shell::GetInstance()->display_manager(); + display_manager->SetSoftwareMirroring(true); + + // Test with device scale factor. + UpdateDisplay("400x600*2,400x600"); + + aura::RootWindow* root = Shell::GetInstance()->GetPrimaryRootWindow(); + aura::test::EventGenerator generator(root); + generator.MoveMouseToInHost(10, 20); + + gfx::Point hot_point = test_api.GetCursorHotPoint(); + EXPECT_EQ("8,9", hot_point.ToString()); + gfx::Point cursor_window_origin = + test_api.GetCursorWindow()->bounds().origin(); + EXPECT_EQ(10 - hot_point.x(), cursor_window_origin.x()); + EXPECT_EQ(20 - hot_point.y(), cursor_window_origin.y()); + + // Test with ui scale + UpdateDisplay("400x600*0.5,400x600"); + generator.MoveMouseToInHost(20, 30); + + hot_point = test_api.GetCursorHotPoint(); + EXPECT_EQ("4,4", hot_point.ToString()); + cursor_window_origin = test_api.GetCursorWindow()->bounds().origin(); + EXPECT_EQ(20 - hot_point.x(), cursor_window_origin.x()); + EXPECT_EQ(30 - hot_point.y(), cursor_window_origin.y()); + + // Test with rotation + UpdateDisplay("400x600/r,400x600"); + generator.MoveMouseToInHost(30, 40); + + hot_point = test_api.GetCursorHotPoint(); + EXPECT_EQ("4,4", hot_point.ToString()); + cursor_window_origin = test_api.GetCursorWindow()->bounds().origin(); + EXPECT_EQ(30 - hot_point.x(), cursor_window_origin.x()); + EXPECT_EQ(40 - hot_point.y(), cursor_window_origin.y()); +} + } // namsspace internal } // namespace ash diff --git a/ash/display/root_window_transformers.cc b/ash/display/root_window_transformers.cc new file mode 100644 index 0000000..bb117dc --- /dev/null +++ b/ash/display/root_window_transformers.cc @@ -0,0 +1,276 @@ +// Copyright 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/display/root_window_transformers.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 "base/basictypes.h" +#include "base/memory/scoped_ptr.h" +#include "third_party/skia/include/utils/SkMatrix44.h" +#include "ui/aura/root_window.h" +#include "ui/aura/root_window_transformer.h" +#include "ui/aura/window_property.h" +#include "ui/compositor/dip_util.h" +#include "ui/gfx/display.h" +#include "ui/gfx/insets.h" +#include "ui/gfx/size_conversions.h" +#include "ui/gfx/transform.h" +#include "ui/gfx/transform.h" + +DECLARE_WINDOW_PROPERTY_TYPE(gfx::Display::Rotation); + +namespace ash { +namespace internal { +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) { + 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; +} + +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()); + } + return transform; +} + +gfx::Transform CreateInsetsAndScaleTransform(const gfx::Insets& insets, + float device_scale_factor, + float ui_scale) { + gfx::Transform transform; + if (insets.top() != 0 || insets.left() != 0) { + 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 / ui_scale; + transform.Scale(inverted_scale, inverted_scale); + return transform; +} + +gfx::Transform CreateOverscanAndUIScaleTransform(aura::RootWindow* root_window, + const gfx::Display& display) { + DisplayInfo info = + Shell::GetInstance()->display_manager()->GetDisplayInfo(display.id()); + return CreateInsetsAndScaleTransform( + info.GetOverscanInsetsInPixel(), + ui::GetDeviceScaleFactor(root_window->layer()), + info.ui_scale()); +} + +// RootWindowTransformer for ash environment. +class AshRootWindowTransformer : public aura::RootWindowTransformer { + public: + 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_)); + + 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); + } + + // aura::RootWindowTransformer overrides: + virtual gfx::Transform GetTransform() const OVERRIDE { + return transform_; + } + virtual gfx::Transform GetInverseTransform() const OVERRIDE { + return invert_transform_; + } + virtual gfx::Rect GetRootWindowBounds( + const gfx::Size& host_size) const OVERRIDE { + gfx::Rect bounds(host_size); + bounds.Inset(host_insets_); + bounds = ui::ConvertRectToDIP(root_window_->layer(), bounds); + gfx::RectF new_bounds(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_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 + // backing pixel when |root_window_scale_| is specified + // (850 height at 1.25 scale becomes 1062.5 for example.) + return gfx::Rect(gfx::ToFlooredSize(new_bounds.size())); + } + + virtual gfx::Insets GetHostInsets() const OVERRIDE { + return host_insets_; + } + + private: + virtual ~AshRootWindowTransformer() {} + + aura::RootWindow* root_window_; + gfx::Transform transform_; + + // The accurate representation of the inverse of the |transform_|. + // This is used to avoid computation error caused by + // |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_ui_scale_; + + gfx::Insets host_insets_; + + DISALLOW_COPY_AND_ASSIGN(AshRootWindowTransformer); +}; + +// RootWindowTransformer for mirror root window. We simply copy the +// texture (bitmap) of the source display into the mirror window, so +// the root window bounds is the same as the source display's +// pixel size (excluding overscan insets). +class MirrorRootWindowTransformer : public aura::RootWindowTransformer { + public: + MirrorRootWindowTransformer(const DisplayInfo& source_display_info, + const DisplayInfo& mirror_display_info) { + root_bounds_ = gfx::Rect(source_display_info.bounds_in_pixel().size()); + gfx::Rect mirror_display_rect = + gfx::Rect(mirror_display_info.bounds_in_pixel().size()); + + // TODO(oshima): Insets & scale has to be adjusted so that + // 1) it does letterbox/pillarbox to adjust aspect ratio + // 2) visible area excluding insets are correctly mapped + // to the other display's visible area. + float mirror_scale_ratio = + (static_cast<float>(root_bounds_.width()) / + static_cast<float>(mirror_display_rect.width())); + float inverted_scale = 1.0f / mirror_scale_ratio; + transform_.Scale(inverted_scale, inverted_scale); + } + + // aura::RootWindowTransformer overrides: + virtual gfx::Transform GetTransform() const OVERRIDE { + return transform_; + } + virtual gfx::Transform GetInverseTransform() const OVERRIDE { + gfx::Transform invert; + CHECK(transform_.GetInverse(&invert)); + return invert; + } + virtual gfx::Rect GetRootWindowBounds( + const gfx::Size& host_size) const OVERRIDE { + return root_bounds_; + } + virtual gfx::Insets GetHostInsets() const OVERRIDE { + return gfx::Insets(); + } + + private: + virtual ~MirrorRootWindowTransformer() {} + + gfx::Transform transform_; + gfx::Rect root_bounds_; + + DISALLOW_COPY_AND_ASSIGN(MirrorRootWindowTransformer); +}; + +} // namespace + +aura::RootWindowTransformer* CreateRootWindowTransformerForDisplay( + aura::RootWindow* root, + const gfx::Display& display) { + return new AshRootWindowTransformer(root, display); +} + +aura::RootWindowTransformer* CreateRootWindowTransformerForMirroredDisplay( + const DisplayInfo& source_display_info, + const DisplayInfo& mirror_display_info) { + return new MirrorRootWindowTransformer(source_display_info, + mirror_display_info); +} + +} // namespace internal +} // namespace ash diff --git a/ash/display/root_window_transformers.h b/ash/display/root_window_transformers.h new file mode 100644 index 0000000..aca8479 --- /dev/null +++ b/ash/display/root_window_transformers.h @@ -0,0 +1,40 @@ +// Copyright 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. + +#ifndef ASH_DISPLAY_ROOT_WINDOW_TRANSFORMERS_H_ +#define ASH_DISPLAY_ROOT_WINDOW_TRANSFORMERS_H_ + +#include "ash/ash_export.h" + +namespace aura { +class RootWindow; +class RootWindowTransformer; +} + +namespace gfx { +class Display; +class Transform; +} + +namespace ash { +namespace internal { +class DisplayInfo; + +ASH_EXPORT aura::RootWindowTransformer* CreateRootWindowTransformerForDisplay( + aura::RootWindow* root, + const gfx::Display& display); + +// Creates a RootWindowTransformers for mirror root window. +// |source_display_info| specifies the display being mirrored, +// and |mirror_display_info| specifies the display used to +// mirror the content. +ASH_EXPORT aura::RootWindowTransformer* +CreateRootWindowTransformerForMirroredDisplay( + const DisplayInfo& source_display_info, + const DisplayInfo& mirror_display_info); + +} // namespace internal +} // namespace ash + +#endif // ASH_DISPLAY_ROOT_WINDOW_TRANSFORMERS_H_ diff --git a/ash/ash_root_window_transformer_unittest.cc b/ash/display/root_window_transformers_unittest.cc index 5bca069..631ca95 100644 --- a/ash/ash_root_window_transformer_unittest.cc +++ b/ash/display/root_window_transformers_unittest.cc @@ -1,8 +1,8 @@ -// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Copyright 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/root_window_transformers.h" #include "ash/display/display_controller.h" #include "ash/display/display_info.h" @@ -291,8 +291,8 @@ TEST_F(AshRootWindowTransformerTest, MAYBE_TouchScaleAndMagnify) { 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()); + EXPECT_FLOAT_EQ(0.2f, event_handler.touch_radius_x()); + EXPECT_FLOAT_EQ(0.2f, event_handler.touch_radius_y()); generator.ScrollSequence(gfx::Point(0,0), base::TimeDelta::FromMilliseconds(100), diff --git a/ash/magnifier/magnification_controller.cc b/ash/magnifier/magnification_controller.cc index ec0a7bc..bb50285 100644 --- a/ash/magnifier/magnification_controller.cc +++ b/ash/magnifier/magnification_controller.cc @@ -4,9 +4,9 @@ #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/display/root_window_transformers.h" #include "ash/shell.h" #include "ash/shell_delegate.h" #include "ash/system/tray/system_tray_delegate.h" @@ -274,7 +274,7 @@ bool MagnificationControllerImpl::RedrawDIP(const gfx::PointF& position_in_dip, gfx::Display display = Shell::GetScreen()->GetDisplayNearestWindow(root_window_); scoped_ptr<aura::RootWindowTransformer> transformer( - new AshRootWindowTransformer(root_window_, display)); + internal::CreateRootWindowTransformerForDisplay(root_window_, display)); root_window_->SetRootWindowTransformer(transformer.Pass()); if (animate) diff --git a/ash/system/chromeos/tray_display.cc b/ash/system/chromeos/tray_display.cc index bfe814a..84f5369 100644 --- a/ash/system/chromeos/tray_display.cc +++ b/ash/system/chromeos/tray_display.cc @@ -79,7 +79,7 @@ class DisplayView : public ash::internal::ActionableView { // Returns the name of the currently connected external display. base::string16 GetExternalDisplayName() const { DisplayManager* display_manager = Shell::GetInstance()->display_manager(); - int64 external_id = display_manager->mirrored_display_id(); + int64 external_id = display_manager->mirrored_display().id(); if (external_id == gfx::Display::kInvalidDisplayID) { int64 internal_display_id = gfx::Display::InternalDisplayId(); |