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