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.h" 6 7 #include "base/logging.h" 8 #include "ui/gfx/canvas.h" 9 #include "ui/views/accessibility/native_view_accessibility.h" 10 #include "ui/views/controls/native/native_view_host_wrapper.h" 11 #include "ui/views/widget/widget.h" 12 13 namespace views { 14 15 // static 16 const char NativeViewHost::kViewClassName[] = "NativeViewHost"; 17 const char kWidgetNativeViewHostKey[] = "WidgetNativeViewHost"; 18 19 #if defined(USE_AURA) 20 // Views implementation draws the focus. 21 // TODO(oshima): Eliminate this flag and consolidate 22 // the focus border code. 23 const bool NativeViewHost::kRenderNativeControlFocus = false; 24 #else 25 // static 26 const bool NativeViewHost::kRenderNativeControlFocus = true; 27 #endif 28 29 //////////////////////////////////////////////////////////////////////////////// 30 // NativeViewHost, public: 31 32 NativeViewHost::NativeViewHost() 33 : native_view_(NULL), 34 fast_resize_(false), 35 fast_resize_at_last_layout_(false), 36 focus_view_(NULL) { 37 } 38 39 NativeViewHost::~NativeViewHost() { 40 } 41 42 void NativeViewHost::Attach(gfx::NativeView native_view) { 43 DCHECK(native_view); 44 DCHECK(!native_view_); 45 native_view_ = native_view; 46 // If set_focus_view() has not been invoked, this view is the one that should 47 // be seen as focused when the native view receives focus. 48 if (!focus_view_) 49 focus_view_ = this; 50 native_wrapper_->NativeViewWillAttach(); 51 Widget::ReparentNativeView(native_view_, GetWidget()->GetNativeView()); 52 Layout(); 53 54 Widget* widget = Widget::GetWidgetForNativeView(native_view); 55 if (widget) 56 widget->SetNativeWindowProperty(kWidgetNativeViewHostKey, this); 57 } 58 59 void NativeViewHost::Detach() { 60 Detach(false); 61 } 62 63 void NativeViewHost::SetPreferredSize(const gfx::Size& size) { 64 preferred_size_ = size; 65 PreferredSizeChanged(); 66 } 67 68 void NativeViewHost::NativeViewDestroyed() { 69 // Detach so we can clear our state and notify the native_wrapper_ to release 70 // ref on the native view. 71 Detach(true); 72 } 73 74 //////////////////////////////////////////////////////////////////////////////// 75 // NativeViewHost, View overrides: 76 77 gfx::Size NativeViewHost::GetPreferredSize() { 78 return preferred_size_; 79 } 80 81 void NativeViewHost::Layout() { 82 if (!native_view_ || !native_wrapper_.get()) 83 return; 84 85 gfx::Rect vis_bounds = GetVisibleBounds(); 86 bool visible = !vis_bounds.IsEmpty(); 87 88 if (visible && !fast_resize_) { 89 if (vis_bounds.size() != size()) { 90 // Only a portion of the Widget is really visible. 91 int x = vis_bounds.x(); 92 int y = vis_bounds.y(); 93 native_wrapper_->InstallClip(x, y, vis_bounds.width(), 94 vis_bounds.height()); 95 } else if (native_wrapper_->HasInstalledClip()) { 96 // The whole widget is visible but we installed a clip on the widget, 97 // uninstall it. 98 native_wrapper_->UninstallClip(); 99 } 100 } 101 102 if (visible) { 103 // Since widgets know nothing about the View hierarchy (they are direct 104 // children of the Widget that hosts our View hierarchy) they need to be 105 // positioned in the coordinate system of the Widget, not the current 106 // view. Also, they should be positioned respecting the border insets 107 // of the native view. 108 gfx::Rect local_bounds = ConvertRectToWidget(GetContentsBounds()); 109 native_wrapper_->ShowWidget(local_bounds.x(), local_bounds.y(), 110 local_bounds.width(), 111 local_bounds.height()); 112 } else { 113 native_wrapper_->HideWidget(); 114 } 115 fast_resize_at_last_layout_ = visible && fast_resize_; 116 } 117 118 void NativeViewHost::OnPaint(gfx::Canvas* canvas) { 119 // Paint background if there is one. NativeViewHost needs to paint 120 // a background when it is hosted in a TabbedPane. For Gtk implementation, 121 // NativeTabbedPaneGtk uses a NativeWidgetGtk as page container and because 122 // NativeWidgetGtk hook "expose" with its root view's paint, we need to 123 // fill the content. Otherwise, the tab page's background is not properly 124 // cleared. For Windows case, it appears okay to not paint background because 125 // we don't have a container window in-between. However if you want to use 126 // customized background, then this becomes necessary. 127 OnPaintBackground(canvas); 128 129 // The area behind our window is black, so during a fast resize (where our 130 // content doesn't draw over the full size of our native view, and the native 131 // view background color doesn't show up), we need to cover that blackness 132 // with something so that fast resizes don't result in black flash. 133 // 134 // It would be nice if this used some approximation of the page's 135 // current background color. 136 if (native_wrapper_->HasInstalledClip()) 137 canvas->FillRect(GetLocalBounds(), SK_ColorWHITE); 138 } 139 140 void NativeViewHost::VisibilityChanged(View* starting_from, bool is_visible) { 141 Layout(); 142 } 143 144 bool NativeViewHost::NeedsNotificationWhenVisibleBoundsChange() const { 145 // The native widget is placed relative to the root. As such, we need to 146 // know when the position of any ancestor changes, or our visibility relative 147 // to other views changed as it'll effect our position relative to the root. 148 return true; 149 } 150 151 void NativeViewHost::OnVisibleBoundsChanged() { 152 Layout(); 153 } 154 155 void NativeViewHost::ViewHierarchyChanged( 156 const ViewHierarchyChangedDetails& details) { 157 views::Widget* this_widget = GetWidget(); 158 159 // A non-NULL |details.move_view| indicates a move operation i.e. |this| is 160 // is being reparented. If the previous and new parents belong to the same 161 // widget, don't remove |this| from the widget. This saves resources from 162 // removing from widget and immediately followed by adding to widget; in 163 // particular, there wouldn't be spurious visibilitychange events for web 164 // contents of |WebView|. 165 if (details.move_view && this_widget && 166 details.move_view->GetWidget() == this_widget) { 167 return; 168 } 169 170 if (details.is_add && this_widget) { 171 if (!native_wrapper_.get()) 172 native_wrapper_.reset(NativeViewHostWrapper::CreateWrapper(this)); 173 native_wrapper_->AddedToWidget(); 174 } else if (!details.is_add) { 175 native_wrapper_->RemovedFromWidget(); 176 } 177 } 178 179 const char* NativeViewHost::GetClassName() const { 180 return kViewClassName; 181 } 182 183 void NativeViewHost::OnFocus() { 184 native_wrapper_->SetFocus(); 185 NotifyAccessibilityEvent(ui::AccessibilityTypes::EVENT_FOCUS, true); 186 } 187 188 gfx::NativeViewAccessible NativeViewHost::GetNativeViewAccessible() { 189 if (native_wrapper_.get()) { 190 gfx::NativeViewAccessible accessible_view = 191 native_wrapper_->GetNativeViewAccessible(); 192 if (accessible_view) 193 return accessible_view; 194 } 195 196 return View::GetNativeViewAccessible(); 197 } 198 199 //////////////////////////////////////////////////////////////////////////////// 200 // NativeViewHost, private: 201 202 void NativeViewHost::Detach(bool destroyed) { 203 if (native_view_) { 204 if (!destroyed) { 205 Widget* widget = Widget::GetWidgetForNativeView(native_view_); 206 if (widget) 207 widget->SetNativeWindowProperty(kWidgetNativeViewHostKey, NULL); 208 ClearFocus(); 209 } 210 native_wrapper_->NativeViewDetaching(destroyed); 211 native_view_ = NULL; 212 } 213 } 214 215 void NativeViewHost::ClearFocus() { 216 FocusManager* focus_manager = GetFocusManager(); 217 if (!focus_manager || !focus_manager->GetFocusedView()) 218 return; 219 220 Widget::Widgets widgets; 221 Widget::GetAllChildWidgets(native_view(), &widgets); 222 for (Widget::Widgets::iterator i = widgets.begin(); i != widgets.end(); ++i) { 223 focus_manager->ViewRemoved((*i)->GetRootView()); 224 if (!focus_manager->GetFocusedView()) 225 return; 226 } 227 } 228 229 230 } // namespace views 231