prerender_contents.cc revision 72a454cd3513ac24fbdd0e0cb9ad70b86a99b801
1// Copyright (c) 2011 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/prerender/prerender_contents.h" 6 7#include "base/metrics/histogram.h" 8#include "base/utf_string_conversions.h" 9#include "chrome/browser/background_contents_service.h" 10#include "chrome/browser/browsing_instance.h" 11#include "chrome/browser/prerender/prerender_manager.h" 12#include "chrome/browser/profiles/profile.h" 13#include "chrome/browser/renderer_host/render_view_host.h" 14#include "chrome/browser/renderer_host/site_instance.h" 15#include "chrome/browser/renderer_preferences_util.h" 16#include "chrome/browser/ui/login/login_prompt.h" 17#include "chrome/common/extensions/extension_constants.h" 18#include "chrome/common/notification_service.h" 19#include "chrome/common/url_constants.h" 20#include "chrome/common/view_types.h" 21#include "chrome/common/render_messages.h" 22#include "chrome/common/render_messages_params.h" 23#include "ui/gfx/rect.h" 24 25class PrerenderContentsFactoryImpl : public PrerenderContents::Factory { 26 public: 27 virtual PrerenderContents* CreatePrerenderContents( 28 PrerenderManager* prerender_manager, Profile* profile, const GURL& url, 29 const std::vector<GURL>& alias_urls) { 30 return new PrerenderContents(prerender_manager, profile, url, alias_urls); 31 } 32}; 33 34PrerenderContents::PrerenderContents(PrerenderManager* prerender_manager, 35 Profile* profile, 36 const GURL& url, 37 const std::vector<GURL>& alias_urls) 38 : prerender_manager_(prerender_manager), 39 render_view_host_(NULL), 40 prerender_url_(url), 41 profile_(profile), 42 page_id_(0), 43 has_stopped_loading_(false), 44 final_status_(FINAL_STATUS_MAX) { 45 DCHECK(prerender_manager != NULL); 46 AddAliasURL(prerender_url_); 47 for (std::vector<GURL>::const_iterator it = alias_urls.begin(); 48 it != alias_urls.end(); 49 ++it) { 50 AddAliasURL(*it); 51 } 52} 53 54// static 55PrerenderContents::Factory* PrerenderContents::CreateFactory() { 56 return new PrerenderContentsFactoryImpl(); 57} 58 59void PrerenderContents::StartPrerendering() { 60 DCHECK(profile_ != NULL); 61 SiteInstance* site_instance = SiteInstance::CreateSiteInstance(profile_); 62 render_view_host_ = new RenderViewHost(site_instance, this, MSG_ROUTING_NONE, 63 NULL); 64 render_view_host_->AllowScriptToClose(true); 65 66 // Close ourselves when the application is shutting down. 67 registrar_.Add(this, NotificationType::APP_TERMINATING, 68 NotificationService::AllSources()); 69 70 // Register for our parent profile to shutdown, so we can shut ourselves down 71 // as well (should only be called for OTR profiles, as we should receive 72 // APP_TERMINATING before non-OTR profiles are destroyed). 73 // TODO(tburkard): figure out if this is needed. 74 registrar_.Add(this, NotificationType::PROFILE_DESTROYED, 75 Source<Profile>(profile_)); 76 render_view_host_->CreateRenderView(string16()); 77 78 // Register to cancel if Authentication is required. 79 registrar_.Add(this, NotificationType::AUTH_NEEDED, 80 NotificationService::AllSources()); 81 82 registrar_.Add(this, NotificationType::AUTH_CANCELLED, 83 NotificationService::AllSources()); 84 85 DCHECK(load_start_time_.is_null()); 86 load_start_time_ = base::TimeTicks::Now(); 87 88 ViewMsg_Navigate_Params params; 89 params.url = prerender_url_; 90 params.transition = PageTransition::LINK; 91 params.navigation_type = ViewMsg_Navigate_Params::PRERENDER; 92 render_view_host_->Navigate(params); 93} 94 95void PrerenderContents::set_final_status(FinalStatus final_status) { 96 DCHECK(final_status >= FINAL_STATUS_USED && final_status < FINAL_STATUS_MAX); 97 DCHECK_EQ(FINAL_STATUS_MAX, final_status_); 98 final_status_ = final_status; 99} 100 101PrerenderContents::FinalStatus PrerenderContents::final_status() const { 102 return final_status_; 103} 104 105PrerenderContents::~PrerenderContents() { 106 DCHECK(final_status_ != FINAL_STATUS_MAX); 107 UMA_HISTOGRAM_ENUMERATION("Prerender.FinalStatus", 108 final_status_, 109 FINAL_STATUS_MAX); 110 111 if (!render_view_host_) // Will be null for unit tests. 112 return; 113 114 render_view_host_->Shutdown(); // deletes render_view_host 115} 116 117RenderViewHostDelegate::View* PrerenderContents::GetViewDelegate() { 118 return this; 119} 120 121const GURL& PrerenderContents::GetURL() const { 122 return url_; 123} 124 125ViewType::Type PrerenderContents::GetRenderViewType() const { 126 return ViewType::BACKGROUND_CONTENTS; 127} 128 129int PrerenderContents::GetBrowserWindowID() const { 130 return extension_misc::kUnknownWindowId; 131} 132 133void PrerenderContents::DidNavigate( 134 RenderViewHost* render_view_host, 135 const ViewHostMsg_FrameNavigate_Params& params) { 136 // We only care when the outer frame changes. 137 if (!PageTransition::IsMainFrame(params.transition)) 138 return; 139 140 // Store the navigation params. 141 ViewHostMsg_FrameNavigate_Params* p = new ViewHostMsg_FrameNavigate_Params(); 142 *p = params; 143 navigate_params_.reset(p); 144 145 url_ = params.url; 146 147 AddAliasURL(url_); 148} 149 150void PrerenderContents::UpdateTitle(RenderViewHost* render_view_host, 151 int32 page_id, 152 const std::wstring& title) { 153 if (title.empty()) { 154 return; 155 } 156 157 title_ = WideToUTF16Hack(title); 158 page_id_ = page_id; 159} 160 161void PrerenderContents::RunJavaScriptMessage( 162 const std::wstring& message, 163 const std::wstring& default_prompt, 164 const GURL& frame_url, 165 const int flags, 166 IPC::Message* reply_msg, 167 bool* did_suppress_message) { 168 // Always suppress JavaScript messages if they're triggered by a page being 169 // prerendered. 170 *did_suppress_message = true; 171 // We still want to show the user the message when they navigate to this 172 // page, so cancel this prerender. 173 Destroy(FINAL_STATUS_JAVASCRIPT_ALERT); 174} 175 176bool PrerenderContents::PreHandleKeyboardEvent( 177 const NativeWebKeyboardEvent& event, 178 bool* is_keyboard_shortcut) { 179 return false; 180} 181 182void PrerenderContents::Observe(NotificationType type, 183 const NotificationSource& source, 184 const NotificationDetails& details) { 185 switch (type.value) { 186 case NotificationType::PROFILE_DESTROYED: 187 Destroy(FINAL_STATUS_PROFILE_DESTROYED); 188 return; 189 case NotificationType::APP_TERMINATING: 190 Destroy(FINAL_STATUS_APP_TERMINATING); 191 return; 192 193 case NotificationType::AUTH_NEEDED: 194 case NotificationType::AUTH_CANCELLED: { 195 // Prerendered pages have a NULL controller and the login handler should 196 // be referencing us as the render view host delegate. 197 NavigationController* controller = 198 Source<NavigationController>(source).ptr(); 199 LoginNotificationDetails* details_ptr = 200 Details<LoginNotificationDetails>(details).ptr(); 201 LoginHandler* handler = details_ptr->handler(); 202 DCHECK(handler != NULL); 203 RenderViewHostDelegate* delegate = handler->GetRenderViewHostDelegate(); 204 if (controller == NULL && delegate == this) 205 Destroy(FINAL_STATUS_AUTH_NEEDED); 206 break; 207 } 208 209 default: 210 NOTREACHED() << "Unexpected notification sent."; 211 break; 212 } 213} 214 215void PrerenderContents::OnMessageBoxClosed(IPC::Message* reply_msg, 216 bool success, 217 const std::wstring& prompt) { 218 render_view_host_->JavaScriptMessageBoxClosed(reply_msg, success, prompt); 219} 220 221gfx::NativeWindow PrerenderContents::GetMessageBoxRootWindow() { 222 NOTIMPLEMENTED(); 223 return NULL; 224} 225 226TabContents* PrerenderContents::AsTabContents() { 227 return NULL; 228} 229 230ExtensionHost* PrerenderContents::AsExtensionHost() { 231 return NULL; 232} 233 234void PrerenderContents::UpdateInspectorSetting(const std::string& key, 235 const std::string& value) { 236 RenderViewHostDelegateHelper::UpdateInspectorSetting(profile_, key, value); 237} 238 239void PrerenderContents::ClearInspectorSettings() { 240 RenderViewHostDelegateHelper::ClearInspectorSettings(profile_); 241} 242 243void PrerenderContents::Close(RenderViewHost* render_view_host) { 244 Destroy(FINAL_STATUS_CLOSED); 245} 246 247RendererPreferences PrerenderContents::GetRendererPrefs( 248 Profile* profile) const { 249 RendererPreferences preferences; 250 renderer_preferences_util::UpdateFromSystemSettings(&preferences, profile); 251 return preferences; 252} 253 254WebPreferences PrerenderContents::GetWebkitPrefs() { 255 return RenderViewHostDelegateHelper::GetWebkitPrefs(profile_, 256 false); // is_dom_ui 257} 258 259void PrerenderContents::ProcessWebUIMessage( 260 const ViewHostMsg_DomMessage_Params& params) { 261 render_view_host_->BlockExtensionRequest(params.request_id); 262} 263 264void PrerenderContents::CreateNewWindow( 265 int route_id, 266 const ViewHostMsg_CreateWindow_Params& params) { 267 // Since we don't want to permit child windows that would have a 268 // window.opener property, terminate prerendering. 269 Destroy(FINAL_STATUS_CREATE_NEW_WINDOW); 270} 271 272void PrerenderContents::CreateNewWidget(int route_id, 273 WebKit::WebPopupType popup_type) { 274 NOTREACHED(); 275} 276 277void PrerenderContents::CreateNewFullscreenWidget(int route_id) { 278 NOTREACHED(); 279} 280 281void PrerenderContents::ShowCreatedWindow(int route_id, 282 WindowOpenDisposition disposition, 283 const gfx::Rect& initial_pos, 284 bool user_gesture) { 285 // TODO(tburkard): need to figure out what the correct behavior here is 286 NOTIMPLEMENTED(); 287} 288 289void PrerenderContents::ShowCreatedWidget(int route_id, 290 const gfx::Rect& initial_pos) { 291 NOTIMPLEMENTED(); 292} 293 294void PrerenderContents::ShowCreatedFullscreenWidget(int route_id) { 295 NOTIMPLEMENTED(); 296} 297 298bool PrerenderContents::OnMessageReceived(const IPC::Message& message) { 299 bool handled = true; 300 bool message_is_ok = true; 301 IPC_BEGIN_MESSAGE_MAP_EX(PrerenderContents, message, message_is_ok) 302 IPC_MESSAGE_HANDLER(ViewHostMsg_DidStartProvisionalLoadForFrame, 303 OnDidStartProvisionalLoadForFrame) 304 IPC_MESSAGE_HANDLER(ViewHostMsg_DidRedirectProvisionalLoad, 305 OnDidRedirectProvisionalLoad) 306 IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateFavIconURL, OnUpdateFavIconURL) 307 IPC_MESSAGE_UNHANDLED(handled = false) 308 IPC_END_MESSAGE_MAP_EX() 309 310 return handled; 311} 312 313void PrerenderContents::OnDidStartProvisionalLoadForFrame(int64 frame_id, 314 bool is_main_frame, 315 const GURL& url) { 316 if (is_main_frame) 317 AddAliasURL(url); 318} 319 320void PrerenderContents::OnDidRedirectProvisionalLoad(int32 page_id, 321 const GURL& source_url, 322 const GURL& target_url) { 323 AddAliasURL(target_url); 324} 325 326void PrerenderContents::OnUpdateFavIconURL(int32 page_id, 327 const GURL& icon_url) { 328 icon_url_ = icon_url; 329} 330 331void PrerenderContents::AddAliasURL(const GURL& url) { 332 alias_urls_.push_back(url); 333} 334 335bool PrerenderContents::MatchesURL(const GURL& url) const { 336 return std::find(alias_urls_.begin(), alias_urls_.end(), url) 337 != alias_urls_.end(); 338} 339 340void PrerenderContents::DidStopLoading() { 341 has_stopped_loading_ = true; 342} 343 344void PrerenderContents::Destroy(FinalStatus final_status) { 345 prerender_manager_->RemoveEntry(this); 346 set_final_status(final_status); 347 delete this; 348} 349