Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / ash / display / root_window_transformers.cc
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/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"
25
26 DECLARE_WINDOW_PROPERTY_TYPE(gfx::Display::Rotation);
27
28 namespace ash {
29 namespace {
30
31 #if defined(OS_WIN)
32 DEFINE_WINDOW_PROPERTY_KEY(gfx::Display::Rotation, kRotationPropertyKey,
33                            gfx::Display::ROTATE_0);
34 #endif
35
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));
44     }
45   }
46 }
47
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.
51
52 gfx::Transform CreateRotationTransform(aura::Window* root_window,
53                                        const gfx::Display& display) {
54   DisplayInfo info =
55       Shell::GetInstance()->display_manager()->GetDisplayInfo(display.id());
56
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
67
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;
88   }
89
90   RoundNearZero(&rotate);
91   return rotate;
92 }
93
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();
102   }
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());
107   }
108   return transform;
109 }
110
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);
119   }
120   float inverted_scale = 1.0f / ui_scale;
121   transform.Scale(inverted_scale, inverted_scale);
122   return transform;
123 }
124
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_));
142   }
143
144   // aura::RootWindowTransformer overrides:
145   gfx::Transform GetTransform() const override { return transform_; }
146   gfx::Transform GetInverseTransform() const override {
147     return invert_transform_;
148   }
149   gfx::Rect GetRootWindowBounds(const gfx::Size& host_size) const override {
150     gfx::Rect bounds(host_size);
151     bounds.Inset(host_insets_);
152     bounds = ui::ConvertRectToDIP(root_window_->layer(), bounds);
153     gfx::RectF new_bounds(bounds);
154     root_window_bounds_transform_.TransformRect(&new_bounds);
155     // Apply |root_window_scale_| twice as the downscaling
156     // is already applied once in |SetTransformInternal()|.
157     // TODO(oshima): This is a bit ugly. Consider specifying
158     // the pseudo host resolution instead.
159     new_bounds.Scale(root_window_ui_scale_ * root_window_ui_scale_);
160     // Ignore the origin because RootWindow's insets are handled by
161     // the transform.
162     // Floor the size because the bounds is no longer aligned to
163     // backing pixel when |root_window_scale_| is specified
164     // (850 height at 1.25 scale becomes 1062.5 for example.)
165     return gfx::Rect(gfx::ToFlooredSize(new_bounds.size()));
166   }
167
168   gfx::Insets GetHostInsets() const override { return host_insets_; }
169
170  private:
171   ~AshRootWindowTransformer() override {}
172
173   aura::Window* root_window_;
174   gfx::Transform transform_;
175
176   // The accurate representation of the inverse of the |transform_|.
177   // This is used to avoid computation error caused by
178   // |gfx::Transform::GetInverse|.
179   gfx::Transform invert_transform_;
180
181   // The transform of the root window bounds. This is used to calculate
182   // the size of root window.
183   gfx::Transform root_window_bounds_transform_;
184
185   // The scale of the root window. See |display_info::ui_scale_|
186   // for more info.
187   float root_window_ui_scale_;
188
189   gfx::Insets host_insets_;
190
191   DISALLOW_COPY_AND_ASSIGN(AshRootWindowTransformer);
192 };
193
194 // RootWindowTransformer for mirror root window. We simply copy the
195 // texture (bitmap) of the source display into the mirror window, so
196 // the root window bounds is the same as the source display's
197 // pixel size (excluding overscan insets).
198 class MirrorRootWindowTransformer : public RootWindowTransformer {
199  public:
200   MirrorRootWindowTransformer(const DisplayInfo& source_display_info,
201                               const DisplayInfo& mirror_display_info) {
202     root_bounds_ = gfx::Rect(source_display_info.bounds_in_native().size());
203     gfx::Rect mirror_display_rect =
204         gfx::Rect(mirror_display_info.bounds_in_native().size());
205
206     bool letterbox = root_bounds_.width() * mirror_display_rect.height() >
207         root_bounds_.height() * mirror_display_rect.width();
208     if (letterbox) {
209       float mirror_scale_ratio =
210           (static_cast<float>(root_bounds_.width()) /
211            static_cast<float>(mirror_display_rect.width()));
212       float inverted_scale = 1.0f / mirror_scale_ratio;
213       int margin = static_cast<int>(
214           (mirror_display_rect.height() -
215            root_bounds_.height() * inverted_scale) / 2);
216       insets_.Set(0, margin, 0, margin);
217
218       transform_.Translate(0,  margin);
219       transform_.Scale(inverted_scale, inverted_scale);
220     } else {
221       float mirror_scale_ratio =
222           (static_cast<float>(root_bounds_.height()) /
223            static_cast<float>(mirror_display_rect.height()));
224       float inverted_scale = 1.0f / mirror_scale_ratio;
225       int margin = static_cast<int>(
226           (mirror_display_rect.width() -
227            root_bounds_.width() * inverted_scale) / 2);
228       insets_.Set(margin, 0, margin, 0);
229
230       transform_.Translate(margin, 0);
231       transform_.Scale(inverted_scale, inverted_scale);
232     }
233   }
234
235   // aura::RootWindowTransformer overrides:
236   gfx::Transform GetTransform() const override { return transform_; }
237   gfx::Transform GetInverseTransform() const override {
238     gfx::Transform invert;
239     CHECK(transform_.GetInverse(&invert));
240     return invert;
241   }
242   gfx::Rect GetRootWindowBounds(const gfx::Size& host_size) const override {
243     return root_bounds_;
244   }
245   gfx::Insets GetHostInsets() const override { return insets_; }
246
247  private:
248   ~MirrorRootWindowTransformer() override {}
249
250   gfx::Transform transform_;
251   gfx::Rect root_bounds_;
252   gfx::Insets insets_;
253
254   DISALLOW_COPY_AND_ASSIGN(MirrorRootWindowTransformer);
255 };
256
257 }  // namespace
258
259 RootWindowTransformer* CreateRootWindowTransformerForDisplay(
260     aura::Window* root,
261     const gfx::Display& display) {
262   return new AshRootWindowTransformer(root, display);
263 }
264
265 RootWindowTransformer* CreateRootWindowTransformerForMirroredDisplay(
266     const DisplayInfo& source_display_info,
267     const DisplayInfo& mirror_display_info) {
268   return new MirrorRootWindowTransformer(source_display_info,
269                                          mirror_display_info);
270 }
271
272 }  // namespace ash