Home | History | Annotate | Download | only in webview
      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/webview/webview.h"
      6 
      7 #include "content/public/browser/browser_context.h"
      8 #include "content/public/browser/navigation_controller.h"
      9 #include "content/public/browser/notification_details.h"
     10 #include "content/public/browser/notification_registrar.h"
     11 #include "content/public/browser/notification_source.h"
     12 #include "content/public/browser/notification_types.h"
     13 #include "content/public/browser/render_view_host.h"
     14 #include "content/public/browser/render_widget_host_view.h"
     15 #include "content/public/browser/web_contents.h"
     16 #include "content/public/browser/web_contents_view.h"
     17 #include "ipc/ipc_message.h"
     18 #include "ui/base/accessibility/accessibility_types.h"
     19 #include "ui/base/accessibility/accessible_view_state.h"
     20 #include "ui/base/events/event.h"
     21 #include "ui/views/accessibility/native_view_accessibility.h"
     22 #include "ui/views/controls/native/native_view_host.h"
     23 #include "ui/views/focus/focus_manager.h"
     24 #include "ui/views/views_delegate.h"
     25 
     26 namespace views {
     27 
     28 // static
     29 const char WebView::kViewClassName[] = "WebView";
     30 
     31 ////////////////////////////////////////////////////////////////////////////////
     32 // WebView, public:
     33 
     34 WebView::WebView(content::BrowserContext* browser_context)
     35     : wcv_holder_(new NativeViewHost),
     36       web_contents_(NULL),
     37       browser_context_(browser_context),
     38       allow_accelerators_(false) {
     39   AddChildView(wcv_holder_);
     40   NativeViewAccessibility::RegisterWebView(this);
     41 }
     42 
     43 WebView::~WebView() {
     44   NativeViewAccessibility::UnregisterWebView(this);
     45 }
     46 
     47 content::WebContents* WebView::GetWebContents() {
     48   CreateWebContentsWithSiteInstance(NULL);
     49   return web_contents_;
     50 }
     51 
     52 void WebView::CreateWebContentsWithSiteInstance(
     53     content::SiteInstance* site_instance) {
     54   if (!web_contents_) {
     55     wc_owner_.reset(CreateWebContents(browser_context_, site_instance));
     56     web_contents_ = wc_owner_.get();
     57     web_contents_->SetDelegate(this);
     58     AttachWebContents();
     59   }
     60 }
     61 
     62 void WebView::SetWebContents(content::WebContents* web_contents) {
     63   if (web_contents == web_contents_)
     64     return;
     65   DetachWebContents();
     66   wc_owner_.reset();
     67   web_contents_ = web_contents;
     68   AttachWebContents();
     69 }
     70 
     71 void WebView::LoadInitialURL(const GURL& url) {
     72   GetWebContents()->GetController().LoadURL(
     73       url, content::Referrer(), content::PAGE_TRANSITION_AUTO_TOPLEVEL,
     74       std::string());
     75 }
     76 
     77 void WebView::SetFastResize(bool fast_resize) {
     78   wcv_holder_->set_fast_resize(fast_resize);
     79 }
     80 
     81 void WebView::OnWebContentsFocused(content::WebContents* web_contents) {
     82   FocusManager* focus_manager = GetFocusManager();
     83   if (focus_manager)
     84     focus_manager->SetFocusedView(this);
     85 }
     86 
     87 void WebView::SetPreferredSize(const gfx::Size& preferred_size) {
     88   preferred_size_ = preferred_size;
     89   PreferredSizeChanged();
     90 }
     91 
     92 ////////////////////////////////////////////////////////////////////////////////
     93 // WebView, View overrides:
     94 
     95 const char* WebView::GetClassName() const {
     96   return kViewClassName;
     97 }
     98 
     99 void WebView::OnBoundsChanged(const gfx::Rect& previous_bounds) {
    100   wcv_holder_->SetSize(bounds().size());
    101 }
    102 
    103 void WebView::ViewHierarchyChanged(
    104     const ViewHierarchyChangedDetails& details) {
    105   if (details.is_add)
    106     AttachWebContents();
    107 }
    108 
    109 bool WebView::SkipDefaultKeyEventProcessing(const ui::KeyEvent& event) {
    110   if (allow_accelerators_)
    111     return FocusManager::IsTabTraversalKeyEvent(event);
    112 
    113   // Don't look-up accelerators or tab-traversal if we are showing a non-crashed
    114   // TabContents.
    115   // We'll first give the page a chance to process the key events.  If it does
    116   // not process them, they'll be returned to us and we'll treat them as
    117   // accelerators then.
    118   return web_contents_ && !web_contents_->IsCrashed();
    119 }
    120 
    121 bool WebView::IsFocusable() const {
    122   // We need to be focusable when our contents is not a view hierarchy, as
    123   // clicking on the contents needs to focus us.
    124   return !!web_contents_;
    125 }
    126 
    127 void WebView::OnFocus() {
    128   if (web_contents_)
    129     web_contents_->GetView()->Focus();
    130 }
    131 
    132 void WebView::AboutToRequestFocusFromTabTraversal(bool reverse) {
    133   if (web_contents_)
    134     web_contents_->FocusThroughTabTraversal(reverse);
    135 }
    136 
    137 void WebView::GetAccessibleState(ui::AccessibleViewState* state) {
    138   state->role = ui::AccessibilityTypes::ROLE_GROUPING;
    139 }
    140 
    141 gfx::NativeViewAccessible WebView::GetNativeViewAccessible() {
    142   if (web_contents_) {
    143     content::RenderWidgetHostView* host_view =
    144         web_contents_->GetRenderWidgetHostView();
    145     if (host_view)
    146       return host_view->GetNativeViewAccessible();
    147   }
    148   return View::GetNativeViewAccessible();
    149 }
    150 
    151 gfx::Size WebView::GetPreferredSize() {
    152   if (preferred_size_ == gfx::Size())
    153     return View::GetPreferredSize();
    154   else
    155     return preferred_size_;
    156 }
    157 
    158 ////////////////////////////////////////////////////////////////////////////////
    159 // WebView, content::NotificationObserver implementation:
    160 
    161 void WebView::Observe(int type,
    162                       const content::NotificationSource& source,
    163                       const content::NotificationDetails& details) {
    164   if (type == content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED) {
    165     std::pair<content::RenderViewHost*, content::RenderViewHost*>*
    166         switched_details =
    167             content::Details<std::pair<content::RenderViewHost*,
    168                                        content::RenderViewHost*> >(
    169                 details).ptr();
    170     RenderViewHostChanged(switched_details->first,
    171                           switched_details->second);
    172   } else if (type == content::NOTIFICATION_WEB_CONTENTS_DESTROYED) {
    173     WebContentsDestroyed(content::Source<content::WebContents>(source).ptr());
    174   } else {
    175     NOTREACHED();
    176   }
    177 }
    178 
    179 ////////////////////////////////////////////////////////////////////////////////
    180 // WebView, content::WebContentsDelegate implementation:
    181 
    182 void WebView::WebContentsFocused(content::WebContents* web_contents) {
    183   DCHECK(wc_owner_.get());
    184   // The WebView is only the delegate of WebContentses it creates itself.
    185   OnWebContentsFocused(web_contents_);
    186 }
    187 
    188 ////////////////////////////////////////////////////////////////////////////////
    189 // WebView, AccessibleWebView implementation:
    190 
    191 gfx::NativeViewAccessible WebView::AccessibleObjectFromChildId(long child_id) {
    192 #if defined(OS_WIN) && defined(USE_AURA)
    193   if (!web_contents_)
    194     return NULL;
    195   content::RenderWidgetHostView* host_view =
    196       web_contents_->GetRenderWidgetHostView();
    197   if (host_view)
    198     return host_view->AccessibleObjectFromChildId(child_id);
    199   return NULL;
    200 #else
    201   NOTIMPLEMENTED();
    202   return NULL;
    203 #endif
    204 }
    205 
    206 View* WebView::AsView() {
    207   return this;
    208 }
    209 
    210 ////////////////////////////////////////////////////////////////////////////////
    211 // WebView, private:
    212 
    213 void WebView::AttachWebContents() {
    214   // Prevents attachment if the WebView isn't already in a Widget, or it's
    215   // already attached.
    216   if (!GetWidget() || !web_contents_ ||
    217       wcv_holder_->native_view() == web_contents_->GetView()->GetNativeView()) {
    218     return;
    219   }
    220 
    221   if (web_contents_) {
    222     wcv_holder_->Attach(web_contents_->GetView()->GetNativeView());
    223 
    224     // The WebContentsView will not be focused automatically when it is
    225     // attached, so we need to pass on focus to it if the FocusManager thinks
    226     // the WebView is focused. Note that not every Widget has a focus manager.
    227     FocusManager* focus_manager = GetFocusManager();
    228     if (focus_manager && focus_manager->GetFocusedView() == this)
    229       web_contents_->GetView()->Focus();
    230 
    231     registrar_.Add(
    232         this,
    233         content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED,
    234         content::Source<content::NavigationController>(
    235             &web_contents_->GetController()));
    236     registrar_.Add(
    237         this,
    238         content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
    239         content::Source<content::WebContents>(web_contents_));
    240   }
    241 
    242 #if defined(OS_WIN) && defined(USE_AURA)
    243   web_contents_->SetParentNativeViewAccessible(
    244       parent()->GetNativeViewAccessible());
    245 #endif
    246 }
    247 
    248 void WebView::DetachWebContents() {
    249   if (web_contents_) {
    250     wcv_holder_->Detach();
    251 #if defined(OS_WIN) && !defined(USE_AURA)
    252     // TODO(beng): This should either not be necessary, or be done implicitly by
    253     // NativeViewHostWin on Detach(). As it stands, this is needed so that the
    254     // view of the detached contents knows to tell the renderer it's been
    255     // hidden.
    256     //
    257     // Moving this out of here would also mean we wouldn't be potentially
    258     // calling member functions on a half-destroyed WebContents.
    259     ShowWindow(web_contents_->GetView()->GetNativeView(), SW_HIDE);
    260 #elif defined(OS_WIN) && defined(USE_AURA)
    261     web_contents_->SetParentNativeViewAccessible(NULL);
    262 #endif
    263   }
    264   registrar_.RemoveAll();
    265 }
    266 
    267 void WebView::RenderViewHostChanged(content::RenderViewHost* old_host,
    268                                     content::RenderViewHost* new_host) {
    269   if (GetFocusManager()->GetFocusedView() == this)
    270     web_contents_->GetView()->Focus();
    271 }
    272 
    273 void WebView::WebContentsDestroyed(content::WebContents* web_contents) {
    274   DCHECK(web_contents == web_contents_);
    275   SetWebContents(NULL);
    276 }
    277 
    278 content::WebContents* WebView::CreateWebContents(
    279       content::BrowserContext* browser_context,
    280       content::SiteInstance* site_instance) {
    281   content::WebContents* contents = NULL;
    282   if (ViewsDelegate::views_delegate) {
    283     contents = ViewsDelegate::views_delegate->CreateWebContents(
    284         browser_context, site_instance);
    285   }
    286 
    287   if (!contents) {
    288     content::WebContents::CreateParams create_params(
    289         browser_context, site_instance);
    290     return content::WebContents::Create(create_params);
    291   }
    292 
    293   return contents;
    294 }
    295 
    296 }  // namespace views
    297