Home | History | Annotate | Download | only in panels
      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/panels/panel_host.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/logging.h"
      9 #include "base/message_loop/message_loop.h"
     10 #include "chrome/browser/chrome_notification_types.h"
     11 #include "chrome/browser/chrome_page_zoom.h"
     12 #include "chrome/browser/extensions/extension_web_contents_observer.h"
     13 #include "chrome/browser/extensions/window_controller.h"
     14 #include "chrome/browser/favicon/favicon_tab_helper.h"
     15 #include "chrome/browser/profiles/profile.h"
     16 #include "chrome/browser/sessions/session_tab_helper.h"
     17 #include "chrome/browser/ui/browser_navigator.h"
     18 #include "chrome/browser/ui/panels/panel.h"
     19 #include "chrome/browser/ui/prefs/prefs_tab_helper.h"
     20 #include "chrome/common/extensions/extension_messages.h"
     21 #include "content/public/browser/invalidate_type.h"
     22 #include "content/public/browser/navigation_controller.h"
     23 #include "content/public/browser/notification_service.h"
     24 #include "content/public/browser/notification_source.h"
     25 #include "content/public/browser/notification_types.h"
     26 #include "content/public/browser/render_view_host.h"
     27 #include "content/public/browser/site_instance.h"
     28 #include "content/public/browser/user_metrics.h"
     29 #include "content/public/browser/web_contents.h"
     30 #include "extensions/browser/view_type_utils.h"
     31 #include "ipc/ipc_message.h"
     32 #include "ipc/ipc_message_macros.h"
     33 #include "ui/gfx/image/image.h"
     34 #include "ui/gfx/rect.h"
     35 
     36 using content::UserMetricsAction;
     37 
     38 PanelHost::PanelHost(Panel* panel, Profile* profile)
     39     : panel_(panel),
     40       profile_(profile),
     41       extension_function_dispatcher_(profile, this),
     42       weak_factory_(this) {
     43 }
     44 
     45 PanelHost::~PanelHost() {
     46 }
     47 
     48 void PanelHost::Init(const GURL& url) {
     49   if (url.is_empty())
     50     return;
     51 
     52   content::WebContents::CreateParams create_params(
     53       profile_, content::SiteInstance::CreateForURL(profile_, url));
     54   web_contents_.reset(content::WebContents::Create(create_params));
     55   extensions::SetViewType(web_contents_.get(), extensions::VIEW_TYPE_PANEL);
     56   web_contents_->SetDelegate(this);
     57   content::WebContentsObserver::Observe(web_contents_.get());
     58 
     59   // Needed to give the web contents a Tab ID. Extension APIs
     60   // expect web contents to have a Tab ID.
     61   SessionTabHelper::CreateForWebContents(web_contents_.get());
     62   SessionTabHelper::FromWebContents(web_contents_.get())->SetWindowID(
     63       panel_->session_id());
     64 
     65   FaviconTabHelper::CreateForWebContents(web_contents_.get());
     66   PrefsTabHelper::CreateForWebContents(web_contents_.get());
     67   extensions::ExtensionWebContentsObserver::CreateForWebContents(
     68       web_contents_.get());
     69 
     70   web_contents_->GetController().LoadURL(
     71       url, content::Referrer(), content::PAGE_TRANSITION_LINK, std::string());
     72 }
     73 
     74 void PanelHost::DestroyWebContents() {
     75   // Cannot do a web_contents_.reset() because web_contents_.get() will
     76   // still return the pointer when we CHECK in WebContentsDestroyed (or if
     77   // we get called back in the middle of web contents destruction, which
     78   // WebView might do when it detects the web contents is destroyed).
     79   content::WebContents* contents = web_contents_.release();
     80   delete contents;
     81 }
     82 
     83 gfx::Image PanelHost::GetPageIcon() const {
     84   if (!web_contents_.get())
     85     return gfx::Image();
     86 
     87   FaviconTabHelper* favicon_tab_helper =
     88       FaviconTabHelper::FromWebContents(web_contents_.get());
     89   CHECK(favicon_tab_helper);
     90   return favicon_tab_helper->GetFavicon();
     91 }
     92 
     93 content::WebContents* PanelHost::OpenURLFromTab(
     94     content::WebContents* source,
     95     const content::OpenURLParams& params) {
     96   // These dispositions aren't really navigations.
     97   if (params.disposition == SUPPRESS_OPEN ||
     98       params.disposition == SAVE_TO_DISK ||
     99       params.disposition == IGNORE_ACTION)
    100     return NULL;
    101 
    102   // Only allow clicks on links.
    103   if (params.transition != content::PAGE_TRANSITION_LINK)
    104     return NULL;
    105 
    106   // Force all links to open in a new tab.
    107   chrome::NavigateParams navigate_params(profile_,
    108                                          params.url,
    109                                          params.transition);
    110   switch (params.disposition) {
    111     case NEW_BACKGROUND_TAB:
    112     case NEW_WINDOW:
    113     case OFF_THE_RECORD:
    114       navigate_params.disposition = params.disposition;
    115       break;
    116     default:
    117       navigate_params.disposition = NEW_FOREGROUND_TAB;
    118       break;
    119   }
    120   chrome::Navigate(&navigate_params);
    121   return navigate_params.target_contents;
    122 }
    123 
    124 void PanelHost::NavigationStateChanged(const content::WebContents* source,
    125                                        unsigned changed_flags) {
    126   // Only need to update the title if the title changed while not loading,
    127   // because the title is also updated when loading state changes.
    128   if ((changed_flags & content::INVALIDATE_TYPE_TAB) ||
    129       ((changed_flags & content::INVALIDATE_TYPE_TITLE) &&
    130        !source->IsLoading()))
    131     panel_->UpdateTitleBar();
    132 }
    133 
    134 void PanelHost::AddNewContents(content::WebContents* source,
    135                                content::WebContents* new_contents,
    136                                WindowOpenDisposition disposition,
    137                                const gfx::Rect& initial_pos,
    138                                bool user_gesture,
    139                                bool* was_blocked) {
    140   chrome::NavigateParams navigate_params(profile_, new_contents->GetURL(),
    141                                          content::PAGE_TRANSITION_LINK);
    142   navigate_params.target_contents = new_contents;
    143 
    144   // Force all links to open in a new tab, even if they were trying to open a
    145   // window.
    146   navigate_params.disposition =
    147       disposition == NEW_BACKGROUND_TAB ? disposition : NEW_FOREGROUND_TAB;
    148 
    149   navigate_params.window_bounds = initial_pos;
    150   navigate_params.user_gesture = user_gesture;
    151   navigate_params.extension_app_id = panel_->extension_id();
    152   chrome::Navigate(&navigate_params);
    153 }
    154 
    155 void PanelHost::ActivateContents(content::WebContents* contents) {
    156   panel_->Activate();
    157 }
    158 
    159 void PanelHost::DeactivateContents(content::WebContents* contents) {
    160   panel_->Deactivate();
    161 }
    162 
    163 void PanelHost::LoadingStateChanged(content::WebContents* source) {
    164   bool is_loading = source->IsLoading();
    165   panel_->LoadingStateChanged(is_loading);
    166 }
    167 
    168 void PanelHost::CloseContents(content::WebContents* source) {
    169   panel_->Close();
    170 }
    171 
    172 void PanelHost::MoveContents(content::WebContents* source,
    173                              const gfx::Rect& pos) {
    174   panel_->SetBounds(pos);
    175 }
    176 
    177 bool PanelHost::IsPopupOrPanel(const content::WebContents* source) const {
    178   return true;
    179 }
    180 
    181 void PanelHost::ContentsZoomChange(bool zoom_in) {
    182   Zoom(zoom_in ? content::PAGE_ZOOM_IN : content::PAGE_ZOOM_OUT);
    183 }
    184 
    185 void PanelHost::HandleKeyboardEvent(
    186     content::WebContents* source,
    187     const content::NativeWebKeyboardEvent& event) {
    188   return panel_->HandleKeyboardEvent(event);
    189 }
    190 
    191 void PanelHost::WebContentsFocused(content::WebContents* contents) {
    192   panel_->WebContentsFocused(contents);
    193 }
    194 
    195 void PanelHost::ResizeDueToAutoResize(content::WebContents* web_contents,
    196                                       const gfx::Size& new_size) {
    197   panel_->OnContentsAutoResized(new_size);
    198 }
    199 
    200 void PanelHost::RenderViewCreated(content::RenderViewHost* render_view_host) {
    201   extensions::WindowController* window = GetExtensionWindowController();
    202   render_view_host->Send(new ExtensionMsg_UpdateBrowserWindowId(
    203       render_view_host->GetRoutingID(), window->GetWindowId()));
    204 }
    205 
    206 void PanelHost::RenderProcessGone(base::TerminationStatus status) {
    207   CloseContents(web_contents_.get());
    208 }
    209 
    210 void PanelHost::WebContentsDestroyed(content::WebContents* web_contents) {
    211   // Web contents should only be destroyed by us.
    212   CHECK(!web_contents_.get());
    213 
    214   // Close the panel after we return to the message loop (not immediately,
    215   // otherwise, it may destroy this object before the stack has a chance
    216   // to cleanly unwind.)
    217   base::MessageLoop::current()->PostTask(
    218       FROM_HERE,
    219       base::Bind(&PanelHost::ClosePanel, weak_factory_.GetWeakPtr()));
    220 }
    221 
    222 void PanelHost::ClosePanel() {
    223   panel_->Close();
    224 }
    225 
    226 bool PanelHost::OnMessageReceived(const IPC::Message& message) {
    227   bool handled = true;
    228   IPC_BEGIN_MESSAGE_MAP(PanelHost, message)
    229     IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest)
    230     IPC_MESSAGE_UNHANDLED(handled = false)
    231   IPC_END_MESSAGE_MAP()
    232   return handled;
    233 }
    234 
    235 void PanelHost::OnRequest(const ExtensionHostMsg_Request_Params& params) {
    236   if (!web_contents_.get())
    237     return;
    238 
    239   extension_function_dispatcher_.Dispatch(params,
    240                                           web_contents_->GetRenderViewHost());
    241 }
    242 
    243 extensions::WindowController* PanelHost::GetExtensionWindowController() const {
    244   return panel_->extension_window_controller();
    245 }
    246 
    247 content::WebContents* PanelHost::GetAssociatedWebContents() const {
    248   return web_contents_.get();
    249 }
    250 
    251 void PanelHost::Reload() {
    252   content::RecordAction(UserMetricsAction("Reload"));
    253   web_contents_->GetController().Reload(true);
    254 }
    255 
    256 void PanelHost::ReloadIgnoringCache() {
    257   content::RecordAction(UserMetricsAction("ReloadIgnoringCache"));
    258   web_contents_->GetController().ReloadIgnoringCache(true);
    259 }
    260 
    261 void PanelHost::StopLoading() {
    262   content::RecordAction(UserMetricsAction("Stop"));
    263   web_contents_->Stop();
    264 }
    265 
    266 void PanelHost::Zoom(content::PageZoom zoom) {
    267   chrome_page_zoom::Zoom(web_contents_.get(), zoom);
    268 }
    269