| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "ash/ash_root_window_transformer.h" | |
| 6 | |
| 7 #include <cmath> | |
| 8 | |
| 9 #include "ash/display/display_info.h" | |
| 10 #include "ash/display/display_manager.h" | |
| 11 #include "ash/magnifier/magnification_controller.h" | |
| 12 #include "ash/shell.h" | |
| 13 #include "third_party/skia/include/utils/SkMatrix44.h" | |
| 14 #include "ui/aura/root_window.h" | |
| 15 #include "ui/aura/window_property.h" | |
| 16 #include "ui/compositor/dip_util.h" | |
| 17 #include "ui/gfx/display.h" | |
| 18 #include "ui/gfx/size_conversions.h" | |
| 19 #include "ui/gfx/transform.h" | |
| 20 | |
| 21 DECLARE_WINDOW_PROPERTY_TYPE(gfx::Display::Rotation); | |
| 22 | |
| 23 namespace ash { | |
| 24 namespace { | |
| 25 | |
| 26 DEFINE_WINDOW_PROPERTY_KEY(gfx::Display::Rotation, kRotationPropertyKey, | |
| 27 gfx::Display::ROTATE_0); | |
| 28 | |
| 29 // Round near zero value to zero. | |
| 30 void RoundNearZero(gfx::Transform* transform) { | |
| 31 const float kEpsilon = 0.001f; | |
| 32 SkMatrix44& matrix = transform->matrix(); | |
| 33 for (int x = 0; x < 4; ++x) { | |
| 34 for (int y = 0; y < 4; ++y) { | |
| 35 if (std::abs(SkMScalarToFloat(matrix.get(x, y))) < kEpsilon) | |
| 36 matrix.set(x, y, SkFloatToMScalar(0.0f)); | |
| 37 } | |
| 38 } | |
| 39 } | |
| 40 | |
| 41 gfx::Transform CreateRotationTransform(aura::RootWindow* root_window, | |
| 42 const gfx::Display& display) { | |
| 43 internal::DisplayInfo info = | |
| 44 Shell::GetInstance()->display_manager()->GetDisplayInfo(display.id()); | |
| 45 | |
| 46 // TODO(oshima): Add animation. (crossfade+rotation, or just cross-fade) | |
| 47 #if defined(OS_WIN) | |
| 48 // Windows 8 bots refused to resize the host window, and | |
| 49 // updating the transform results in incorrectly resizing | |
| 50 // the root window. Don't apply the transform unless | |
| 51 // necessary so that unit tests pass on win8 bots. | |
| 52 if (info.rotation() == root_window->GetProperty(kRotationPropertyKey)) | |
| 53 return gfx::Transform(); | |
| 54 root_window->SetProperty(kRotationPropertyKey, info.rotation()); | |
| 55 #endif | |
| 56 | |
| 57 gfx::Transform rotate; | |
| 58 // The origin is (0, 0), so the translate width/height must be reduced by | |
| 59 // 1 pixel. | |
| 60 float one_pixel = 1.0f / display.device_scale_factor(); | |
| 61 switch (info.rotation()) { | |
| 62 case gfx::Display::ROTATE_0: | |
| 63 break; | |
| 64 case gfx::Display::ROTATE_90: | |
| 65 rotate.Translate(display.bounds().height() - one_pixel, 0); | |
| 66 rotate.Rotate(90); | |
| 67 break; | |
| 68 case gfx::Display::ROTATE_270: | |
| 69 rotate.Translate(0, display.bounds().width() - one_pixel); | |
| 70 rotate.Rotate(270); | |
| 71 break; | |
| 72 case gfx::Display::ROTATE_180: | |
| 73 rotate.Translate(display.bounds().width() - one_pixel, | |
| 74 display.bounds().height() - one_pixel); | |
| 75 rotate.Rotate(180); | |
| 76 break; | |
| 77 } | |
| 78 | |
| 79 RoundNearZero(&rotate); | |
| 80 return rotate; | |
| 81 } | |
| 82 | |
| 83 gfx::Transform CreateMagnifierTransform(aura::RootWindow* root_window) { | |
| 84 MagnificationController* magnifier = | |
| 85 Shell::GetInstance()->magnification_controller(); | |
| 86 float magnifier_scale = 1.f; | |
| 87 gfx::Point magnifier_offset; | |
| 88 if (magnifier && magnifier->IsEnabled()) { | |
| 89 magnifier_scale = magnifier->GetScale(); | |
| 90 magnifier_offset = magnifier->GetWindowPosition(); | |
| 91 } | |
| 92 gfx::Transform transform; | |
| 93 if (magnifier_scale != 1.f) { | |
| 94 transform.Scale(magnifier_scale, magnifier_scale); | |
| 95 transform.Translate(-magnifier_offset.x(), -magnifier_offset.y()); | |
| 96 } | |
| 97 return transform; | |
| 98 } | |
| 99 | |
| 100 gfx::Transform CreateOverscanAndUIScaleTransform(aura::RootWindow* root_window, | |
| 101 const gfx::Display& display) { | |
| 102 internal::DisplayInfo info = | |
| 103 Shell::GetInstance()->display_manager()->GetDisplayInfo(display.id()); | |
| 104 gfx::Insets insets = info.GetOverscanInsetsInPixel(); | |
| 105 float scale = info.ui_scale(); | |
| 106 | |
| 107 gfx::Transform transform; | |
| 108 if (insets.top() != 0 || insets.left() != 0) { | |
| 109 float device_scale_factor = ui::GetDeviceScaleFactor(root_window->layer()); | |
| 110 float x_offset = insets.left() / device_scale_factor; | |
| 111 float y_offset = insets.top() / device_scale_factor; | |
| 112 transform.Translate(x_offset, y_offset); | |
| 113 } | |
| 114 float inverted_scale = 1.0f / scale; | |
| 115 transform.Scale(inverted_scale, inverted_scale); | |
| 116 return transform; | |
| 117 } | |
| 118 | |
| 119 } // namespace | |
| 120 | |
| 121 AshRootWindowTransformer::AshRootWindowTransformer(aura::RootWindow* root, | |
| 122 const gfx::Display& display) | |
| 123 : root_window_(root) { | |
| 124 root_window_bounds_transform_ = | |
| 125 CreateOverscanAndUIScaleTransform(root, display) * | |
| 126 CreateRotationTransform(root, display); | |
| 127 transform_ = root_window_bounds_transform_ * CreateMagnifierTransform(root); | |
| 128 CHECK(transform_.GetInverse(&invert_transform_)); | |
| 129 | |
| 130 internal::DisplayInfo info = Shell::GetInstance()-> | |
| 131 display_manager()->GetDisplayInfo(display.id()); | |
| 132 root_window_ui_scale_ = info.ui_scale(); | |
| 133 host_insets_ = info.GetOverscanInsetsInPixel(); | |
| 134 MagnificationController* magnifier = | |
| 135 Shell::GetInstance()->magnification_controller(); | |
| 136 | |
| 137 bool scaled = (root_window_ui_scale_ != 1.f) || | |
| 138 (magnifier && magnifier->GetScale() != 1.f); | |
| 139 root_window_->layer()->SetForceRenderSurface(scaled); | |
| 140 } | |
| 141 | |
| 142 AshRootWindowTransformer::~AshRootWindowTransformer() {} | |
| 143 | |
| 144 gfx::Transform AshRootWindowTransformer::GetTransform() const { | |
| 145 return transform_; | |
| 146 } | |
| 147 | |
| 148 gfx::Transform AshRootWindowTransformer::GetInverseTransform() const { | |
| 149 return invert_transform_; | |
| 150 } | |
| 151 | |
| 152 gfx::Rect AshRootWindowTransformer::GetRootWindowBounds( | |
| 153 const gfx::Size& host_size) const { | |
| 154 gfx::Rect bounds(host_size); | |
| 155 bounds.Inset(host_insets_); | |
| 156 bounds = ui::ConvertRectToDIP(root_window_->layer(), bounds); | |
| 157 gfx::RectF new_bounds(bounds); | |
| 158 root_window_bounds_transform_.TransformRect(&new_bounds); | |
| 159 // Apply |root_window_scale_| twice as the downscaling | |
| 160 // is already applied once in |SetTransformInternal()|. | |
| 161 // TODO(oshima): This is a bit ugly. Consider specifying | |
| 162 // the pseudo host resolution instead. | |
| 163 new_bounds.Scale(root_window_ui_scale_ * root_window_ui_scale_); | |
| 164 // Ignore the origin because RootWindow's insets are handled by | |
| 165 // the transform. | |
| 166 // Floor the size because the bounds is no longer aligned to | |
| 167 // backing pixel when |root_window_scale_| is specified | |
| 168 // (850 height at 1.25 scale becomes 1062.5 for example.) | |
| 169 return gfx::Rect(gfx::ToFlooredSize(new_bounds.size())); | |
| 170 } | |
| 171 | |
| 172 gfx::Insets AshRootWindowTransformer::GetHostInsets() const { | |
| 173 return host_insets_; | |
| 174 } | |
| 175 | |
| 176 } // namespace ash | |
| OLD | NEW |