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