1// Copyright (c) 2012 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/views/controls/native/native_view_host_aura.h"
6
7#include "base/logging.h"
8#include "ui/aura/client/aura_constants.h"
9#include "ui/aura/client/focus_client.h"
10#include "ui/aura/window.h"
11#include "ui/aura/window_delegate.h"
12#include "ui/base/cursor/cursor.h"
13#include "ui/base/hit_test.h"
14#include "ui/views/controls/native/native_view_host.h"
15#include "ui/views/view_constants_aura.h"
16#include "ui/views/widget/widget.h"
17
18namespace views {
19
20class NativeViewHostAura::ClippingWindowDelegate : public aura::WindowDelegate {
21 public:
22  ClippingWindowDelegate() : native_view_(NULL) {}
23  virtual ~ClippingWindowDelegate() {}
24
25  void set_native_view(aura::Window* native_view) {
26    native_view_ = native_view;
27  }
28
29  virtual gfx::Size GetMinimumSize() const OVERRIDE { return gfx::Size(); }
30  virtual gfx::Size GetMaximumSize() const OVERRIDE { return gfx::Size(); }
31  virtual void OnBoundsChanged(const gfx::Rect& old_bounds,
32                               const gfx::Rect& new_bounds) OVERRIDE {}
33  virtual gfx::NativeCursor GetCursor(const gfx::Point& point) OVERRIDE {
34    return gfx::kNullCursor;
35  }
36  virtual int GetNonClientComponent(const gfx::Point& point) const OVERRIDE {
37    return HTCLIENT;
38  }
39  virtual bool ShouldDescendIntoChildForEventHandling(
40      aura::Window* child,
41      const gfx::Point& location) OVERRIDE { return true; }
42  virtual bool CanFocus() OVERRIDE {
43    // Ask the hosted native view's delegate because directly calling
44    // aura::Window::CanFocus() will call back into this when checking whether
45    // parents can focus.
46    return native_view_ && native_view_->delegate()
47        ? native_view_->delegate()->CanFocus()
48        : true;
49  }
50  virtual void OnCaptureLost() OVERRIDE {}
51  virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {}
52  virtual void OnDeviceScaleFactorChanged(float device_scale_factor) OVERRIDE {}
53  virtual void OnWindowDestroying(aura::Window* window) OVERRIDE {}
54  virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE {}
55  virtual void OnWindowTargetVisibilityChanged(bool visible) OVERRIDE {}
56  virtual bool HasHitTestMask() const OVERRIDE { return false; }
57  virtual void GetHitTestMask(gfx::Path* mask) const OVERRIDE {}
58
59 private:
60  aura::Window* native_view_;
61};
62
63NativeViewHostAura::NativeViewHostAura(NativeViewHost* host)
64    : host_(host),
65      clipping_window_delegate_(new ClippingWindowDelegate()),
66      clipping_window_(clipping_window_delegate_.get()) {
67  // Set the type so descendant views (including popups) get positioned
68  // appropriately.
69  clipping_window_.SetType(ui::wm::WINDOW_TYPE_CONTROL);
70  clipping_window_.Init(aura::WINDOW_LAYER_NOT_DRAWN);
71  clipping_window_.set_owned_by_parent(false);
72  clipping_window_.SetName("NativeViewHostAuraClip");
73  clipping_window_.layer()->SetMasksToBounds(true);
74  clipping_window_.SetProperty(views::kHostViewKey, static_cast<View*>(host_));
75}
76
77NativeViewHostAura::~NativeViewHostAura() {
78  if (host_->native_view()) {
79    host_->native_view()->RemoveObserver(this);
80    host_->native_view()->ClearProperty(views::kHostViewKey);
81    host_->native_view()->ClearProperty(aura::client::kHostWindowKey);
82    clipping_window_.ClearProperty(views::kHostViewKey);
83    if (host_->native_view()->parent() == &clipping_window_)
84      clipping_window_.RemoveChild(host_->native_view());
85  }
86}
87
88////////////////////////////////////////////////////////////////////////////////
89// NativeViewHostAura, NativeViewHostWrapper implementation:
90void NativeViewHostAura::AttachNativeView() {
91  clipping_window_delegate_->set_native_view(host_->native_view());
92  host_->native_view()->AddObserver(this);
93  host_->native_view()->SetProperty(views::kHostViewKey,
94      static_cast<View*>(host_));
95  AddClippingWindow();
96}
97
98void NativeViewHostAura::NativeViewDetaching(bool destroyed) {
99  clipping_window_delegate_->set_native_view(NULL);
100  RemoveClippingWindow();
101  if (!destroyed) {
102    host_->native_view()->RemoveObserver(this);
103    host_->native_view()->ClearProperty(views::kHostViewKey);
104    host_->native_view()->ClearProperty(aura::client::kHostWindowKey);
105    host_->native_view()->Hide();
106    if (host_->native_view()->parent())
107      Widget::ReparentNativeView(host_->native_view(), NULL);
108  }
109}
110
111void NativeViewHostAura::AddedToWidget() {
112  if (!host_->native_view())
113    return;
114
115  AddClippingWindow();
116  if (host_->IsDrawn())
117    host_->native_view()->Show();
118  else
119    host_->native_view()->Hide();
120  host_->Layout();
121}
122
123void NativeViewHostAura::RemovedFromWidget() {
124  if (host_->native_view()) {
125    host_->native_view()->Hide();
126    host_->native_view()->ClearProperty(aura::client::kHostWindowKey);
127    if (host_->native_view()->parent())
128      host_->native_view()->parent()->RemoveChild(host_->native_view());
129    RemoveClippingWindow();
130  }
131}
132
133void NativeViewHostAura::InstallClip(int x, int y, int w, int h) {
134  clip_rect_.reset(
135      new gfx::Rect(host_->ConvertRectToWidget(gfx::Rect(x, y, w, h))));
136}
137
138bool NativeViewHostAura::HasInstalledClip() {
139  return clip_rect_;
140}
141
142void NativeViewHostAura::UninstallClip() {
143  clip_rect_.reset();
144}
145
146void NativeViewHostAura::ShowWidget(int x, int y, int w, int h) {
147  int width = w;
148  int height = h;
149  if (host_->fast_resize()) {
150    gfx::Point origin(x, y);
151    views::View::ConvertPointFromWidget(host_, &origin);
152    InstallClip(origin.x(), origin.y(), w, h);
153    width = host_->native_view()->bounds().width();
154    height = host_->native_view()->bounds().height();
155  }
156  clipping_window_.SetBounds(clip_rect_ ? *clip_rect_
157                                        : gfx::Rect(x, y, w, h));
158
159  gfx::Point clip_offset = clipping_window_.bounds().origin();
160  host_->native_view()->SetBounds(
161      gfx::Rect(x - clip_offset.x(), y - clip_offset.y(), width, height));
162  host_->native_view()->Show();
163  clipping_window_.Show();
164}
165
166void NativeViewHostAura::HideWidget() {
167  host_->native_view()->Hide();
168  clipping_window_.Hide();
169}
170
171void NativeViewHostAura::SetFocus() {
172  aura::Window* window = host_->native_view();
173  aura::client::FocusClient* client = aura::client::GetFocusClient(window);
174  if (client)
175    client->FocusWindow(window);
176}
177
178gfx::NativeViewAccessible NativeViewHostAura::GetNativeViewAccessible() {
179  return NULL;
180}
181
182gfx::NativeCursor NativeViewHostAura::GetCursor(int x, int y) {
183  if (host_->native_view())
184    return host_->native_view()->GetCursor(gfx::Point(x, y));
185  return gfx::kNullCursor;
186}
187
188void NativeViewHostAura::OnWindowDestroying(aura::Window* window) {
189  DCHECK(window == host_->native_view());
190  clipping_window_delegate_->set_native_view(NULL);
191}
192
193void NativeViewHostAura::OnWindowDestroyed(aura::Window* window) {
194  DCHECK(window == host_->native_view());
195  host_->NativeViewDestroyed();
196}
197
198// static
199NativeViewHostWrapper* NativeViewHostWrapper::CreateWrapper(
200    NativeViewHost* host) {
201  return new NativeViewHostAura(host);
202}
203
204void NativeViewHostAura::AddClippingWindow() {
205  RemoveClippingWindow();
206
207  host_->native_view()->SetProperty(aura::client::kHostWindowKey,
208                                    host_->GetWidget()->GetNativeView());
209  Widget::ReparentNativeView(host_->native_view(),
210                             &clipping_window_);
211  if (host_->GetWidget()->GetNativeView()) {
212    Widget::ReparentNativeView(&clipping_window_,
213                               host_->GetWidget()->GetNativeView());
214  }
215}
216
217void NativeViewHostAura::RemoveClippingWindow() {
218  clipping_window_.Hide();
219  if (host_->native_view())
220    host_->native_view()->ClearProperty(aura::client::kHostWindowKey);
221
222  if (host_->native_view()->parent() == &clipping_window_) {
223    if (host_->GetWidget() && host_->GetWidget()->GetNativeView()) {
224      Widget::ReparentNativeView(host_->native_view(),
225                                 host_->GetWidget()->GetNativeView());
226    } else {
227      clipping_window_.RemoveChild(host_->native_view());
228    }
229    host_->native_view()->SetBounds(clipping_window_.bounds());
230  }
231  if (clipping_window_.parent())
232    clipping_window_.parent()->RemoveChild(&clipping_window_);
233}
234
235}  // namespace views
236