Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / ash / display / root_window_transformers.cc
blobe739cd93457344e68f2205796977569c63bd303a
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.
5 #include "ash/display/root_window_transformers.h"
7 #include <cmath>
9 #include "ash/ash_switches.h"
10 #include "ash/display/display_info.h"
11 #include "ash/display/display_manager.h"
12 #include "ash/host/root_window_transformer.h"
13 #include "ash/magnifier/magnification_controller.h"
14 #include "ash/shell.h"
15 #include "base/basictypes.h"
16 #include "base/command_line.h"
17 #include "base/memory/scoped_ptr.h"
18 #include "third_party/skia/include/utils/SkMatrix44.h"
19 #include "ui/aura/window_event_dispatcher.h"
20 #include "ui/aura/window_property.h"
21 #include "ui/compositor/dip_util.h"
22 #include "ui/gfx/display.h"
23 #include "ui/gfx/geometry/insets.h"
24 #include "ui/gfx/geometry/size_conversions.h"
25 #include "ui/gfx/transform.h"
26 #include "ui/gfx/transform.h"
28 DECLARE_WINDOW_PROPERTY_TYPE(gfx::Display::Rotation);
30 namespace ash {
31 namespace {
33 #if defined(OS_WIN)
34 DEFINE_WINDOW_PROPERTY_KEY(gfx::Display::Rotation, kRotationPropertyKey,
35 gfx::Display::ROTATE_0);
36 #endif
38 // Round near zero value to zero.
39 void RoundNearZero(gfx::Transform* transform) {
40 const float kEpsilon = 0.001f;
41 SkMatrix44& matrix = transform->matrix();
42 for (int x = 0; x < 4; ++x) {
43 for (int y = 0; y < 4; ++y) {
44 if (std::abs(SkMScalarToFloat(matrix.get(x, y))) < kEpsilon)
45 matrix.set(x, y, SkFloatToMScalar(0.0f));
50 // TODO(oshima): Transformers should be able to adjust itself
51 // when the device scale factor is changed, instead of
52 // precalculating the transform using fixed value.
54 gfx::Transform CreateRotationTransform(aura::Window* root_window,
55 const gfx::Display& display) {
56 DisplayInfo info =
57 Shell::GetInstance()->display_manager()->GetDisplayInfo(display.id());
59 // TODO(oshima): Add animation. (crossfade+rotation, or just cross-fade)
60 #if defined(OS_WIN)
61 // Windows 8 bots refused to resize the host window, and
62 // updating the transform results in incorrectly resizing
63 // the root window. Don't apply the transform unless
64 // necessary so that unit tests pass on win8 bots.
65 if (info.GetActiveRotation() ==
66 root_window->GetProperty(kRotationPropertyKey)) {
67 return gfx::Transform();
69 root_window->SetProperty(kRotationPropertyKey, info.GetActiveRotation());
70 #endif
72 gfx::Transform rotate;
73 // The origin is (0, 0), so the translate width/height must be reduced by
74 // 1 pixel.
75 float one_pixel = 1.0f / display.device_scale_factor();
76 switch (info.GetActiveRotation()) {
77 case gfx::Display::ROTATE_0:
78 break;
79 case gfx::Display::ROTATE_90:
80 rotate.Translate(display.bounds().height() - one_pixel, 0);
81 rotate.Rotate(90);
82 break;
83 case gfx::Display::ROTATE_270:
84 rotate.Translate(0, display.bounds().width() - one_pixel);
85 rotate.Rotate(270);
86 break;
87 case gfx::Display::ROTATE_180:
88 rotate.Translate(display.bounds().width() - one_pixel,
89 display.bounds().height() - one_pixel);
90 rotate.Rotate(180);
91 break;
94 RoundNearZero(&rotate);
95 return rotate;
98 gfx::Transform CreateMagnifierTransform(aura::Window* root_window) {
99 MagnificationController* magnifier =
100 Shell::GetInstance()->magnification_controller();
101 float magnifier_scale = 1.f;
102 gfx::Point magnifier_offset;
103 if (magnifier && magnifier->IsEnabled()) {
104 magnifier_scale = magnifier->GetScale();
105 magnifier_offset = magnifier->GetWindowPosition();
107 gfx::Transform transform;
108 if (magnifier_scale != 1.f) {
109 transform.Scale(magnifier_scale, magnifier_scale);
110 transform.Translate(-magnifier_offset.x(), -magnifier_offset.y());
112 return transform;
115 gfx::Transform CreateInsetsAndScaleTransform(const gfx::Insets& insets,
116 float device_scale_factor,
117 float ui_scale) {
118 gfx::Transform transform;
119 if (insets.top() != 0 || insets.left() != 0) {
120 float x_offset = insets.left() / device_scale_factor;
121 float y_offset = insets.top() / device_scale_factor;
122 transform.Translate(x_offset, y_offset);
124 float inverted_scale = 1.0f / ui_scale;
125 transform.Scale(inverted_scale, inverted_scale);
126 return transform;
129 gfx::Transform CreateMirrorTransform(const gfx::Display& display) {
130 gfx::Transform transform;
131 transform.matrix().set3x3(-1, 0, 0,
132 0, 1, 0,
133 0, 0, 1);
134 transform.Translate(-display.size().width(), 0);
135 return transform;
138 // RootWindowTransformer for ash environment.
139 class AshRootWindowTransformer : public RootWindowTransformer {
140 public:
141 AshRootWindowTransformer(aura::Window* root,
142 const gfx::Display& display)
143 : root_window_(root) {
144 DisplayManager* display_manager = Shell::GetInstance()->display_manager();
145 DisplayInfo info = display_manager->GetDisplayInfo(display.id());
146 host_insets_ = info.GetOverscanInsetsInPixel();
147 root_window_ui_scale_ = info.GetEffectiveUIScale();
148 // In unified mode, the scaling happen when mirroring, so don't apply
149 // scaling to the root window.
150 const float apply_ui_scale =
151 display_manager->IsInUnifiedMode() ? 1.0f : root_window_ui_scale_;
153 root_window_bounds_transform_ =
154 CreateInsetsAndScaleTransform(
155 host_insets_, display.device_scale_factor(), apply_ui_scale) *
156 CreateRotationTransform(root, display);
157 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
158 switches::kAshEnableMirroredScreen)) {
159 // Apply the tranform that flips the screen image horizontally so that
160 // the screen looks normal when reflected on a mirror.
161 root_window_bounds_transform_ =
162 root_window_bounds_transform_ * CreateMirrorTransform(display);
164 transform_ = root_window_bounds_transform_ * CreateMagnifierTransform(root);
166 CHECK(transform_.GetInverse(&invert_transform_));
169 // aura::RootWindowTransformer overrides:
170 gfx::Transform GetTransform() const override { return transform_; }
171 gfx::Transform GetInverseTransform() const override {
172 return invert_transform_;
174 gfx::Rect GetRootWindowBounds(const gfx::Size& host_size) const override {
175 gfx::Rect bounds(host_size);
176 bounds.Inset(host_insets_);
177 bounds = ui::ConvertRectToDIP(root_window_->layer(), bounds);
178 gfx::RectF new_bounds(bounds);
179 root_window_bounds_transform_.TransformRect(&new_bounds);
180 if (Shell::GetInstance()->display_manager()->IsInUnifiedMode()) {
181 new_bounds.Scale(root_window_ui_scale_);
182 } else {
183 // Apply |root_window_scale_| twice as the downscaling
184 // is already applied once in |SetTransformInternal()|.
185 // TODO(oshima): This is a bit ugly. Consider specifying
186 // the pseudo host resolution instead.
187 new_bounds.Scale(root_window_ui_scale_ * root_window_ui_scale_);
189 // Ignore the origin because RootWindow's insets are handled by
190 // the transform.
191 // Floor the size because the bounds is no longer aligned to
192 // backing pixel when |root_window_scale_| is specified
193 // (850 height at 1.25 scale becomes 1062.5 for example.)
194 return gfx::Rect(gfx::ToFlooredSize(new_bounds.size()));
197 gfx::Insets GetHostInsets() const override { return host_insets_; }
199 private:
200 ~AshRootWindowTransformer() override {}
202 aura::Window* root_window_;
203 gfx::Transform transform_;
205 // The accurate representation of the inverse of the |transform_|.
206 // This is used to avoid computation error caused by
207 // |gfx::Transform::GetInverse|.
208 gfx::Transform invert_transform_;
210 // The transform of the root window bounds. This is used to calculate
211 // the size of root window.
212 gfx::Transform root_window_bounds_transform_;
214 // The scale of the root window. See |display_info::ui_scale_|
215 // for more info.
216 float root_window_ui_scale_;
218 gfx::Insets host_insets_;
220 DISALLOW_COPY_AND_ASSIGN(AshRootWindowTransformer);
223 // RootWindowTransformer for mirror root window. We simply copy the
224 // texture (bitmap) of the source display into the mirror window, so
225 // the root window bounds is the same as the source display's
226 // pixel size (excluding overscan insets).
227 class MirrorRootWindowTransformer : public RootWindowTransformer {
228 public:
229 MirrorRootWindowTransformer(const DisplayInfo& source_display_info,
230 const DisplayInfo& mirror_display_info) {
231 root_bounds_ = gfx::Rect(source_display_info.bounds_in_native().size());
232 gfx::Rect mirror_display_rect =
233 gfx::Rect(mirror_display_info.bounds_in_native().size());
235 bool letterbox = root_bounds_.width() * mirror_display_rect.height() >
236 root_bounds_.height() * mirror_display_rect.width();
237 if (letterbox) {
238 float mirror_scale_ratio =
239 (static_cast<float>(root_bounds_.width()) /
240 static_cast<float>(mirror_display_rect.width()));
241 float inverted_scale = 1.0f / mirror_scale_ratio;
242 int margin = static_cast<int>(
243 (mirror_display_rect.height() -
244 root_bounds_.height() * inverted_scale) / 2);
245 insets_.Set(0, margin, 0, margin);
247 transform_.Translate(0, margin);
248 transform_.Scale(inverted_scale, inverted_scale);
249 } else {
250 float mirror_scale_ratio =
251 (static_cast<float>(root_bounds_.height()) /
252 static_cast<float>(mirror_display_rect.height()));
253 float inverted_scale = 1.0f / mirror_scale_ratio;
254 int margin = static_cast<int>(
255 (mirror_display_rect.width() -
256 root_bounds_.width() * inverted_scale) / 2);
257 insets_.Set(margin, 0, margin, 0);
259 transform_.Translate(margin, 0);
260 transform_.Scale(inverted_scale, inverted_scale);
264 // aura::RootWindowTransformer overrides:
265 gfx::Transform GetTransform() const override { return transform_; }
266 gfx::Transform GetInverseTransform() const override {
267 gfx::Transform invert;
268 CHECK(transform_.GetInverse(&invert));
269 return invert;
271 gfx::Rect GetRootWindowBounds(const gfx::Size& host_size) const override {
272 return root_bounds_;
274 gfx::Insets GetHostInsets() const override { return insets_; }
276 private:
277 ~MirrorRootWindowTransformer() override {}
279 gfx::Transform transform_;
280 gfx::Rect root_bounds_;
281 gfx::Insets insets_;
283 DISALLOW_COPY_AND_ASSIGN(MirrorRootWindowTransformer);
286 class PartialBoundsRootWindowTransformer : public RootWindowTransformer {
287 public:
288 PartialBoundsRootWindowTransformer(const gfx::Rect& screen_bounds,
289 const gfx::Display& display) {
290 DisplayInfo display_info =
291 Shell::GetInstance()->display_manager()->GetDisplayInfo(display.id());
292 root_bounds_ = gfx::Rect(display_info.bounds_in_native().size());
293 transform_.Translate(-SkIntToMScalar(display.bounds().x()),
294 -SkIntToMScalar(display.bounds().y()));
295 float scale =
296 root_bounds_.height() / static_cast<float>(screen_bounds.height());
297 transform_.Scale(scale, scale);
300 // RootWindowTransformer:
301 gfx::Transform GetTransform() const override { return transform_; }
302 gfx::Transform GetInverseTransform() const override {
303 gfx::Transform invert;
304 CHECK(transform_.GetInverse(&invert));
305 return invert;
307 gfx::Rect GetRootWindowBounds(const gfx::Size& host_size) const override {
308 return root_bounds_;
310 gfx::Insets GetHostInsets() const override { return gfx::Insets(); }
312 private:
313 gfx::Transform transform_;
314 gfx::Rect root_bounds_;
316 DISALLOW_COPY_AND_ASSIGN(PartialBoundsRootWindowTransformer);
319 } // namespace
321 RootWindowTransformer* CreateRootWindowTransformerForDisplay(
322 aura::Window* root,
323 const gfx::Display& display) {
324 return new AshRootWindowTransformer(root, display);
327 RootWindowTransformer* CreateRootWindowTransformerForMirroredDisplay(
328 const DisplayInfo& source_display_info,
329 const DisplayInfo& mirror_display_info) {
330 return new MirrorRootWindowTransformer(source_display_info,
331 mirror_display_info);
334 RootWindowTransformer* CreateRootWindowTransformerForUnifiedDesktop(
335 const gfx::Rect& screen_bounds,
336 const gfx::Display& display) {
337 return new PartialBoundsRootWindowTransformer(screen_bounds, display);
340 } // namespace ash