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 |