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/display/root_window_transformers.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 "base/basictypes.h" |
| 14 #include "base/memory/scoped_ptr.h" |
| 15 #include "third_party/skia/include/utils/SkMatrix44.h" |
| 16 #include "ui/aura/root_window.h" |
| 17 #include "ui/aura/root_window_transformer.h" |
| 18 #include "ui/aura/window_property.h" |
| 19 #include "ui/compositor/dip_util.h" |
| 20 #include "ui/gfx/display.h" |
| 21 #include "ui/gfx/insets.h" |
| 22 #include "ui/gfx/size_conversions.h" |
| 23 #include "ui/gfx/transform.h" |
| 24 #include "ui/gfx/transform.h" |
| 25 |
| 26 DECLARE_WINDOW_PROPERTY_TYPE(gfx::Display::Rotation); |
| 27 |
| 28 namespace ash { |
| 29 namespace internal { |
| 30 namespace { |
| 31 |
| 32 DEFINE_WINDOW_PROPERTY_KEY(gfx::Display::Rotation, kRotationPropertyKey, |
| 33 gfx::Display::ROTATE_0); |
| 34 |
| 35 // Round near zero value to zero. |
| 36 void RoundNearZero(gfx::Transform* transform) { |
| 37 const float kEpsilon = 0.001f; |
| 38 SkMatrix44& matrix = transform->matrix(); |
| 39 for (int x = 0; x < 4; ++x) { |
| 40 for (int y = 0; y < 4; ++y) { |
| 41 if (std::abs(SkMScalarToFloat(matrix.get(x, y))) < kEpsilon) |
| 42 matrix.set(x, y, SkFloatToMScalar(0.0f)); |
| 43 } |
| 44 } |
| 45 } |
| 46 |
| 47 gfx::Transform CreateRotationTransform(aura::RootWindow* root_window, |
| 48 const gfx::Display& display) { |
| 49 DisplayInfo info = |
| 50 Shell::GetInstance()->display_manager()->GetDisplayInfo(display.id()); |
| 51 |
| 52 // TODO(oshima): Add animation. (crossfade+rotation, or just cross-fade) |
| 53 #if defined(OS_WIN) |
| 54 // Windows 8 bots refused to resize the host window, and |
| 55 // updating the transform results in incorrectly resizing |
| 56 // the root window. Don't apply the transform unless |
| 57 // necessary so that unit tests pass on win8 bots. |
| 58 if (info.rotation() == root_window->GetProperty(kRotationPropertyKey)) |
| 59 return gfx::Transform(); |
| 60 root_window->SetProperty(kRotationPropertyKey, info.rotation()); |
| 61 #endif |
| 62 |
| 63 gfx::Transform rotate; |
| 64 // The origin is (0, 0), so the translate width/height must be reduced by |
| 65 // 1 pixel. |
| 66 float one_pixel = 1.0f / display.device_scale_factor(); |
| 67 switch (info.rotation()) { |
| 68 case gfx::Display::ROTATE_0: |
| 69 break; |
| 70 case gfx::Display::ROTATE_90: |
| 71 rotate.Translate(display.bounds().height() - one_pixel, 0); |
| 72 rotate.Rotate(90); |
| 73 break; |
| 74 case gfx::Display::ROTATE_270: |
| 75 rotate.Translate(0, display.bounds().width() - one_pixel); |
| 76 rotate.Rotate(270); |
| 77 break; |
| 78 case gfx::Display::ROTATE_180: |
| 79 rotate.Translate(display.bounds().width() - one_pixel, |
| 80 display.bounds().height() - one_pixel); |
| 81 rotate.Rotate(180); |
| 82 break; |
| 83 } |
| 84 |
| 85 RoundNearZero(&rotate); |
| 86 return rotate; |
| 87 } |
| 88 |
| 89 gfx::Transform CreateMagnifierTransform(aura::RootWindow* root_window) { |
| 90 MagnificationController* magnifier = |
| 91 Shell::GetInstance()->magnification_controller(); |
| 92 float magnifier_scale = 1.f; |
| 93 gfx::Point magnifier_offset; |
| 94 if (magnifier && magnifier->IsEnabled()) { |
| 95 magnifier_scale = magnifier->GetScale(); |
| 96 magnifier_offset = magnifier->GetWindowPosition(); |
| 97 } |
| 98 gfx::Transform transform; |
| 99 if (magnifier_scale != 1.f) { |
| 100 transform.Scale(magnifier_scale, magnifier_scale); |
| 101 transform.Translate(-magnifier_offset.x(), -magnifier_offset.y()); |
| 102 } |
| 103 return transform; |
| 104 } |
| 105 |
| 106 gfx::Transform CreateInsetsAndScaleTransform(const gfx::Insets& insets, |
| 107 float device_scale_factor, |
| 108 float ui_scale) { |
| 109 gfx::Transform transform; |
| 110 if (insets.top() != 0 || insets.left() != 0) { |
| 111 float x_offset = insets.left() / device_scale_factor; |
| 112 float y_offset = insets.top() / device_scale_factor; |
| 113 transform.Translate(x_offset, y_offset); |
| 114 } |
| 115 float inverted_scale = 1.0f / ui_scale; |
| 116 transform.Scale(inverted_scale, inverted_scale); |
| 117 return transform; |
| 118 } |
| 119 |
| 120 gfx::Transform CreateOverscanAndUIScaleTransform(aura::RootWindow* root_window, |
| 121 const gfx::Display& display) { |
| 122 DisplayInfo info = |
| 123 Shell::GetInstance()->display_manager()->GetDisplayInfo(display.id()); |
| 124 return CreateInsetsAndScaleTransform( |
| 125 info.GetOverscanInsetsInPixel(), |
| 126 ui::GetDeviceScaleFactor(root_window->layer()), |
| 127 info.ui_scale()); |
| 128 } |
| 129 |
| 130 // RootWindowTransformer for ash environment. |
| 131 class AshRootWindowTransformer : public aura::RootWindowTransformer { |
| 132 public: |
| 133 AshRootWindowTransformer(aura::RootWindow* root, |
| 134 const gfx::Display& display) |
| 135 : root_window_(root) { |
| 136 root_window_bounds_transform_ = |
| 137 CreateOverscanAndUIScaleTransform(root, display) * |
| 138 CreateRotationTransform(root, display); |
| 139 transform_ = root_window_bounds_transform_ * CreateMagnifierTransform(root); |
| 140 CHECK(transform_.GetInverse(&invert_transform_)); |
| 141 |
| 142 DisplayInfo info = Shell::GetInstance()->display_manager()-> |
| 143 GetDisplayInfo(display.id()); |
| 144 root_window_ui_scale_ = info.ui_scale(); |
| 145 host_insets_ = info.GetOverscanInsetsInPixel(); |
| 146 MagnificationController* magnifier = |
| 147 Shell::GetInstance()->magnification_controller(); |
| 148 |
| 149 bool scaled = (root_window_ui_scale_ != 1.f) || |
| 150 (magnifier && magnifier->GetScale() != 1.f); |
| 151 root_window_->layer()->SetForceRenderSurface(scaled); |
| 152 } |
| 153 |
| 154 // aura::RootWindowTransformer overrides: |
| 155 virtual gfx::Transform GetTransform() const OVERRIDE { |
| 156 return transform_; |
| 157 } |
| 158 virtual gfx::Transform GetInverseTransform() const OVERRIDE { |
| 159 return invert_transform_; |
| 160 } |
| 161 virtual gfx::Rect GetRootWindowBounds( |
| 162 const gfx::Size& host_size) const OVERRIDE { |
| 163 gfx::Rect bounds(host_size); |
| 164 bounds.Inset(host_insets_); |
| 165 bounds = ui::ConvertRectToDIP(root_window_->layer(), bounds); |
| 166 gfx::RectF new_bounds(bounds); |
| 167 root_window_bounds_transform_.TransformRect(&new_bounds); |
| 168 // Apply |root_window_scale_| twice as the downscaling |
| 169 // is already applied once in |SetTransformInternal()|. |
| 170 // TODO(oshima): This is a bit ugly. Consider specifying |
| 171 // the pseudo host resolution instead. |
| 172 new_bounds.Scale(root_window_ui_scale_ * root_window_ui_scale_); |
| 173 // Ignore the origin because RootWindow's insets are handled by |
| 174 // the transform. |
| 175 // Floor the size because the bounds is no longer aligned to |
| 176 // backing pixel when |root_window_scale_| is specified |
| 177 // (850 height at 1.25 scale becomes 1062.5 for example.) |
| 178 return gfx::Rect(gfx::ToFlooredSize(new_bounds.size())); |
| 179 } |
| 180 |
| 181 virtual gfx::Insets GetHostInsets() const OVERRIDE { |
| 182 return host_insets_; |
| 183 } |
| 184 |
| 185 private: |
| 186 virtual ~AshRootWindowTransformer() {} |
| 187 |
| 188 aura::RootWindow* root_window_; |
| 189 gfx::Transform transform_; |
| 190 |
| 191 // The accurate representation of the inverse of the |transform_|. |
| 192 // This is used to avoid computation error caused by |
| 193 // |gfx::Transform::GetInverse|. |
| 194 gfx::Transform invert_transform_; |
| 195 |
| 196 // The transform of the root window bounds. This is used to calculate |
| 197 // the size of root window. |
| 198 gfx::Transform root_window_bounds_transform_; |
| 199 |
| 200 // The scale of the root window. This is used to expand the |
| 201 // area of the root window (useful in HighDPI display). |
| 202 // Note that this should not be confused with the device scale |
| 203 // factor, which specfies the pixel density of the display. |
| 204 float root_window_ui_scale_; |
| 205 |
| 206 gfx::Insets host_insets_; |
| 207 |
| 208 DISALLOW_COPY_AND_ASSIGN(AshRootWindowTransformer); |
| 209 }; |
| 210 |
| 211 // RootWindowTransformer for mirror root window. We simply copy the |
| 212 // texture (bitmap) of the source display into the mirror window, so |
| 213 // the root window bounds is the same as the source display's |
| 214 // pixel size (excluding overscan insets). |
| 215 class MirrorRootWindowTransformer : public aura::RootWindowTransformer { |
| 216 public: |
| 217 MirrorRootWindowTransformer(const DisplayInfo& source_display_info, |
| 218 const DisplayInfo& mirror_display_info) { |
| 219 root_bounds_ = gfx::Rect(source_display_info.bounds_in_pixel().size()); |
| 220 gfx::Rect mirror_display_rect = |
| 221 gfx::Rect(mirror_display_info.bounds_in_pixel().size()); |
| 222 |
| 223 // TODO(oshima): Insets & scale has to be adjusted so that |
| 224 // 1) it does letterbox/pillarbox to adjust aspect ratio |
| 225 // 2) visible area excluding insets are correctly mapped |
| 226 // to the other display's visible area. |
| 227 float mirror_scale_ratio = |
| 228 (static_cast<float>(root_bounds_.width()) / |
| 229 static_cast<float>(mirror_display_rect.width())); |
| 230 float inverted_scale = 1.0f / mirror_scale_ratio; |
| 231 transform_.Scale(inverted_scale, inverted_scale); |
| 232 } |
| 233 |
| 234 // aura::RootWindowTransformer overrides: |
| 235 virtual gfx::Transform GetTransform() const OVERRIDE { |
| 236 return transform_; |
| 237 } |
| 238 virtual gfx::Transform GetInverseTransform() const OVERRIDE { |
| 239 gfx::Transform invert; |
| 240 CHECK(transform_.GetInverse(&invert)); |
| 241 return invert; |
| 242 } |
| 243 virtual gfx::Rect GetRootWindowBounds( |
| 244 const gfx::Size& host_size) const OVERRIDE { |
| 245 return root_bounds_; |
| 246 } |
| 247 virtual gfx::Insets GetHostInsets() const OVERRIDE { |
| 248 return gfx::Insets(); |
| 249 } |
| 250 |
| 251 private: |
| 252 virtual ~MirrorRootWindowTransformer() {} |
| 253 |
| 254 gfx::Transform transform_; |
| 255 gfx::Rect root_bounds_; |
| 256 |
| 257 DISALLOW_COPY_AND_ASSIGN(MirrorRootWindowTransformer); |
| 258 }; |
| 259 |
| 260 } // namespace |
| 261 |
| 262 aura::RootWindowTransformer* CreateRootWindowTransformerForDisplay( |
| 263 aura::RootWindow* root, |
| 264 const gfx::Display& display) { |
| 265 return new AshRootWindowTransformer(root, display); |
| 266 } |
| 267 |
| 268 aura::RootWindowTransformer* CreateRootWindowTransformerForMirroredDisplay( |
| 269 const DisplayInfo& source_display_info, |
| 270 const DisplayInfo& mirror_display_info) { |
| 271 return new MirrorRootWindowTransformer(source_display_info, |
| 272 mirror_display_info); |
| 273 } |
| 274 |
| 275 } // namespace internal |
| 276 } // namespace ash |
OLD | NEW |