Home | History | Annotate | Download | only in extensions
      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 "chrome/browser/ui/views/extensions/extension_view_views.h"
      6 
      7 #include "chrome/browser/extensions/extension_view_host.h"
      8 #include "chrome/browser/ui/browser.h"
      9 #include "chrome/browser/ui/views/extensions/extension_popup.h"
     10 #include "content/public/browser/content_browser_client.h"
     11 #include "content/public/browser/render_view_host.h"
     12 #include "content/public/browser/render_widget_host_view.h"
     13 #include "content/public/browser/web_contents.h"
     14 #include "extensions/browser/extension_host.h"
     15 #include "extensions/common/view_type.h"
     16 #include "ui/events/event.h"
     17 #include "ui/views/widget/widget.h"
     18 
     19 #if defined(USE_AURA)
     20 #include "ui/base/cursor/cursor.h"
     21 #endif
     22 
     23 ExtensionViewViews::ExtensionViewViews(extensions::ExtensionHost* host,
     24                                        Browser* browser)
     25     : host_(host),
     26       browser_(browser),
     27       initialized_(false),
     28       container_(NULL),
     29       is_clipped_(false) {
     30   // This view needs to be focusable so it can act as the focused view for the
     31   // focus manager. This is required to have SkipDefaultKeyEventProcessing
     32   // called so the tab key events are forwarded to the renderer.
     33   SetFocusable(true);
     34 }
     35 
     36 ExtensionViewViews::~ExtensionViewViews() {
     37   if (parent())
     38     parent()->RemoveChildView(this);
     39   CleanUp();
     40 }
     41 
     42 gfx::Size ExtensionViewViews::GetMinimumSize() const {
     43   // If the minimum size has never been set, returns the preferred size (same
     44   // behavior as views::View).
     45   return (minimum_size_ == gfx::Size()) ? GetPreferredSize() : minimum_size_;
     46 }
     47 
     48 void ExtensionViewViews::SetVisible(bool is_visible) {
     49   if (is_visible != visible()) {
     50     NativeViewHost::SetVisible(is_visible);
     51 
     52     // Also tell RenderWidgetHostView the new visibility. Despite its name, it
     53     // is not part of the View hierarchy and does not know about the change
     54     // unless we tell it.
     55     content::RenderWidgetHostView* host_view = render_view_host()->GetView();
     56     if (host_view) {
     57       if (is_visible)
     58         host_view->Show();
     59       else
     60         host_view->Hide();
     61     }
     62   }
     63 }
     64 
     65 gfx::NativeCursor ExtensionViewViews::GetCursor(const ui::MouseEvent& event) {
     66   return gfx::kNullCursor;
     67 }
     68 
     69 void ExtensionViewViews::ViewHierarchyChanged(
     70     const ViewHierarchyChangedDetails& details) {
     71   NativeViewHost::ViewHierarchyChanged(details);
     72   if (details.is_add && GetWidget() && !initialized_)
     73     CreateWidgetHostView();
     74 }
     75 
     76 void ExtensionViewViews::SetIsClipped(bool is_clipped) {
     77   if (is_clipped_ != is_clipped) {
     78     is_clipped_ = is_clipped;
     79     if (visible())
     80       ShowIfCompletelyLoaded();
     81   }
     82 }
     83 
     84 void ExtensionViewViews::Init() {
     85   // Initialization continues in ViewHierarchyChanged().
     86 }
     87 
     88 Browser* ExtensionViewViews::GetBrowser() {
     89   return browser_;
     90 }
     91 
     92 gfx::NativeView ExtensionViewViews::GetNativeView() {
     93   return native_view();
     94 }
     95 
     96 void ExtensionViewViews::ResizeDueToAutoResize(const gfx::Size& new_size) {
     97   // Don't actually do anything with this information until we have been shown.
     98   // Size changes will not be honored by lower layers while we are hidden.
     99   if (!visible()) {
    100     pending_preferred_size_ = new_size;
    101     return;
    102   }
    103 
    104   if (new_size != GetPreferredSize())
    105     SetPreferredSize(new_size);
    106 }
    107 
    108 void ExtensionViewViews::RenderViewCreated() {
    109   extensions::ViewType host_type = host_->extension_host_type();
    110   if (host_type == extensions::VIEW_TYPE_EXTENSION_POPUP) {
    111     render_view_host()->EnableAutoResize(
    112         gfx::Size(ExtensionPopup::kMinWidth, ExtensionPopup::kMinHeight),
    113         gfx::Size(ExtensionPopup::kMaxWidth, ExtensionPopup::kMaxHeight));
    114   }
    115 }
    116 
    117 void ExtensionViewViews::HandleKeyboardEvent(
    118     content::WebContents* source,
    119     const content::NativeWebKeyboardEvent& event) {
    120   if (browser_) {
    121     // Handle lower priority browser shortcuts such as Ctrl-f.
    122     browser_->HandleKeyboardEvent(source, event);
    123     return;
    124   }
    125 
    126   unhandled_keyboard_event_handler_.HandleKeyboardEvent(event,
    127                                                         GetFocusManager());
    128 }
    129 
    130 void ExtensionViewViews::DidStopLoading() {
    131   ShowIfCompletelyLoaded();
    132 }
    133 
    134 bool ExtensionViewViews::SkipDefaultKeyEventProcessing(const ui::KeyEvent& e) {
    135   // Let the tab key event be processed by the renderer (instead of moving the
    136   // focus to the next focusable view). Also handle Backspace, since otherwise
    137   // (on Windows at least), pressing Backspace, when focus is on a text field
    138   // within the ExtensionViewViews, will navigate the page back instead of
    139   // erasing a character.
    140   return (e.key_code() == ui::VKEY_TAB || e.key_code() == ui::VKEY_BACK);
    141 }
    142 
    143 void ExtensionViewViews::OnBoundsChanged(const gfx::Rect& previous_bounds) {
    144   // Propagate the new size to RenderWidgetHostView.
    145   // We can't send size zero because RenderWidget DCHECKs that.
    146   if (render_view_host()->GetView() && !bounds().IsEmpty())
    147     render_view_host()->GetView()->SetSize(size());
    148 }
    149 
    150 void ExtensionViewViews::PreferredSizeChanged() {
    151   View::PreferredSizeChanged();
    152   if (container_)
    153     container_->OnExtensionSizeChanged(this);
    154 }
    155 
    156 void ExtensionViewViews::OnFocus() {
    157   host()->host_contents()->Focus();
    158 }
    159 
    160 void ExtensionViewViews::CreateWidgetHostView() {
    161   DCHECK(!initialized_);
    162   initialized_ = true;
    163   Attach(host_->host_contents()->GetNativeView());
    164   host_->CreateRenderViewSoon();
    165   SetVisible(false);
    166 }
    167 
    168 void ExtensionViewViews::ShowIfCompletelyLoaded() {
    169   if (visible() || is_clipped_)
    170     return;
    171 
    172   // We wait to show the ExtensionViewViews until it has loaded, and the view
    173   // has actually been created. These can happen in different orders.
    174   if (host_->did_stop_loading()) {
    175     SetVisible(true);
    176     ResizeDueToAutoResize(pending_preferred_size_);
    177   }
    178 }
    179 
    180 void ExtensionViewViews::CleanUp() {
    181   if (!initialized_)
    182     return;
    183   if (native_view())
    184     Detach();
    185   initialized_ = false;
    186 }
    187 
    188 namespace extensions {
    189 
    190 // static
    191 scoped_ptr<ExtensionView> ExtensionViewHost::CreateExtensionView(
    192     ExtensionViewHost* host,
    193     Browser* browser) {
    194   scoped_ptr<ExtensionViewViews> view(new ExtensionViewViews(host, browser));
    195   // We own |view_|, so don't auto delete when it's removed from the view
    196   // hierarchy.
    197   view->set_owned_by_client();
    198   return view.PassAs<ExtensionView>();
    199 }
    200 
    201 }  // namespace extensions
    202