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 37using base::UserMetricsAction; 38 39PanelHost::PanelHost(Panel* panel, Profile* profile) 40 : panel_(panel), 41 profile_(profile), 42 extension_function_dispatcher_(profile, this), 43 weak_factory_(this) { 44} 45 46PanelHost::~PanelHost() { 47} 48 49void 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 78void 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 87gfx::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 97content::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 128void 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 138void 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 159void PanelHost::ActivateContents(content::WebContents* contents) { 160 panel_->Activate(); 161} 162 163void PanelHost::DeactivateContents(content::WebContents* contents) { 164 panel_->Deactivate(); 165} 166 167void 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 173void PanelHost::CloseContents(content::WebContents* source) { 174 panel_->Close(); 175} 176 177void PanelHost::MoveContents(content::WebContents* source, 178 const gfx::Rect& pos) { 179 panel_->SetBounds(pos); 180} 181 182bool PanelHost::IsPopupOrPanel(const content::WebContents* source) const { 183 return true; 184} 185 186void PanelHost::ContentsZoomChange(bool zoom_in) { 187 Zoom(zoom_in ? content::PAGE_ZOOM_IN : content::PAGE_ZOOM_OUT); 188} 189 190void PanelHost::HandleKeyboardEvent( 191 content::WebContents* source, 192 const content::NativeWebKeyboardEvent& event) { 193 return panel_->HandleKeyboardEvent(event); 194} 195 196void PanelHost::WebContentsFocused(content::WebContents* contents) { 197 panel_->WebContentsFocused(contents); 198} 199 200void PanelHost::ResizeDueToAutoResize(content::WebContents* web_contents, 201 const gfx::Size& new_size) { 202 panel_->OnContentsAutoResized(new_size); 203} 204 205void 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 211void PanelHost::RenderProcessGone(base::TerminationStatus status) { 212 CloseContents(web_contents_.get()); 213} 214 215void 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 227void PanelHost::ClosePanel() { 228 panel_->Close(); 229} 230 231bool 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 240void 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 248extensions::WindowController* PanelHost::GetExtensionWindowController() const { 249 return panel_->extension_window_controller(); 250} 251 252content::WebContents* PanelHost::GetAssociatedWebContents() const { 253 return web_contents_.get(); 254} 255 256void PanelHost::Reload() { 257 content::RecordAction(UserMetricsAction("Reload")); 258 web_contents_->GetController().Reload(true); 259} 260 261void PanelHost::ReloadIgnoringCache() { 262 content::RecordAction(UserMetricsAction("ReloadIgnoringCache")); 263 web_contents_->GetController().ReloadIgnoringCache(true); 264} 265 266void PanelHost::StopLoading() { 267 content::RecordAction(UserMetricsAction("Stop")); 268 web_contents_->Stop(); 269} 270 271void PanelHost::Zoom(content::PageZoom zoom) { 272 chrome_page_zoom::Zoom(web_contents_.get(), zoom); 273} 274