Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "ash/ash_root_window_transformer.h" | 5 #include "ash/display/root_window_transformers.h" |
| 6 | 6 |
| 7 #include <cmath> | 7 #include <cmath> |
| 8 | 8 |
| 9 #include "ash/display/display_info.h" | 9 #include "ash/display/display_info.h" |
| 10 #include "ash/display/display_manager.h" | 10 #include "ash/display/display_manager.h" |
| 11 #include "ash/magnifier/magnification_controller.h" | 11 #include "ash/magnifier/magnification_controller.h" |
| 12 #include "ash/shell.h" | 12 #include "ash/shell.h" |
| 13 #include "base/basictypes.h" | |
| 14 #include "base/memory/scoped_ptr.h" | |
| 13 #include "third_party/skia/include/utils/SkMatrix44.h" | 15 #include "third_party/skia/include/utils/SkMatrix44.h" |
| 14 #include "ui/aura/root_window.h" | 16 #include "ui/aura/root_window.h" |
| 17 #include "ui/aura/root_window_transformer.h" | |
| 15 #include "ui/aura/window_property.h" | 18 #include "ui/aura/window_property.h" |
| 16 #include "ui/compositor/dip_util.h" | 19 #include "ui/compositor/dip_util.h" |
| 17 #include "ui/gfx/display.h" | 20 #include "ui/gfx/display.h" |
| 21 #include "ui/gfx/insets.h" | |
| 18 #include "ui/gfx/size_conversions.h" | 22 #include "ui/gfx/size_conversions.h" |
| 19 #include "ui/gfx/transform.h" | 23 #include "ui/gfx/transform.h" |
| 24 #include "ui/gfx/transform.h" | |
| 20 | 25 |
| 21 DECLARE_WINDOW_PROPERTY_TYPE(gfx::Display::Rotation); | 26 DECLARE_WINDOW_PROPERTY_TYPE(gfx::Display::Rotation); |
| 22 | 27 |
| 23 namespace ash { | 28 namespace ash { |
| 29 namespace internal { | |
| 24 namespace { | 30 namespace { |
| 25 | 31 |
| 26 DEFINE_WINDOW_PROPERTY_KEY(gfx::Display::Rotation, kRotationPropertyKey, | 32 DEFINE_WINDOW_PROPERTY_KEY(gfx::Display::Rotation, kRotationPropertyKey, |
| 27 gfx::Display::ROTATE_0); | 33 gfx::Display::ROTATE_0); |
| 28 | 34 |
| 29 // Round near zero value to zero. | 35 // Round near zero value to zero. |
| 30 void RoundNearZero(gfx::Transform* transform) { | 36 void RoundNearZero(gfx::Transform* transform) { |
| 31 const float kEpsilon = 0.001f; | 37 const float kEpsilon = 0.001f; |
| 32 SkMatrix44& matrix = transform->matrix(); | 38 SkMatrix44& matrix = transform->matrix(); |
| 33 for (int x = 0; x < 4; ++x) { | 39 for (int x = 0; x < 4; ++x) { |
| 34 for (int y = 0; y < 4; ++y) { | 40 for (int y = 0; y < 4; ++y) { |
| 35 if (std::abs(SkMScalarToFloat(matrix.get(x, y))) < kEpsilon) | 41 if (std::abs(SkMScalarToFloat(matrix.get(x, y))) < kEpsilon) |
| 36 matrix.set(x, y, SkFloatToMScalar(0.0f)); | 42 matrix.set(x, y, SkFloatToMScalar(0.0f)); |
| 37 } | 43 } |
| 38 } | 44 } |
| 39 } | 45 } |
| 40 | 46 |
| 41 gfx::Transform CreateRotationTransform(aura::RootWindow* root_window, | 47 gfx::Transform CreateRotationTransform(aura::RootWindow* root_window, |
| 42 const gfx::Display& display) { | 48 const gfx::Display& display) { |
| 43 internal::DisplayInfo info = | 49 DisplayInfo info = |
| 44 Shell::GetInstance()->display_manager()->GetDisplayInfo(display.id()); | 50 Shell::GetInstance()->display_manager()->GetDisplayInfo(display.id()); |
| 45 | 51 |
| 46 // TODO(oshima): Add animation. (crossfade+rotation, or just cross-fade) | 52 // TODO(oshima): Add animation. (crossfade+rotation, or just cross-fade) |
| 47 #if defined(OS_WIN) | 53 #if defined(OS_WIN) |
| 48 // Windows 8 bots refused to resize the host window, and | 54 // Windows 8 bots refused to resize the host window, and |
| 49 // updating the transform results in incorrectly resizing | 55 // updating the transform results in incorrectly resizing |
| 50 // the root window. Don't apply the transform unless | 56 // the root window. Don't apply the transform unless |
| 51 // necessary so that unit tests pass on win8 bots. | 57 // necessary so that unit tests pass on win8 bots. |
| 52 if (info.rotation() == root_window->GetProperty(kRotationPropertyKey)) | 58 if (info.rotation() == root_window->GetProperty(kRotationPropertyKey)) |
| 53 return gfx::Transform(); | 59 return gfx::Transform(); |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 90 magnifier_offset = magnifier->GetWindowPosition(); | 96 magnifier_offset = magnifier->GetWindowPosition(); |
| 91 } | 97 } |
| 92 gfx::Transform transform; | 98 gfx::Transform transform; |
| 93 if (magnifier_scale != 1.f) { | 99 if (magnifier_scale != 1.f) { |
| 94 transform.Scale(magnifier_scale, magnifier_scale); | 100 transform.Scale(magnifier_scale, magnifier_scale); |
| 95 transform.Translate(-magnifier_offset.x(), -magnifier_offset.y()); | 101 transform.Translate(-magnifier_offset.x(), -magnifier_offset.y()); |
| 96 } | 102 } |
| 97 return transform; | 103 return transform; |
| 98 } | 104 } |
| 99 | 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 | |
| 100 gfx::Transform CreateOverscanAndUIScaleTransform(aura::RootWindow* root_window, | 120 gfx::Transform CreateOverscanAndUIScaleTransform(aura::RootWindow* root_window, |
| 101 const gfx::Display& display) { | 121 const gfx::Display& display) { |
| 102 internal::DisplayInfo info = | 122 DisplayInfo info = |
| 103 Shell::GetInstance()->display_manager()->GetDisplayInfo(display.id()); | 123 Shell::GetInstance()->display_manager()->GetDisplayInfo(display.id()); |
| 104 gfx::Insets insets = info.GetOverscanInsetsInPixel(); | 124 return CreateInsetsAndScaleTransform( |
| 105 float scale = info.ui_scale(); | 125 info.GetOverscanInsetsInPixel(), |
| 126 ui::GetDeviceScaleFactor(root_window->layer()), | |
| 127 info.ui_scale()); | |
| 128 } | |
| 106 | 129 |
| 107 gfx::Transform transform; | 130 // RootWindowTransformer for ash environment. |
| 108 if (insets.top() != 0 || insets.left() != 0) { | 131 class ASH_EXPORT AshRootWindowTransformer : public aura::RootWindowTransformer { |
|
James Cook
2013/05/29 12:22:43
Dumb question: If these are internal classes in a
oshima
2013/05/29 15:39:49
good point. I just copied from header and apparent
| |
| 109 float device_scale_factor = ui::GetDeviceScaleFactor(root_window->layer()); | 132 public: |
| 110 float x_offset = insets.left() / device_scale_factor; | 133 AshRootWindowTransformer(aura::RootWindow* root, |
| 111 float y_offset = insets.top() / device_scale_factor; | 134 const gfx::Display& display) |
| 112 transform.Translate(x_offset, y_offset); | 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); | |
| 113 } | 152 } |
| 114 float inverted_scale = 1.0f / scale; | 153 |
| 115 transform.Scale(inverted_scale, inverted_scale); | 154 // aura::RootWindowTransformer overrides: |
| 116 return transform; | 155 virtual gfx::Transform GetTransform() const OVERRIDE { |
| 117 } | 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 // kthe root window bounds is the same as the source display's | |
|
James Cook
2013/05/29 12:22:43
kthe -> the
oshima
2013/05/29 15:39:49
Done.
| |
| 214 // pixel size (excluding overscan insets). | |
| 215 class ASH_EXPORT MirrorRootWindowTransformer | |
| 216 : public aura::RootWindowTransformer { | |
| 217 public: | |
| 218 MirrorRootWindowTransformer(const DisplayInfo& source_display_info, | |
| 219 const DisplayInfo& mirror_display_info) { | |
| 220 root_bounds_ = gfx::Rect(source_display_info.bounds_in_pixel().size()); | |
| 221 gfx::Rect mirror_display_rect = | |
| 222 gfx::Rect(mirror_display_info.bounds_in_pixel().size()); | |
| 223 | |
| 224 // TODO(oshima): Insets & scale has to be adjusted so that | |
| 225 // 1) it does letterbox/pillarbox to adjust aspect ration | |
|
James Cook
2013/05/29 12:22:43
ration -> ratio
oshima
2013/05/29 15:39:49
Done.
| |
| 226 // 2) visible area excluding insets are corretly mapped | |
|
James Cook
2013/05/29 12:22:43
corretly -> correctly
I'm like a human spelling-c
oshima
2013/05/29 15:39:49
Done.
| |
| 227 // to the other display's visible area. | |
| 228 float mirror_scale_ratio = | |
| 229 (static_cast<float>(root_bounds_.width()) / | |
| 230 static_cast<float>(mirror_display_rect.width())); | |
| 231 float inverted_scale = 1.0f / mirror_scale_ratio; | |
| 232 transform_.Scale(inverted_scale, inverted_scale); | |
| 233 } | |
| 234 | |
| 235 // aura::RootWindowTransformer overrides: | |
| 236 virtual gfx::Transform GetTransform() const OVERRIDE { | |
| 237 return transform_; | |
| 238 } | |
| 239 virtual gfx::Transform GetInverseTransform() const OVERRIDE { | |
| 240 gfx::Transform invert; | |
| 241 CHECK(transform_.GetInverse(&invert)); | |
| 242 return invert; | |
| 243 } | |
| 244 virtual gfx::Rect GetRootWindowBounds( | |
| 245 const gfx::Size& host_size) const OVERRIDE { | |
| 246 return root_bounds_; | |
| 247 } | |
| 248 virtual gfx::Insets GetHostInsets() const OVERRIDE { | |
| 249 return gfx::Insets(); | |
| 250 } | |
| 251 | |
| 252 private: | |
| 253 virtual ~MirrorRootWindowTransformer() {} | |
| 254 | |
| 255 gfx::Transform transform_; | |
| 256 gfx::Rect root_bounds_; | |
| 257 | |
| 258 DISALLOW_COPY_AND_ASSIGN(MirrorRootWindowTransformer); | |
| 259 }; | |
| 118 | 260 |
| 119 } // namespace | 261 } // namespace |
| 120 | 262 |
| 121 AshRootWindowTransformer::AshRootWindowTransformer(aura::RootWindow* root, | 263 aura::RootWindowTransformer* CreateRootWindowTransformerForDisplay( |
| 122 const gfx::Display& display) | 264 aura::RootWindow* root, |
| 123 : root_window_(root) { | 265 const gfx::Display& display) { |
| 124 root_window_bounds_transform_ = | 266 return new AshRootWindowTransformer(root, display); |
| 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 } | 267 } |
| 141 | 268 |
| 142 AshRootWindowTransformer::~AshRootWindowTransformer() {} | 269 aura::RootWindowTransformer* CreateRootWindowTransformerForMirroredDisplay( |
| 143 | 270 const DisplayInfo& source_display_info, |
| 144 gfx::Transform AshRootWindowTransformer::GetTransform() const { | 271 const DisplayInfo& mirror_display_info) { |
| 145 return transform_; | 272 return new MirrorRootWindowTransformer(source_display_info, |
| 273 mirror_display_info); | |
| 146 } | 274 } |
| 147 | 275 |
| 148 gfx::Transform AshRootWindowTransformer::GetInverseTransform() const { | 276 } // namespace internal |
| 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 | 277 } // namespace ash |
| OLD | NEW |