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.
5 #include "ui/views/controls/native/native_view_host.h"
7 #include "base/logging.h"
8 #include "ui/base/cursor/cursor.h"
9 #include "ui/gfx/canvas.h"
10 #include "ui/views/accessibility/native_view_accessibility.h"
11 #include "ui/views/controls/native/native_view_host_wrapper.h"
12 #include "ui/views/widget/widget.h"
17 const char NativeViewHost::kViewClassName
[] = "NativeViewHost";
18 const char kWidgetNativeViewHostKey
[] = "WidgetNativeViewHost";
20 ////////////////////////////////////////////////////////////////////////////////
21 // NativeViewHost, public:
23 NativeViewHost::NativeViewHost()
26 fast_resize_at_last_layout_(false),
27 resize_background_color_(SK_ColorWHITE
) {
30 NativeViewHost::~NativeViewHost() {
33 void NativeViewHost::Attach(gfx::NativeView native_view
) {
35 DCHECK(!native_view_
);
36 native_view_
= native_view
;
37 native_wrapper_
->AttachNativeView();
40 Widget
* widget
= Widget::GetWidgetForNativeView(native_view
);
42 widget
->SetNativeWindowProperty(kWidgetNativeViewHostKey
, this);
45 void NativeViewHost::Detach() {
49 void NativeViewHost::SetPreferredSize(const gfx::Size
& size
) {
50 preferred_size_
= size
;
51 PreferredSizeChanged();
54 void NativeViewHost::NativeViewDestroyed() {
55 // Detach so we can clear our state and notify the native_wrapper_ to release
56 // ref on the native view.
60 ////////////////////////////////////////////////////////////////////////////////
61 // NativeViewHost, View overrides:
63 gfx::Size
NativeViewHost::GetPreferredSize() const {
64 return preferred_size_
;
67 void NativeViewHost::Layout() {
68 if (!native_view_
|| !native_wrapper_
.get())
71 gfx::Rect vis_bounds
= GetVisibleBounds();
72 bool visible
= !vis_bounds
.IsEmpty();
74 if (visible
&& !fast_resize_
) {
75 if (vis_bounds
.size() != size()) {
76 // Only a portion of the Widget is really visible.
77 int x
= vis_bounds
.x();
78 int y
= vis_bounds
.y();
79 native_wrapper_
->InstallClip(x
, y
, vis_bounds
.width(),
81 } else if (native_wrapper_
->HasInstalledClip()) {
82 // The whole widget is visible but we installed a clip on the widget,
84 native_wrapper_
->UninstallClip();
89 // Since widgets know nothing about the View hierarchy (they are direct
90 // children of the Widget that hosts our View hierarchy) they need to be
91 // positioned in the coordinate system of the Widget, not the current
92 // view. Also, they should be positioned respecting the border insets
93 // of the native view.
94 gfx::Rect local_bounds
= ConvertRectToWidget(GetContentsBounds());
95 native_wrapper_
->ShowWidget(local_bounds
.x(), local_bounds
.y(),
97 local_bounds
.height());
99 native_wrapper_
->HideWidget();
101 fast_resize_at_last_layout_
= visible
&& fast_resize_
;
104 void NativeViewHost::OnPaint(gfx::Canvas
* canvas
) {
105 // Paint background if there is one. NativeViewHost needs to paint
106 // a background when it is hosted in a TabbedPane. For Gtk implementation,
107 // NativeTabbedPaneGtk uses a NativeWidgetGtk as page container and because
108 // NativeWidgetGtk hook "expose" with its root view's paint, we need to
109 // fill the content. Otherwise, the tab page's background is not properly
110 // cleared. For Windows case, it appears okay to not paint background because
111 // we don't have a container window in-between. However if you want to use
112 // customized background, then this becomes necessary.
113 OnPaintBackground(canvas
);
115 // The area behind our window is black, so during a fast resize (where our
116 // content doesn't draw over the full size of our native view, and the native
117 // view background color doesn't show up), we need to cover that blackness
118 // with something so that fast resizes don't result in black flash.
120 // It would be nice if this used some approximation of the page's
121 // current background color.
122 if (native_wrapper_
->HasInstalledClip())
123 canvas
->FillRect(GetLocalBounds(), resize_background_color_
);
126 void NativeViewHost::VisibilityChanged(View
* starting_from
, bool is_visible
) {
130 bool NativeViewHost::GetNeedsNotificationWhenVisibleBoundsChange() const {
131 // The native widget is placed relative to the root. As such, we need to
132 // know when the position of any ancestor changes, or our visibility relative
133 // to other views changed as it'll effect our position relative to the root.
137 void NativeViewHost::OnVisibleBoundsChanged() {
141 void NativeViewHost::ViewHierarchyChanged(
142 const ViewHierarchyChangedDetails
& details
) {
143 views::Widget
* this_widget
= GetWidget();
145 // A non-NULL |details.move_view| indicates a move operation i.e. |this| is
146 // is being reparented. If the previous and new parents belong to the same
147 // widget, don't remove |this| from the widget. This saves resources from
148 // removing from widget and immediately followed by adding to widget; in
149 // particular, there wouldn't be spurious visibilitychange events for web
150 // contents of |WebView|.
151 if (details
.move_view
&& this_widget
&&
152 details
.move_view
->GetWidget() == this_widget
) {
156 if (details
.is_add
&& this_widget
) {
157 if (!native_wrapper_
.get())
158 native_wrapper_
.reset(NativeViewHostWrapper::CreateWrapper(this));
159 native_wrapper_
->AddedToWidget();
160 } else if (!details
.is_add
) {
161 native_wrapper_
->RemovedFromWidget();
165 const char* NativeViewHost::GetClassName() const {
166 return kViewClassName
;
169 void NativeViewHost::OnFocus() {
170 native_wrapper_
->SetFocus();
171 NotifyAccessibilityEvent(ui::AX_EVENT_FOCUS
, true);
174 gfx::NativeViewAccessible
NativeViewHost::GetNativeViewAccessible() {
175 if (native_wrapper_
.get()) {
176 gfx::NativeViewAccessible accessible_view
=
177 native_wrapper_
->GetNativeViewAccessible();
179 return accessible_view
;
182 return View::GetNativeViewAccessible();
185 gfx::NativeCursor
NativeViewHost::GetCursor(const ui::MouseEvent
& event
) {
186 return native_wrapper_
->GetCursor(event
.x(), event
.y());
189 ////////////////////////////////////////////////////////////////////////////////
190 // NativeViewHost, private:
192 void NativeViewHost::Detach(bool destroyed
) {
195 Widget
* widget
= Widget::GetWidgetForNativeView(native_view_
);
197 widget
->SetNativeWindowProperty(kWidgetNativeViewHostKey
, NULL
);
200 native_wrapper_
->NativeViewDetaching(destroyed
);
205 void NativeViewHost::ClearFocus() {
206 FocusManager
* focus_manager
= GetFocusManager();
207 if (!focus_manager
|| !focus_manager
->GetFocusedView())
210 Widget::Widgets widgets
;
211 Widget::GetAllChildWidgets(native_view(), &widgets
);
212 for (Widget::Widgets::iterator i
= widgets
.begin(); i
!= widgets
.end(); ++i
) {
213 focus_manager
->ViewRemoved((*i
)->GetRootView());
214 if (!focus_manager
->GetFocusedView())