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/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