window_tree_host.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
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 "ui/aura/window_tree_host.h"
6
7#include "ui/aura/client/cursor_client.h"
8#include "ui/aura/env.h"
9#include "ui/aura/root_window.h"
10#include "ui/aura/root_window_transformer.h"
11#include "ui/aura/window.h"
12#include "ui/aura/window_tree_host_delegate.h"
13#include "ui/compositor/dip_util.h"
14#include "ui/compositor/layer.h"
15#include "ui/gfx/display.h"
16#include "ui/gfx/insets.h"
17#include "ui/gfx/point.h"
18#include "ui/gfx/point3_f.h"
19#include "ui/gfx/point_conversions.h"
20#include "ui/gfx/screen.h"
21#include "ui/gfx/size_conversions.h"
22
23namespace aura {
24
25float GetDeviceScaleFactorFromDisplay(Window* window) {
26  gfx::Display display = gfx::Screen::GetScreenFor(window)->
27      GetDisplayNearestWindow(window);
28  DCHECK(display.is_valid());
29  return display.device_scale_factor();
30}
31
32class SimpleRootWindowTransformer : public RootWindowTransformer {
33 public:
34  SimpleRootWindowTransformer(const Window* root_window,
35                              const gfx::Transform& transform)
36      : root_window_(root_window),
37        transform_(transform) {
38  }
39
40  // RootWindowTransformer overrides:
41  virtual gfx::Transform GetTransform() const OVERRIDE {
42    return transform_;
43  }
44
45  virtual gfx::Transform GetInverseTransform() const OVERRIDE {
46    gfx::Transform invert;
47    if (!transform_.GetInverse(&invert))
48      return transform_;
49    return invert;
50  }
51
52  virtual gfx::Rect GetRootWindowBounds(
53      const gfx::Size& host_size) const OVERRIDE {
54    gfx::Rect bounds(host_size);
55    gfx::RectF new_bounds(ui::ConvertRectToDIP(root_window_->layer(), bounds));
56    transform_.TransformRect(&new_bounds);
57    return gfx::Rect(gfx::ToFlooredSize(new_bounds.size()));
58  }
59
60  virtual gfx::Insets GetHostInsets() const OVERRIDE {
61    return gfx::Insets();
62  }
63
64 private:
65  virtual ~SimpleRootWindowTransformer() {}
66
67  const Window* root_window_;
68  const gfx::Transform transform_;
69
70  DISALLOW_COPY_AND_ASSIGN(SimpleRootWindowTransformer);
71};
72
73////////////////////////////////////////////////////////////////////////////////
74// WindowTreeHost, public:
75
76WindowTreeHost::~WindowTreeHost() {
77  DCHECK(!compositor_) << "compositor must be destroyed before root window";
78}
79
80void WindowTreeHost::InitHost() {
81  window()->Init(aura::WINDOW_LAYER_NOT_DRAWN);
82  InitCompositor();
83  UpdateRootWindowSize(GetBounds().size());
84  Env::GetInstance()->NotifyRootWindowInitialized(delegate_->AsRootWindow());
85  window()->Show();
86}
87
88void WindowTreeHost::InitCompositor() {
89  compositor_->SetScaleAndSize(GetDeviceScaleFactorFromDisplay(window()),
90                               GetBounds().size());
91  compositor_->SetRootLayer(window()->layer());
92  transformer_.reset(
93      new SimpleRootWindowTransformer(window(), gfx::Transform()));
94}
95
96aura::Window* WindowTreeHost::window() {
97  return const_cast<Window*>(const_cast<const WindowTreeHost*>(this)->window());
98}
99
100const aura::Window* WindowTreeHost::window() const {
101  return delegate_->AsRootWindow()->window();
102}
103
104void WindowTreeHost::SetRootWindowTransformer(
105    scoped_ptr<RootWindowTransformer> transformer) {
106  transformer_ = transformer.Pass();
107  SetInsets(transformer_->GetHostInsets());
108  window()->SetTransform(transformer_->GetTransform());
109  // If the layer is not animating, then we need to update the root window
110  // size immediately.
111  if (!window()->layer()->GetAnimator()->is_animating())
112    UpdateRootWindowSize(GetBounds().size());
113}
114
115gfx::Transform WindowTreeHost::GetRootTransform() const {
116  float scale = ui::GetDeviceScaleFactor(window()->layer());
117  gfx::Transform transform;
118  transform.Scale(scale, scale);
119  transform *= transformer_->GetTransform();
120  return transform;
121}
122
123void WindowTreeHost::SetTransform(const gfx::Transform& transform) {
124  scoped_ptr<RootWindowTransformer> transformer(
125      new SimpleRootWindowTransformer(window(), transform));
126  SetRootWindowTransformer(transformer.Pass());
127}
128
129gfx::Transform WindowTreeHost::GetInverseRootTransform() const {
130  float scale = ui::GetDeviceScaleFactor(window()->layer());
131  gfx::Transform transform;
132  transform.Scale(1.0f / scale, 1.0f / scale);
133  return transformer_->GetInverseTransform() * transform;
134}
135
136void WindowTreeHost::UpdateRootWindowSize(const gfx::Size& host_size) {
137  window()->SetBounds(transformer_->GetRootWindowBounds(host_size));
138}
139
140void WindowTreeHost::ConvertPointToNativeScreen(gfx::Point* point) const {
141  ConvertPointToHost(point);
142  gfx::Point location = GetLocationOnNativeScreen();
143  point->Offset(location.x(), location.y());
144}
145
146void WindowTreeHost::ConvertPointFromNativeScreen(gfx::Point* point) const {
147  gfx::Point location = GetLocationOnNativeScreen();
148  point->Offset(-location.x(), -location.y());
149  ConvertPointFromHost(point);
150}
151
152void WindowTreeHost::ConvertPointToHost(gfx::Point* point) const {
153  gfx::Point3F point_3f(*point);
154  GetRootTransform().TransformPoint(&point_3f);
155  *point = gfx::ToFlooredPoint(point_3f.AsPointF());
156}
157
158void WindowTreeHost::ConvertPointFromHost(gfx::Point* point) const {
159  gfx::Point3F point_3f(*point);
160  GetInverseRootTransform().TransformPoint(&point_3f);
161  *point = gfx::ToFlooredPoint(point_3f.AsPointF());
162}
163
164void WindowTreeHost::SetCursor(gfx::NativeCursor cursor) {
165  last_cursor_ = cursor;
166  // A lot of code seems to depend on NULL cursors actually showing an arrow,
167  // so just pass everything along to the host.
168  SetCursorNative(cursor);
169}
170
171void WindowTreeHost::OnCursorVisibilityChanged(bool show) {
172  // Clear any existing mouse hover effects when the cursor becomes invisible.
173  // Note we do not need to dispatch a mouse enter when the cursor becomes
174  // visible because that can only happen in response to a mouse event, which
175  // will trigger its own mouse enter.
176  if (!show) {
177    delegate_->AsRootWindow()->DispatchMouseExitAtPoint(
178        delegate_->AsRootWindow()->GetLastMouseLocationInRoot());
179  }
180
181  OnCursorVisibilityChangedNative(show);
182}
183
184void WindowTreeHost::MoveCursorTo(const gfx::Point& location_in_dip) {
185  gfx::Point host_location(location_in_dip);
186  ConvertPointToHost(&host_location);
187  MoveCursorToInternal(location_in_dip, host_location);
188}
189
190void WindowTreeHost::MoveCursorToHostLocation(const gfx::Point& host_location) {
191  gfx::Point root_location(host_location);
192  ConvertPointFromHost(&root_location);
193  MoveCursorToInternal(root_location, host_location);
194}
195
196////////////////////////////////////////////////////////////////////////////////
197// WindowTreeHost, protected:
198
199WindowTreeHost::WindowTreeHost()
200    : delegate_(NULL),
201      last_cursor_(ui::kCursorNull) {
202}
203
204void WindowTreeHost::DestroyCompositor() {
205  DCHECK(GetAcceleratedWidget());
206  compositor_.reset();
207}
208
209void WindowTreeHost::CreateCompositor(
210    gfx::AcceleratedWidget accelerated_widget) {
211  compositor_.reset(new ui::Compositor(GetAcceleratedWidget()));
212  DCHECK(compositor_.get());
213}
214
215void WindowTreeHost::NotifyHostResized(const gfx::Size& new_size) {
216  // The compositor should have the same size as the native root window host.
217  // Get the latest scale from display because it might have been changed.
218  compositor_->SetScaleAndSize(GetDeviceScaleFactorFromDisplay(window()),
219                               new_size);
220
221  gfx::Size layer_size = GetBounds().size();
222  // The layer, and the observers should be notified of the
223  // transformed size of the root window.
224  UpdateRootWindowSize(layer_size);
225  delegate_->OnHostResized(layer_size);
226}
227
228void WindowTreeHost::MoveCursorToInternal(const gfx::Point& root_location,
229                                          const gfx::Point& host_location) {
230  MoveCursorToNative(host_location);
231  client::CursorClient* cursor_client = client::GetCursorClient(window());
232  if (cursor_client) {
233    const gfx::Display& display =
234        gfx::Screen::GetScreenFor(window())->GetDisplayNearestWindow(window());
235    cursor_client->SetDisplay(display);
236  }
237  delegate_->OnCursorMovedToRootLocation(root_location);
238}
239
240#if defined(OS_ANDROID)
241// static
242WindowTreeHost* WindowTreeHost::Create(const gfx::Rect& bounds) {
243  // This is only hit for tests and ash, right now these aren't an issue so
244  // adding the CHECK.
245  // TODO(sky): decide if we want a factory.
246  CHECK(false);
247  return NULL;
248}
249#endif
250
251}  // namespace aura
252