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 "base/debug/trace_event.h"
8#include "base/thread_task_runner_handle.h"
9#include "ui/aura/client/capture_client.h"
10#include "ui/aura/client/cursor_client.h"
11#include "ui/aura/env.h"
12#include "ui/aura/window.h"
13#include "ui/aura/window_event_dispatcher.h"
14#include "ui/aura/window_targeter.h"
15#include "ui/aura/window_tree_host_observer.h"
16#include "ui/base/view_prop.h"
17#include "ui/compositor/dip_util.h"
18#include "ui/compositor/layer.h"
19#include "ui/gfx/display.h"
20#include "ui/gfx/insets.h"
21#include "ui/gfx/point.h"
22#include "ui/gfx/point3_f.h"
23#include "ui/gfx/point_conversions.h"
24#include "ui/gfx/screen.h"
25#include "ui/gfx/size_conversions.h"
26
27namespace aura {
28
29const char kWindowTreeHostForAcceleratedWidget[] =
30    "__AURA_WINDOW_TREE_HOST_ACCELERATED_WIDGET__";
31
32float GetDeviceScaleFactorFromDisplay(Window* window) {
33  gfx::Display display = gfx::Screen::GetScreenFor(window)->
34      GetDisplayNearestWindow(window);
35  DCHECK(display.is_valid());
36  return display.device_scale_factor();
37}
38
39////////////////////////////////////////////////////////////////////////////////
40// WindowTreeHost, public:
41
42WindowTreeHost::~WindowTreeHost() {
43  DCHECK(!compositor_) << "compositor must be destroyed before root window";
44}
45
46#if defined(OS_ANDROID)
47// static
48WindowTreeHost* WindowTreeHost::Create(const gfx::Rect& bounds) {
49  // This is only hit for tests and ash, right now these aren't an issue so
50  // adding the CHECK.
51  // TODO(sky): decide if we want a factory.
52  CHECK(false);
53  return NULL;
54}
55#endif
56
57// static
58WindowTreeHost* WindowTreeHost::GetForAcceleratedWidget(
59    gfx::AcceleratedWidget widget) {
60  return reinterpret_cast<WindowTreeHost*>(
61      ui::ViewProp::GetValue(widget, kWindowTreeHostForAcceleratedWidget));
62}
63
64void WindowTreeHost::InitHost() {
65  InitCompositor();
66  UpdateRootWindowSize(GetBounds().size());
67  Env::GetInstance()->NotifyHostInitialized(this);
68  window()->Show();
69}
70
71void WindowTreeHost::InitCompositor() {
72  compositor_->SetScaleAndSize(GetDeviceScaleFactorFromDisplay(window()),
73                               GetBounds().size());
74  compositor_->SetRootLayer(window()->layer());
75}
76
77void WindowTreeHost::AddObserver(WindowTreeHostObserver* observer) {
78  observers_.AddObserver(observer);
79}
80
81void WindowTreeHost::RemoveObserver(WindowTreeHostObserver* observer) {
82  observers_.RemoveObserver(observer);
83}
84
85ui::EventProcessor* WindowTreeHost::event_processor() {
86  return dispatcher();
87}
88
89gfx::Transform WindowTreeHost::GetRootTransform() const {
90  float scale = ui::GetDeviceScaleFactor(window()->layer());
91  gfx::Transform transform;
92  transform.Scale(scale, scale);
93  transform *= window()->layer()->transform();
94  return transform;
95}
96
97void WindowTreeHost::SetRootTransform(const gfx::Transform& transform) {
98  window()->SetTransform(transform);
99  UpdateRootWindowSize(GetBounds().size());
100}
101
102gfx::Transform WindowTreeHost::GetInverseRootTransform() const {
103  gfx::Transform invert;
104  gfx::Transform transform = GetRootTransform();
105  if (!transform.GetInverse(&invert))
106    return transform;
107  return invert;
108}
109
110void WindowTreeHost::UpdateRootWindowSize(const gfx::Size& host_size) {
111  gfx::Rect bounds(host_size);
112  gfx::RectF new_bounds(ui::ConvertRectToDIP(window()->layer(), bounds));
113  window()->layer()->transform().TransformRect(&new_bounds);
114  window()->SetBounds(gfx::Rect(gfx::ToFlooredSize(new_bounds.size())));
115}
116
117void WindowTreeHost::ConvertPointToNativeScreen(gfx::Point* point) const {
118  ConvertPointToHost(point);
119  gfx::Point location = GetLocationOnNativeScreen();
120  point->Offset(location.x(), location.y());
121}
122
123void WindowTreeHost::ConvertPointFromNativeScreen(gfx::Point* point) const {
124  gfx::Point location = GetLocationOnNativeScreen();
125  point->Offset(-location.x(), -location.y());
126  ConvertPointFromHost(point);
127}
128
129void WindowTreeHost::ConvertPointToHost(gfx::Point* point) const {
130  gfx::Point3F point_3f(*point);
131  GetRootTransform().TransformPoint(&point_3f);
132  *point = gfx::ToFlooredPoint(point_3f.AsPointF());
133}
134
135void WindowTreeHost::ConvertPointFromHost(gfx::Point* point) const {
136  gfx::Point3F point_3f(*point);
137  GetInverseRootTransform().TransformPoint(&point_3f);
138  *point = gfx::ToFlooredPoint(point_3f.AsPointF());
139}
140
141void WindowTreeHost::SetCursor(gfx::NativeCursor cursor) {
142  last_cursor_ = cursor;
143  // A lot of code seems to depend on NULL cursors actually showing an arrow,
144  // so just pass everything along to the host.
145  SetCursorNative(cursor);
146}
147
148void WindowTreeHost::OnCursorVisibilityChanged(bool show) {
149  // Clear any existing mouse hover effects when the cursor becomes invisible.
150  // Note we do not need to dispatch a mouse enter when the cursor becomes
151  // visible because that can only happen in response to a mouse event, which
152  // will trigger its own mouse enter.
153  if (!show) {
154    ui::EventDispatchDetails details = dispatcher()->DispatchMouseExitAtPoint(
155        dispatcher()->GetLastMouseLocationInRoot());
156    if (details.dispatcher_destroyed)
157      return;
158  }
159
160  OnCursorVisibilityChangedNative(show);
161}
162
163void WindowTreeHost::MoveCursorTo(const gfx::Point& location_in_dip) {
164  gfx::Point host_location(location_in_dip);
165  ConvertPointToHost(&host_location);
166  MoveCursorToInternal(location_in_dip, host_location);
167}
168
169void WindowTreeHost::MoveCursorToHostLocation(const gfx::Point& host_location) {
170  gfx::Point root_location(host_location);
171  ConvertPointFromHost(&root_location);
172  MoveCursorToInternal(root_location, host_location);
173}
174
175////////////////////////////////////////////////////////////////////////////////
176// WindowTreeHost, protected:
177
178WindowTreeHost::WindowTreeHost()
179    : window_(new Window(NULL)),
180      last_cursor_(ui::kCursorNull) {
181}
182
183void WindowTreeHost::DestroyCompositor() {
184  compositor_.reset();
185}
186
187void WindowTreeHost::DestroyDispatcher() {
188  delete window_;
189  window_ = NULL;
190  dispatcher_.reset();
191
192  // TODO(beng): this comment is no longer quite valid since this function
193  // isn't called from WED, and WED isn't a subclass of Window. So it seems
194  // like we could just rely on ~Window now.
195  // Destroy child windows while we're still valid. This is also done by
196  // ~Window, but by that time any calls to virtual methods overriden here (such
197  // as GetRootWindow()) result in Window's implementation. By destroying here
198  // we ensure GetRootWindow() still returns this.
199  //window()->RemoveOrDestroyChildren();
200}
201
202void WindowTreeHost::CreateCompositor(
203    gfx::AcceleratedWidget accelerated_widget) {
204  DCHECK(Env::GetInstance());
205  ui::ContextFactory* context_factory = Env::GetInstance()->context_factory();
206  DCHECK(context_factory);
207  compositor_.reset(
208      new ui::Compositor(GetAcceleratedWidget(),
209                         context_factory,
210                         base::ThreadTaskRunnerHandle::Get()));
211  // TODO(beng): I think this setup should probably all move to a "accelerated
212  // widget available" function.
213  if (!dispatcher()) {
214    window()->Init(WINDOW_LAYER_NOT_DRAWN);
215    window()->set_host(this);
216    window()->SetName("RootWindow");
217    window()->SetEventTargeter(
218        scoped_ptr<ui::EventTargeter>(new WindowTargeter()));
219    prop_.reset(new ui::ViewProp(GetAcceleratedWidget(),
220                                 kWindowTreeHostForAcceleratedWidget,
221                                 this));
222    dispatcher_.reset(new WindowEventDispatcher(this));
223  }
224}
225
226void WindowTreeHost::OnHostMoved(const gfx::Point& new_location) {
227  TRACE_EVENT1("ui", "WindowTreeHost::OnHostMoved",
228               "origin", new_location.ToString());
229
230  FOR_EACH_OBSERVER(WindowTreeHostObserver, observers_,
231                    OnHostMoved(this, new_location));
232}
233
234void WindowTreeHost::OnHostResized(const gfx::Size& new_size) {
235  // The compositor should have the same size as the native root window host.
236  // Get the latest scale from display because it might have been changed.
237  compositor_->SetScaleAndSize(GetDeviceScaleFactorFromDisplay(window()),
238                               new_size);
239
240  gfx::Size layer_size = GetBounds().size();
241  // The layer, and the observers should be notified of the
242  // transformed size of the root window.
243  UpdateRootWindowSize(layer_size);
244  FOR_EACH_OBSERVER(WindowTreeHostObserver, observers_, OnHostResized(this));
245}
246
247void WindowTreeHost::OnHostCloseRequested() {
248  FOR_EACH_OBSERVER(WindowTreeHostObserver, observers_,
249                    OnHostCloseRequested(this));
250}
251
252void WindowTreeHost::OnHostActivated() {
253  Env::GetInstance()->NotifyHostActivated(this);
254}
255
256void WindowTreeHost::OnHostLostWindowCapture() {
257  Window* capture_window = client::GetCaptureWindow(window());
258  if (capture_window && capture_window->GetRootWindow() == window())
259    capture_window->ReleaseCapture();
260}
261
262////////////////////////////////////////////////////////////////////////////////
263// WindowTreeHost, private:
264
265void WindowTreeHost::MoveCursorToInternal(const gfx::Point& root_location,
266                                          const gfx::Point& host_location) {
267  last_cursor_request_position_in_host_ = host_location;
268  MoveCursorToNative(host_location);
269  client::CursorClient* cursor_client = client::GetCursorClient(window());
270  if (cursor_client) {
271    const gfx::Display& display =
272        gfx::Screen::GetScreenFor(window())->GetDisplayNearestWindow(window());
273    cursor_client->SetDisplay(display);
274  }
275  dispatcher()->OnCursorMovedToRootLocation(root_location);
276}
277
278}  // namespace aura
279