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