1868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved.
2868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// found in the LICENSE file.
4868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
5868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "ash/display/root_window_transformers.h"
6868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
7868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include <cmath>
8868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
9868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "ash/display/display_info.h"
10868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "ash/display/display_manager.h"
11a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#include "ash/host/root_window_transformer.h"
12868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "ash/magnifier/magnification_controller.h"
13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "ash/shell.h"
14868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/basictypes.h"
15868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
16868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "third_party/skia/include/utils/SkMatrix44.h"
17a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/aura/window_event_dispatcher.h"
18868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "ui/aura/window_property.h"
19868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "ui/compositor/dip_util.h"
20868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "ui/gfx/display.h"
21868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "ui/gfx/insets.h"
22868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "ui/gfx/size_conversions.h"
23868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "ui/gfx/transform.h"
24868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "ui/gfx/transform.h"
25868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
26868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)DECLARE_WINDOW_PROPERTY_TYPE(gfx::Display::Rotation);
27868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
28868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)namespace ash {
29868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)namespace {
30868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
318bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#if defined(OS_WIN)
32868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)DEFINE_WINDOW_PROPERTY_KEY(gfx::Display::Rotation, kRotationPropertyKey,
33868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                           gfx::Display::ROTATE_0);
348bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#endif
35868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
36868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Round near zero value to zero.
37868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void RoundNearZero(gfx::Transform* transform) {
38868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  const float kEpsilon = 0.001f;
39868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  SkMatrix44& matrix = transform->matrix();
40868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  for (int x = 0; x < 4; ++x) {
41868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    for (int y = 0; y < 4; ++y) {
42868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      if (std::abs(SkMScalarToFloat(matrix.get(x, y))) < kEpsilon)
43868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        matrix.set(x, y, SkFloatToMScalar(0.0f));
44868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    }
45868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
46868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
47868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
48eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// TODO(oshima): Transformers should be able to adjust itself
49eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// when the device scale factor is changed, instead of
50eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// precalculating the transform using fixed value.
51eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
521e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)gfx::Transform CreateRotationTransform(aura::Window* root_window,
53868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                       const gfx::Display& display) {
54868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DisplayInfo info =
55868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      Shell::GetInstance()->display_manager()->GetDisplayInfo(display.id());
56868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
57868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // TODO(oshima): Add animation. (crossfade+rotation, or just cross-fade)
58868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#if defined(OS_WIN)
59868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Windows 8 bots refused to resize the host window, and
60868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // updating the transform results in incorrectly resizing
61868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // the root window. Don't apply the transform unless
62868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // necessary so that unit tests pass on win8 bots.
63868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (info.rotation() == root_window->GetProperty(kRotationPropertyKey))
64868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return gfx::Transform();
65868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  root_window->SetProperty(kRotationPropertyKey, info.rotation());
66868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#endif
67868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
68868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  gfx::Transform rotate;
69868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // The origin is (0, 0), so the translate width/height must be reduced by
70868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // 1 pixel.
71868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  float one_pixel = 1.0f / display.device_scale_factor();
72868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  switch (info.rotation()) {
73868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    case gfx::Display::ROTATE_0:
74868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      break;
75868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    case gfx::Display::ROTATE_90:
76868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      rotate.Translate(display.bounds().height() - one_pixel, 0);
77868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      rotate.Rotate(90);
78868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      break;
79868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    case gfx::Display::ROTATE_270:
80868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      rotate.Translate(0, display.bounds().width() - one_pixel);
81868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      rotate.Rotate(270);
82868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      break;
83868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    case gfx::Display::ROTATE_180:
84868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      rotate.Translate(display.bounds().width() - one_pixel,
85868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                       display.bounds().height() - one_pixel);
86868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      rotate.Rotate(180);
87868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      break;
88868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
89868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
90868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  RoundNearZero(&rotate);
91868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return rotate;
92868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
93868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
941e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)gfx::Transform CreateMagnifierTransform(aura::Window* root_window) {
95868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  MagnificationController* magnifier =
96868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      Shell::GetInstance()->magnification_controller();
97868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  float magnifier_scale = 1.f;
98868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  gfx::Point magnifier_offset;
99868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (magnifier && magnifier->IsEnabled()) {
100868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    magnifier_scale = magnifier->GetScale();
101868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    magnifier_offset = magnifier->GetWindowPosition();
102868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
103868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  gfx::Transform transform;
104868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (magnifier_scale != 1.f) {
105868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    transform.Scale(magnifier_scale, magnifier_scale);
106868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    transform.Translate(-magnifier_offset.x(), -magnifier_offset.y());
107868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
108868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return transform;
109868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
110868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
111868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)gfx::Transform CreateInsetsAndScaleTransform(const gfx::Insets& insets,
112868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                             float device_scale_factor,
113868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                             float ui_scale) {
114868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  gfx::Transform transform;
115868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (insets.top() != 0 || insets.left() != 0) {
116868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    float x_offset = insets.left() / device_scale_factor;
117868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    float y_offset = insets.top() / device_scale_factor;
118868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    transform.Translate(x_offset, y_offset);
119868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
120868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  float inverted_scale = 1.0f / ui_scale;
121868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  transform.Scale(inverted_scale, inverted_scale);
122868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return transform;
123868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
124868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
125868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// RootWindowTransformer for ash environment.
126a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochclass AshRootWindowTransformer : public RootWindowTransformer {
127868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) public:
1281e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  AshRootWindowTransformer(aura::Window* root,
129868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                           const gfx::Display& display)
130868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      : root_window_(root) {
131f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    DisplayInfo info = Shell::GetInstance()->display_manager()->
132f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        GetDisplayInfo(display.id());
133f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    host_insets_ = info.GetOverscanInsetsInPixel();
134f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    root_window_ui_scale_ = info.GetEffectiveUIScale();
135868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    root_window_bounds_transform_ =
136f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        CreateInsetsAndScaleTransform(host_insets_,
137f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                      display.device_scale_factor(),
138f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                      root_window_ui_scale_) *
139868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        CreateRotationTransform(root, display);
140868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    transform_ = root_window_bounds_transform_ * CreateMagnifierTransform(root);
141868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    CHECK(transform_.GetInverse(&invert_transform_));
142868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
143868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
144868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // aura::RootWindowTransformer overrides:
145868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  virtual gfx::Transform GetTransform() const OVERRIDE {
146868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return transform_;
147868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
148868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  virtual gfx::Transform GetInverseTransform() const OVERRIDE {
149868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return invert_transform_;
150868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
151868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  virtual gfx::Rect GetRootWindowBounds(
152868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      const gfx::Size& host_size) const OVERRIDE {
153868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    gfx::Rect bounds(host_size);
154868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    bounds.Inset(host_insets_);
155868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    bounds = ui::ConvertRectToDIP(root_window_->layer(), bounds);
156868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    gfx::RectF new_bounds(bounds);
157868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    root_window_bounds_transform_.TransformRect(&new_bounds);
158868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // Apply |root_window_scale_| twice as the downscaling
159868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // is already applied once in |SetTransformInternal()|.
160868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // TODO(oshima): This is a bit ugly. Consider specifying
161868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // the pseudo host resolution instead.
162868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    new_bounds.Scale(root_window_ui_scale_ * root_window_ui_scale_);
163868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // Ignore the origin because RootWindow's insets are handled by
164868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // the transform.
165868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // Floor the size because the bounds is no longer aligned to
166868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // backing pixel when |root_window_scale_| is specified
167868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // (850 height at 1.25 scale becomes 1062.5 for example.)
168868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return gfx::Rect(gfx::ToFlooredSize(new_bounds.size()));
169868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
170868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
171868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  virtual gfx::Insets GetHostInsets() const OVERRIDE {
172868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return host_insets_;
173868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
174868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
175868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) private:
176868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  virtual ~AshRootWindowTransformer() {}
177868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
1781e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  aura::Window* root_window_;
179868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  gfx::Transform transform_;
180868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
181868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // The accurate representation of the inverse of the |transform_|.
182868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // This is used to avoid computation error caused by
183868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // |gfx::Transform::GetInverse|.
184868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  gfx::Transform invert_transform_;
185868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
186868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // The transform of the root window bounds. This is used to calculate
187868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // the size of root window.
188868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  gfx::Transform root_window_bounds_transform_;
189868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
19068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // The scale of the root window. See |display_info::ui_scale_|
19168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // for more info.
192868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  float root_window_ui_scale_;
193868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
194868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  gfx::Insets host_insets_;
195868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
196868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(AshRootWindowTransformer);
197868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)};
198868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
199868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// RootWindowTransformer for mirror root window. We simply copy the
200868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// texture (bitmap) of the source display into the mirror window, so
201868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// the root window bounds is the same as the source display's
202868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// pixel size (excluding overscan insets).
203a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochclass MirrorRootWindowTransformer : public RootWindowTransformer {
204868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) public:
205868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  MirrorRootWindowTransformer(const DisplayInfo& source_display_info,
206868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                              const DisplayInfo& mirror_display_info) {
20768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    root_bounds_ = gfx::Rect(source_display_info.bounds_in_native().size());
208868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    gfx::Rect mirror_display_rect =
20968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        gfx::Rect(mirror_display_info.bounds_in_native().size());
210868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
2117d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    bool letterbox = root_bounds_.width() * mirror_display_rect.height() >
2127d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        root_bounds_.height() * mirror_display_rect.width();
2137d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    if (letterbox) {
2147d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      float mirror_scale_ratio =
2157d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)          (static_cast<float>(root_bounds_.width()) /
2167d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)           static_cast<float>(mirror_display_rect.width()));
2177d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      float inverted_scale = 1.0f / mirror_scale_ratio;
2187d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      int margin = static_cast<int>(
2197d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)          (mirror_display_rect.height() -
2207d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)           root_bounds_.height() * inverted_scale) / 2);
2217d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      insets_.Set(0, margin, 0, margin);
2227d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
2237d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      transform_.Translate(0,  margin);
2247d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      transform_.Scale(inverted_scale, inverted_scale);
2257d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    } else {
2267d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      float mirror_scale_ratio =
2277d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)          (static_cast<float>(root_bounds_.height()) /
2287d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)           static_cast<float>(mirror_display_rect.height()));
2297d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      float inverted_scale = 1.0f / mirror_scale_ratio;
2307d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      int margin = static_cast<int>(
2317d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)          (mirror_display_rect.width() -
2327d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)           root_bounds_.width() * inverted_scale) / 2);
2337d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      insets_.Set(margin, 0, margin, 0);
2347d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
2357d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      transform_.Translate(margin, 0);
2367d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      transform_.Scale(inverted_scale, inverted_scale);
2377d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    }
238868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
239868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
240868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // aura::RootWindowTransformer overrides:
241868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  virtual gfx::Transform GetTransform() const OVERRIDE {
242868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return transform_;
243868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
244868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  virtual gfx::Transform GetInverseTransform() const OVERRIDE {
245868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    gfx::Transform invert;
246868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    CHECK(transform_.GetInverse(&invert));
247868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return invert;
248868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
249868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  virtual gfx::Rect GetRootWindowBounds(
250868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      const gfx::Size& host_size) const OVERRIDE {
251868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return root_bounds_;
252868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
253868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  virtual gfx::Insets GetHostInsets() const OVERRIDE {
2547d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return insets_;
255868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
256868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
257868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) private:
258868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  virtual ~MirrorRootWindowTransformer() {}
259868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
260868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  gfx::Transform transform_;
261868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  gfx::Rect root_bounds_;
2627d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  gfx::Insets insets_;
263868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
264868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(MirrorRootWindowTransformer);
265868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)};
266868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
267868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}  // namespace
268868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
269a02191e04bc25c4935f804f2c080ae28663d096dBen MurdochRootWindowTransformer* CreateRootWindowTransformerForDisplay(
2701e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    aura::Window* root,
271868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const gfx::Display& display) {
272868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return new AshRootWindowTransformer(root, display);
273868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
274868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
275a02191e04bc25c4935f804f2c080ae28663d096dBen MurdochRootWindowTransformer* CreateRootWindowTransformerForMirroredDisplay(
276868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const DisplayInfo& source_display_info,
277868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const DisplayInfo& mirror_display_info) {
278868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return new MirrorRootWindowTransformer(source_display_info,
279868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                         mirror_display_info);
280868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
281868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
282868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}  // namespace ash
283