Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / ash / display / root_window_transformers.cc
blobcba66883ac78b0a30493acc486fca56871d6e21b
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/display/display_info.h"
10 #include "ash/display/display_manager.h"
11 #include "ash/host/root_window_transformer.h"
12 #include "ash/magnifier/magnification_controller.h"
13 #include "ash/shell.h"
14 #include "base/basictypes.h"
15 #include "base/memory/scoped_ptr.h"
16 #include "third_party/skia/include/utils/SkMatrix44.h"
17 #include "ui/aura/window_event_dispatcher.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"
26 DECLARE_WINDOW_PROPERTY_TYPE(gfx::Display::Rotation);
28 namespace ash {
29 namespace {
31 #if defined(OS_WIN)
32 DEFINE_WINDOW_PROPERTY_KEY(gfx::Display::Rotation, kRotationPropertyKey,
33 gfx::Display::ROTATE_0);
34 #endif
36 // Round near zero value to zero.
37 void RoundNearZero(gfx::Transform* transform) {
38 const float kEpsilon = 0.001f;
39 SkMatrix44& matrix = transform->matrix();
40 for (int x = 0; x < 4; ++x) {
41 for (int y = 0; y < 4; ++y) {
42 if (std::abs(SkMScalarToFloat(matrix.get(x, y))) < kEpsilon)
43 matrix.set(x, y, SkFloatToMScalar(0.0f));
48 // TODO(oshima): Transformers should be able to adjust itself
49 // when the device scale factor is changed, instead of
50 // precalculating the transform using fixed value.
52 gfx::Transform CreateRotationTransform(aura::Window* root_window,
53 const gfx::Display& display) {
54 DisplayInfo info =
55 Shell::GetInstance()->display_manager()->GetDisplayInfo(display.id());
57 // TODO(oshima): Add animation. (crossfade+rotation, or just cross-fade)
58 #if defined(OS_WIN)
59 // Windows 8 bots refused to resize the host window, and
60 // updating the transform results in incorrectly resizing
61 // the root window. Don't apply the transform unless
62 // necessary so that unit tests pass on win8 bots.
63 if (info.rotation() == root_window->GetProperty(kRotationPropertyKey))
64 return gfx::Transform();
65 root_window->SetProperty(kRotationPropertyKey, info.rotation());
66 #endif
68 gfx::Transform rotate;
69 // The origin is (0, 0), so the translate width/height must be reduced by
70 // 1 pixel.
71 float one_pixel = 1.0f / display.device_scale_factor();
72 switch (info.rotation()) {
73 case gfx::Display::ROTATE_0:
74 break;
75 case gfx::Display::ROTATE_90:
76 rotate.Translate(display.bounds().height() - one_pixel, 0);
77 rotate.Rotate(90);
78 break;
79 case gfx::Display::ROTATE_270:
80 rotate.Translate(0, display.bounds().width() - one_pixel);
81 rotate.Rotate(270);
82 break;
83 case gfx::Display::ROTATE_180:
84 rotate.Translate(display.bounds().width() - one_pixel,
85 display.bounds().height() - one_pixel);
86 rotate.Rotate(180);
87 break;
90 RoundNearZero(&rotate);
91 return rotate;
94 gfx::Transform CreateMagnifierTransform(aura::Window* root_window) {
95 MagnificationController* magnifier =
96 Shell::GetInstance()->magnification_controller();
97 float magnifier_scale = 1.f;
98 gfx::Point magnifier_offset;
99 if (magnifier && magnifier->IsEnabled()) {
100 magnifier_scale = magnifier->GetScale();
101 magnifier_offset = magnifier->GetWindowPosition();
103 gfx::Transform transform;
104 if (magnifier_scale != 1.f) {
105 transform.Scale(magnifier_scale, magnifier_scale);
106 transform.Translate(-magnifier_offset.x(), -magnifier_offset.y());
108 return transform;
111 gfx::Transform CreateInsetsAndScaleTransform(const gfx::Insets& insets,
112 float device_scale_factor,
113 float ui_scale) {
114 gfx::Transform transform;
115 if (insets.top() != 0 || insets.left() != 0) {
116 float x_offset = insets.left() / device_scale_factor;
117 float y_offset = insets.top() / device_scale_factor;
118 transform.Translate(x_offset, y_offset);
120 float inverted_scale = 1.0f / ui_scale;
121 transform.Scale(inverted_scale, inverted_scale);
122 return transform;
125 // RootWindowTransformer for ash environment.
126 class AshRootWindowTransformer : public RootWindowTransformer {
127 public:
128 AshRootWindowTransformer(aura::Window* root,
129 const gfx::Display& display)
130 : root_window_(root) {
131 DisplayInfo info = Shell::GetInstance()->display_manager()->
132 GetDisplayInfo(display.id());
133 host_insets_ = info.GetOverscanInsetsInPixel();
134 root_window_ui_scale_ = info.GetEffectiveUIScale();
135 root_window_bounds_transform_ =
136 CreateInsetsAndScaleTransform(host_insets_,
137 display.device_scale_factor(),
138 root_window_ui_scale_) *
139 CreateRotationTransform(root, display);
140 transform_ = root_window_bounds_transform_ * CreateMagnifierTransform(root);
141 CHECK(transform_.GetInverse(&invert_transform_));
144 // aura::RootWindowTransformer overrides:
145 virtual gfx::Transform GetTransform() const OVERRIDE {
146 return transform_;
148 virtual gfx::Transform GetInverseTransform() const OVERRIDE {
149 return invert_transform_;
151 virtual gfx::Rect GetRootWindowBounds(
152 const gfx::Size& host_size) const OVERRIDE {
153 gfx::Rect bounds(host_size);
154 bounds.Inset(host_insets_);
155 bounds = ui::ConvertRectToDIP(root_window_->layer(), bounds);
156 gfx::RectF new_bounds(bounds);
157 root_window_bounds_transform_.TransformRect(&new_bounds);
158 // Apply |root_window_scale_| twice as the downscaling
159 // is already applied once in |SetTransformInternal()|.
160 // TODO(oshima): This is a bit ugly. Consider specifying
161 // the pseudo host resolution instead.
162 new_bounds.Scale(root_window_ui_scale_ * root_window_ui_scale_);
163 // Ignore the origin because RootWindow's insets are handled by
164 // the transform.
165 // Floor the size because the bounds is no longer aligned to
166 // backing pixel when |root_window_scale_| is specified
167 // (850 height at 1.25 scale becomes 1062.5 for example.)
168 return gfx::Rect(gfx::ToFlooredSize(new_bounds.size()));
171 virtual gfx::Insets GetHostInsets() const OVERRIDE {
172 return host_insets_;
175 private:
176 virtual ~AshRootWindowTransformer() {}
178 aura::Window* root_window_;
179 gfx::Transform transform_;
181 // The accurate representation of the inverse of the |transform_|.
182 // This is used to avoid computation error caused by
183 // |gfx::Transform::GetInverse|.
184 gfx::Transform invert_transform_;
186 // The transform of the root window bounds. This is used to calculate
187 // the size of root window.
188 gfx::Transform root_window_bounds_transform_;
190 // The scale of the root window. See |display_info::ui_scale_|
191 // for more info.
192 float root_window_ui_scale_;
194 gfx::Insets host_insets_;
196 DISALLOW_COPY_AND_ASSIGN(AshRootWindowTransformer);
199 // RootWindowTransformer for mirror root window. We simply copy the
200 // texture (bitmap) of the source display into the mirror window, so
201 // the root window bounds is the same as the source display's
202 // pixel size (excluding overscan insets).
203 class MirrorRootWindowTransformer : public RootWindowTransformer {
204 public:
205 MirrorRootWindowTransformer(const DisplayInfo& source_display_info,
206 const DisplayInfo& mirror_display_info) {
207 root_bounds_ = gfx::Rect(source_display_info.bounds_in_native().size());
208 gfx::Rect mirror_display_rect =
209 gfx::Rect(mirror_display_info.bounds_in_native().size());
211 bool letterbox = root_bounds_.width() * mirror_display_rect.height() >
212 root_bounds_.height() * mirror_display_rect.width();
213 if (letterbox) {
214 float mirror_scale_ratio =
215 (static_cast<float>(root_bounds_.width()) /
216 static_cast<float>(mirror_display_rect.width()));
217 float inverted_scale = 1.0f / mirror_scale_ratio;
218 int margin = static_cast<int>(
219 (mirror_display_rect.height() -
220 root_bounds_.height() * inverted_scale) / 2);
221 insets_.Set(0, margin, 0, margin);
223 transform_.Translate(0, margin);
224 transform_.Scale(inverted_scale, inverted_scale);
225 } else {
226 float mirror_scale_ratio =
227 (static_cast<float>(root_bounds_.height()) /
228 static_cast<float>(mirror_display_rect.height()));
229 float inverted_scale = 1.0f / mirror_scale_ratio;
230 int margin = static_cast<int>(
231 (mirror_display_rect.width() -
232 root_bounds_.width() * inverted_scale) / 2);
233 insets_.Set(margin, 0, margin, 0);
235 transform_.Translate(margin, 0);
236 transform_.Scale(inverted_scale, inverted_scale);
240 // aura::RootWindowTransformer overrides:
241 virtual gfx::Transform GetTransform() const OVERRIDE {
242 return transform_;
244 virtual gfx::Transform GetInverseTransform() const OVERRIDE {
245 gfx::Transform invert;
246 CHECK(transform_.GetInverse(&invert));
247 return invert;
249 virtual gfx::Rect GetRootWindowBounds(
250 const gfx::Size& host_size) const OVERRIDE {
251 return root_bounds_;
253 virtual gfx::Insets GetHostInsets() const OVERRIDE {
254 return insets_;
257 private:
258 virtual ~MirrorRootWindowTransformer() {}
260 gfx::Transform transform_;
261 gfx::Rect root_bounds_;
262 gfx::Insets insets_;
264 DISALLOW_COPY_AND_ASSIGN(MirrorRootWindowTransformer);
267 } // namespace
269 RootWindowTransformer* CreateRootWindowTransformerForDisplay(
270 aura::Window* root,
271 const gfx::Display& display) {
272 return new AshRootWindowTransformer(root, display);
275 RootWindowTransformer* CreateRootWindowTransformerForMirroredDisplay(
276 const DisplayInfo& source_display_info,
277 const DisplayInfo& mirror_display_info) {
278 return new MirrorRootWindowTransformer(source_display_info,
279 mirror_display_info);
282 } // namespace ash