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.
5 #include "chrome/browser/prerender/prerender_contents.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "chrome/browser/chrome_notification_types.h"
13 #include "chrome/browser/favicon/favicon_tab_helper.h"
14 #include "chrome/browser/history/history_tab_helper.h"
15 #include "chrome/browser/history/history_types.h"
16 #include "chrome/browser/prerender/prerender_field_trial.h"
17 #include "chrome/browser/prerender/prerender_final_status.h"
18 #include "chrome/browser/prerender/prerender_handle.h"
19 #include "chrome/browser/prerender/prerender_manager.h"
20 #include "chrome/browser/prerender/prerender_tracker.h"
21 #include "chrome/browser/profiles/profile.h"
22 #include "chrome/browser/ui/browser.h"
23 #include "chrome/browser/ui/browser_tab_contents.h"
24 #include "chrome/common/prerender_messages.h"
25 #include "chrome/common/render_messages.h"
26 #include "chrome/common/url_constants.h"
27 #include "content/public/browser/browser_child_process_host.h"
28 #include "content/public/browser/notification_service.h"
29 #include "content/public/browser/render_process_host.h"
30 #include "content/public/browser/render_view_host.h"
31 #include "content/public/browser/resource_request_details.h"
32 #include "content/public/browser/session_storage_namespace.h"
33 #include "content/public/browser/web_contents.h"
34 #include "content/public/browser/web_contents_delegate.h"
35 #include "content/public/browser/web_contents_view.h"
36 #include "content/public/common/favicon_url.h"
37 #include "content/public/common/frame_navigate_params.h"
38 #include "ui/gfx/rect.h"
40 using content::DownloadItem;
41 using content::OpenURLParams;
42 using content::RenderViewHost;
43 using content::ResourceRedirectDetails;
44 using content::SessionStorageNamespace;
45 using content::WebContents;
49 class PrerenderContentsFactoryImpl : public PrerenderContents::Factory {
51 virtual PrerenderContents* CreatePrerenderContents(
52 PrerenderManager* prerender_manager, Profile* profile,
53 const GURL& url, const content::Referrer& referrer,
54 Origin origin, uint8 experiment_id) OVERRIDE {
55 return new PrerenderContents(prerender_manager, profile,
56 url, referrer, origin, experiment_id);
60 // WebContentsDelegateImpl -----------------------------------------------------
62 class PrerenderContents::WebContentsDelegateImpl
63 : public content::WebContentsDelegate {
65 explicit WebContentsDelegateImpl(PrerenderContents* prerender_contents)
66 : prerender_contents_(prerender_contents) {
69 // content::WebContentsDelegate implementation:
70 virtual WebContents* OpenURLFromTab(WebContents* source,
71 const OpenURLParams& params) OVERRIDE {
72 // |OpenURLFromTab| is typically called when a frame performs a navigation
73 // that requires the browser to perform the transition instead of WebKit.
74 // Examples include prerendering a site that redirects to an app URL,
75 // or if --enable-strict-site-isolation is specified and the prerendered
76 // frame redirects to a different origin.
77 // TODO(cbentzel): Consider supporting this if it is a common case during
79 prerender_contents_->Destroy(FINAL_STATUS_OPEN_URL);
83 virtual void CanDownload(
84 RenderViewHost* render_view_host,
86 const std::string& request_method,
87 const base::Callback<void(bool)>& callback) OVERRIDE {
88 prerender_contents_->Destroy(FINAL_STATUS_DOWNLOAD);
89 // Cancel the download.
93 virtual bool OnGoToEntryOffset(int offset) OVERRIDE {
94 // This isn't allowed because the history merge operation
95 // does not work if there are renderer issued challenges.
96 // TODO(cbentzel): Cancel in this case? May not need to do
97 // since render-issued offset navigations are not guaranteed,
98 // but indicates that the page cares about the history.
102 virtual void JSOutOfMemory(WebContents* tab) OVERRIDE {
103 prerender_contents_->Destroy(FINAL_STATUS_JS_OUT_OF_MEMORY);
106 virtual bool ShouldSuppressDialogs() OVERRIDE {
107 // We still want to show the user the message when they navigate to this
108 // page, so cancel this prerender.
109 prerender_contents_->Destroy(FINAL_STATUS_JAVASCRIPT_ALERT);
110 // Always suppress JavaScript messages if they're triggered by a page being
115 virtual void RegisterProtocolHandler(WebContents* web_contents,
116 const std::string& protocol,
118 const string16& title,
119 bool user_gesture) OVERRIDE {
120 // TODO(mmenke): Consider supporting this if it is a common case during
122 prerender_contents_->Destroy(FINAL_STATUS_REGISTER_PROTOCOL_HANDLER);
126 PrerenderContents* prerender_contents_;
129 void PrerenderContents::Observer::OnPrerenderStopLoading(
130 PrerenderContents* contents) {
133 void PrerenderContents::Observer::OnPrerenderCreatedMatchCompleteReplacement(
134 PrerenderContents* contents, PrerenderContents* replacement) {
137 PrerenderContents::Observer::Observer() {
140 PrerenderContents::Observer::~Observer() {
143 PrerenderContents::PendingPrerenderInfo::PendingPrerenderInfo(
144 base::WeakPtr<PrerenderHandle> weak_prerender_handle,
147 const content::Referrer& referrer,
148 const gfx::Size& size)
149 : weak_prerender_handle(weak_prerender_handle),
156 PrerenderContents::PendingPrerenderInfo::~PendingPrerenderInfo() {
159 void PrerenderContents::AddPendingPrerender(
160 scoped_ptr<PendingPrerenderInfo> pending_prerender_info) {
161 pending_prerenders_.push_back(pending_prerender_info.release());
164 void PrerenderContents::PrepareForUse() {
165 NotifyPrerenderStop();
167 SessionStorageNamespace* session_storage_namespace = NULL;
168 if (prerender_contents_) {
169 // TODO(ajwong): This does not correctly handle storage for isolated apps.
170 session_storage_namespace = prerender_contents_->
171 GetController().GetDefaultSessionStorageNamespace();
173 prerender_manager_->StartPendingPrerenders(
174 child_id_, &pending_prerenders_, session_storage_namespace);
175 pending_prerenders_.clear();
178 PrerenderContents::PrerenderContents(
179 PrerenderManager* prerender_manager,
182 const content::Referrer& referrer,
185 : prerendering_has_started_(false),
186 prerender_manager_(prerender_manager),
191 session_storage_namespace_id_(-1),
192 has_stopped_loading_(false),
193 has_finished_loading_(false),
194 final_status_(FINAL_STATUS_MAX),
195 match_complete_status_(MATCH_COMPLETE_DEFAULT),
196 prerendering_has_been_cancelled_(false),
200 experiment_id_(experiment_id),
201 creator_child_id_(-1) {
202 DCHECK(prerender_manager != NULL);
205 PrerenderContents* PrerenderContents::CreateMatchCompleteReplacement() {
206 PrerenderContents* new_contents = prerender_manager_->CreatePrerenderContents(
207 prerender_url(), referrer(), origin(), experiment_id());
209 new_contents->load_start_time_ = load_start_time_;
210 new_contents->session_storage_namespace_id_ = session_storage_namespace_id_;
211 new_contents->set_match_complete_status(
212 PrerenderContents::MATCH_COMPLETE_REPLACEMENT_PENDING);
214 const bool did_init = new_contents->Init();
216 DCHECK_EQ(alias_urls_.front(), new_contents->alias_urls_.front());
217 DCHECK_EQ(1u, new_contents->alias_urls_.size());
218 new_contents->alias_urls_ = alias_urls_;
219 new_contents->set_match_complete_status(
220 PrerenderContents::MATCH_COMPLETE_REPLACEMENT);
221 NotifyPrerenderCreatedMatchCompleteReplacement(new_contents);
225 bool PrerenderContents::Init() {
226 return AddAliasURL(prerender_url_);
230 PrerenderContents::Factory* PrerenderContents::CreateFactory() {
231 return new PrerenderContentsFactoryImpl();
234 void PrerenderContents::StartPrerendering(
235 int creator_child_id,
236 const gfx::Size& size,
237 SessionStorageNamespace* session_storage_namespace) {
238 DCHECK(profile_ != NULL);
239 DCHECK(!size.IsEmpty());
240 DCHECK(!prerendering_has_started_);
241 DCHECK(prerender_contents_.get() == NULL);
242 DCHECK_EQ(-1, creator_child_id_);
243 DCHECK(size_.IsEmpty());
244 DCHECK_EQ(1U, alias_urls_.size());
246 creator_child_id_ = creator_child_id;
247 session_storage_namespace_id_ = session_storage_namespace->id();
250 DCHECK(load_start_time_.is_null());
251 load_start_time_ = base::TimeTicks::Now();
253 // Everything after this point sets up the WebContents object and associated
254 // RenderView for the prerender page. Don't do this for members of the
256 if (prerender_manager_->IsControlGroup(experiment_id()))
259 if (origin_ == ORIGIN_LOCAL_PREDICTOR &&
260 IsLocalPredictorPrerenderAlwaysControlEnabled()) {
264 prerendering_has_started_ = true;
266 prerender_contents_.reset(CreateWebContents(session_storage_namespace));
267 BrowserTabContents::AttachTabHelpers(prerender_contents_.get());
268 #if defined(OS_ANDROID)
269 // Delay icon fetching until the contents are getting swapped in
270 // to conserve network usage in mobile devices.
271 FaviconTabHelper::FromWebContents(
272 prerender_contents_.get())->set_should_fetch_icons(false);
273 #endif // defined(OS_ANDROID)
274 content::WebContentsObserver::Observe(prerender_contents_.get());
276 web_contents_delegate_.reset(new WebContentsDelegateImpl(this));
277 prerender_contents_.get()->SetDelegate(web_contents_delegate_.get());
278 // Set the size of the prerender WebContents.
279 prerender_contents_->GetView()->SizeContents(size_);
281 child_id_ = GetRenderViewHost()->GetProcess()->GetID();
282 route_id_ = GetRenderViewHost()->GetRoutingID();
284 // For Local Predictor based prerendering, log transactions to see if we could
285 // merge session storage namespaces in the event of a mismatch.
286 if (origin_ == ORIGIN_LOCAL_PREDICTOR)
287 session_storage_namespace->AddTransactionLogProcessId(child_id_);
289 // Register this with the ResourceDispatcherHost as a prerender
290 // RenderViewHost. This must be done before the Navigate message to catch all
291 // resource requests, but as it is on the same thread as the Navigate message
292 // (IO) there is no race condition.
293 AddObserver(prerender_manager()->prerender_tracker());
294 NotifyPrerenderStart();
296 // Close ourselves when the application is shutting down.
297 notification_registrar_.Add(this, chrome::NOTIFICATION_APP_TERMINATING,
298 content::NotificationService::AllSources());
300 // Register for our parent profile to shutdown, so we can shut ourselves down
301 // as well (should only be called for OTR profiles, as we should receive
302 // APP_TERMINATING before non-OTR profiles are destroyed).
303 // TODO(tburkard): figure out if this is needed.
304 notification_registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED,
305 content::Source<Profile>(profile_));
307 // Register to inform new RenderViews that we're prerendering.
308 notification_registrar_.Add(
309 this, content::NOTIFICATION_WEB_CONTENTS_RENDER_VIEW_HOST_CREATED,
310 content::Source<WebContents>(prerender_contents_.get()));
312 // Transfer over the user agent override.
313 prerender_contents_.get()->SetUserAgentOverride(
314 prerender_manager_->config().user_agent_override);
316 content::NavigationController::LoadURLParams load_url_params(
318 load_url_params.referrer = referrer_;
319 load_url_params.transition_type = (origin_ == ORIGIN_OMNIBOX ?
320 content::PAGE_TRANSITION_TYPED : content::PAGE_TRANSITION_LINK);
321 load_url_params.override_user_agent =
322 prerender_manager_->config().is_overriding_user_agent ?
323 content::NavigationController::UA_OVERRIDE_TRUE :
324 content::NavigationController::UA_OVERRIDE_FALSE;
325 prerender_contents_.get()->GetController().LoadURLWithParams(load_url_params);
328 bool PrerenderContents::GetChildId(int* child_id) const {
330 DCHECK_GE(child_id_, -1);
331 *child_id = child_id_;
332 return child_id_ != -1;
335 bool PrerenderContents::GetRouteId(int* route_id) const {
337 DCHECK_GE(route_id_, -1);
338 *route_id = route_id_;
339 return route_id_ != -1;
342 void PrerenderContents::SetFinalStatus(FinalStatus final_status) {
343 DCHECK(final_status >= FINAL_STATUS_USED && final_status < FINAL_STATUS_MAX);
344 DCHECK(final_status_ == FINAL_STATUS_MAX);
346 final_status_ = final_status;
349 PrerenderContents::~PrerenderContents() {
350 DCHECK_NE(FINAL_STATUS_MAX, final_status());
352 prerendering_has_been_cancelled() || final_status() == FINAL_STATUS_USED);
353 DCHECK_NE(ORIGIN_MAX, origin());
355 prerender_manager_->RecordFinalStatusWithMatchCompleteStatus(
356 origin(), experiment_id(), match_complete_status(), final_status());
358 // Broadcast the removal of aliases.
359 for (content::RenderProcessHost::iterator host_iterator =
360 content::RenderProcessHost::AllHostsIterator();
361 !host_iterator.IsAtEnd();
362 host_iterator.Advance()) {
363 content::RenderProcessHost* host = host_iterator.GetCurrentValue();
364 host->Send(new PrerenderMsg_OnPrerenderRemoveAliases(alias_urls_));
367 // If we still have a WebContents, clean up anything we need to and then
369 if (prerender_contents_.get())
370 delete ReleasePrerenderContents();
373 void PrerenderContents::AddObserver(Observer* observer) {
374 DCHECK_EQ(FINAL_STATUS_MAX, final_status_);
375 observer_list_.AddObserver(observer);
378 void PrerenderContents::RemoveObserver(Observer* observer) {
379 observer_list_.RemoveObserver(observer);
382 void PrerenderContents::Observe(int type,
383 const content::NotificationSource& source,
384 const content::NotificationDetails& details) {
386 case chrome::NOTIFICATION_PROFILE_DESTROYED:
387 Destroy(FINAL_STATUS_PROFILE_DESTROYED);
390 case chrome::NOTIFICATION_APP_TERMINATING:
391 Destroy(FINAL_STATUS_APP_TERMINATING);
394 case content::NOTIFICATION_WEB_CONTENTS_RENDER_VIEW_HOST_CREATED: {
395 if (prerender_contents_.get()) {
396 DCHECK_EQ(content::Source<WebContents>(source).ptr(),
397 prerender_contents_.get());
399 content::Details<RenderViewHost> new_render_view_host(details);
400 OnRenderViewHostCreated(new_render_view_host.ptr());
402 // When a new RenderView is created for a prerendering WebContents,
403 // tell the new RenderView it's being used for prerendering before any
404 // navigations occur. Note that this is always triggered before the
405 // first navigation, so there's no need to send the message just after
406 // the WebContents is created.
407 new_render_view_host->Send(
408 new PrerenderMsg_SetIsPrerendering(
409 new_render_view_host->GetRoutingID(),
412 // Make sure the size of the RenderViewHost has been passed to the new
413 // RenderView. Otherwise, the size may not be sent until the
414 // RenderViewReady event makes it from the render process to the UI
415 // thread of the browser process. When the RenderView receives its
416 // size, is also sets itself to be visible, which would then break the
418 new_render_view_host->WasResized();
419 prerender_contents_->WasHidden();
425 NOTREACHED() << "Unexpected notification sent.";
430 void PrerenderContents::OnRenderViewHostCreated(
431 RenderViewHost* new_render_view_host) {
434 size_t PrerenderContents::pending_prerender_count() const {
435 return pending_prerenders_.size();
438 WebContents* PrerenderContents::CreateWebContents(
439 SessionStorageNamespace* session_storage_namespace) {
440 // TODO(ajwong): Remove the temporary map once prerendering is aware of
441 // multiple session storage namespaces per tab.
442 content::SessionStorageNamespaceMap session_storage_namespace_map;
443 session_storage_namespace_map[std::string()] = session_storage_namespace;
444 return WebContents::CreateWithSessionStorage(
445 WebContents::CreateParams(profile_), session_storage_namespace_map);
448 void PrerenderContents::NotifyPrerenderStart() {
449 DCHECK_EQ(FINAL_STATUS_MAX, final_status_);
450 FOR_EACH_OBSERVER(Observer, observer_list_, OnPrerenderStart(this));
453 void PrerenderContents::NotifyPrerenderStopLoading() {
454 FOR_EACH_OBSERVER(Observer, observer_list_, OnPrerenderStopLoading(this));
457 void PrerenderContents::NotifyPrerenderStop() {
458 DCHECK_NE(FINAL_STATUS_MAX, final_status_);
459 FOR_EACH_OBSERVER(Observer, observer_list_, OnPrerenderStop(this));
460 observer_list_.Clear();
463 void PrerenderContents::NotifyPrerenderCreatedMatchCompleteReplacement(
464 PrerenderContents* replacement) {
465 FOR_EACH_OBSERVER(Observer, observer_list_,
466 OnPrerenderCreatedMatchCompleteReplacement(this,
470 void PrerenderContents::DidUpdateFaviconURL(
472 const std::vector<content::FaviconURL>& urls) {
473 VLOG(1) << "PrerenderContents::OnUpdateFaviconURL" << icon_url_;
474 for (std::vector<content::FaviconURL>::const_iterator it = urls.begin();
475 it != urls.end(); ++it) {
476 if (it->icon_type == content::FaviconURL::FAVICON) {
477 icon_url_ = it->icon_url;
478 VLOG(1) << icon_url_;
484 bool PrerenderContents::OnMessageReceived(const IPC::Message& message) {
486 // The following messages we do want to consume.
487 IPC_BEGIN_MESSAGE_MAP(PrerenderContents, message)
488 IPC_MESSAGE_HANDLER(ChromeViewHostMsg_CancelPrerenderForPrinting,
489 OnCancelPrerenderForPrinting)
490 IPC_MESSAGE_UNHANDLED(handled = false)
491 IPC_END_MESSAGE_MAP()
496 bool PrerenderContents::CheckURL(const GURL& url) {
497 const bool http = url.SchemeIs(content::kHttpScheme);
498 const bool https = url.SchemeIs(content::kHttpsScheme);
499 if (!http && !https) {
500 DCHECK_NE(MATCH_COMPLETE_REPLACEMENT_PENDING, match_complete_status_);
501 Destroy(FINAL_STATUS_UNSUPPORTED_SCHEME);
504 if (https && !prerender_manager_->config().https_allowed) {
505 DCHECK_NE(MATCH_COMPLETE_REPLACEMENT_PENDING, match_complete_status_);
506 Destroy(FINAL_STATUS_HTTPS);
509 if (match_complete_status_ != MATCH_COMPLETE_REPLACEMENT_PENDING &&
510 prerender_manager_->HasRecentlyBeenNavigatedTo(origin(), url)) {
511 Destroy(FINAL_STATUS_RECENTLY_VISITED);
517 bool PrerenderContents::AddAliasURL(const GURL& url) {
521 alias_urls_.push_back(url);
523 for (content::RenderProcessHost::iterator host_iterator =
524 content::RenderProcessHost::AllHostsIterator();
525 !host_iterator.IsAtEnd();
526 host_iterator.Advance()) {
527 content::RenderProcessHost* host = host_iterator.GetCurrentValue();
528 host->Send(new PrerenderMsg_OnPrerenderAddAlias(url));
534 bool PrerenderContents::Matches(
536 const SessionStorageNamespace* session_storage_namespace) const {
537 if (session_storage_namespace &&
538 session_storage_namespace_id_ != session_storage_namespace->id()) {
541 return std::count_if(alias_urls_.begin(), alias_urls_.end(),
542 std::bind2nd(std::equal_to<GURL>(), url)) != 0;
545 void PrerenderContents::RenderProcessGone(base::TerminationStatus status) {
546 Destroy(FINAL_STATUS_RENDERER_CRASHED);
549 void PrerenderContents::DidStopLoading(
550 content::RenderViewHost* render_view_host) {
551 has_stopped_loading_ = true;
552 NotifyPrerenderStopLoading();
555 void PrerenderContents::DidStartProvisionalLoadForFrame(
557 int64 parent_frame_id,
559 const GURL& validated_url,
561 bool is_iframe_srcdoc,
562 RenderViewHost* render_view_host) {
564 if (!CheckURL(validated_url))
567 // Usually, this event fires if the user clicks or enters a new URL.
568 // Neither of these can happen in the case of an invisible prerender.
569 // So the cause is: Some JavaScript caused a new URL to be loaded. In that
570 // case, the spinner would start again in the browser, so we must reset
571 // has_stopped_loading_ so that the spinner won't be stopped.
572 has_stopped_loading_ = false;
573 has_finished_loading_ = false;
577 void PrerenderContents::DidFinishLoad(int64 frame_id,
578 const GURL& validated_url,
580 RenderViewHost* render_view_host) {
582 has_finished_loading_ = true;
585 void PrerenderContents::DidNavigateMainFrame(
586 const content::LoadCommittedDetails& details,
587 const content::FrameNavigateParams& params) {
588 // Add each redirect as an alias. |params.url| is included in
589 // |params.redirects|.
591 // TODO(davidben): We do not correctly patch up history for renderer-initated
592 // navigations which add history entries. http://crbug.com/305660.
593 for (size_t i = 0; i < params.redirects.size(); i++) {
594 if (!AddAliasURL(params.redirects[i]))
599 void PrerenderContents::DidGetRedirectForResourceRequest(
600 const content::ResourceRedirectDetails& details) {
601 // DidGetRedirectForResourceRequest can come for any resource on a page. If
602 // it's a redirect on the top-level resource, the name needs to be remembered
603 // for future matching, and if it redirects to an https resource, it needs to
604 // be canceled. If a subresource is redirected, nothing changes.
605 if (details.resource_type != ResourceType::MAIN_FRAME)
607 CheckURL(details.new_url);
610 void PrerenderContents::Destroy(FinalStatus final_status) {
611 DCHECK_NE(final_status, FINAL_STATUS_USED);
613 if (prerendering_has_been_cancelled_)
616 if (child_id_ != -1 && route_id_ != -1) {
617 // Cancel the prerender in the PrerenderTracker. This is needed
618 // because destroy may be called directly from the UI thread without calling
619 // TryCancel(). This is difficult to completely avoid, since prerendering
620 // can be cancelled before a RenderView is created.
621 bool is_cancelled = prerender_manager()->prerender_tracker()->TryCancel(
622 child_id_, route_id_, final_status);
625 // A different final status may have been set already from another thread.
626 // If so, use it instead.
627 if (!prerender_manager()->prerender_tracker()->
628 GetFinalStatus(child_id_, route_id_, &final_status)) {
632 SetFinalStatus(final_status);
634 prerendering_has_been_cancelled_ = true;
635 prerender_manager_->AddToHistory(this);
636 prerender_manager_->MoveEntryToPendingDelete(this, final_status);
638 // Note that if this PrerenderContents was made into a MatchComplete
639 // replacement by MoveEntryToPendingDelete, NotifyPrerenderStop will
640 // not reach the PrerenderHandle. Rather
641 // OnPrerenderCreatedMatchCompleteReplacement will propogate that
642 // information to the referer.
643 if (!prerender_manager_->IsControlGroup(experiment_id()) &&
644 (prerendering_has_started() ||
645 match_complete_status() == MATCH_COMPLETE_REPLACEMENT)) {
646 NotifyPrerenderStop();
650 base::ProcessMetrics* PrerenderContents::MaybeGetProcessMetrics() {
651 if (process_metrics_.get() == NULL) {
652 // If a PrenderContents hasn't started prerending, don't be fully formed.
653 if (!GetRenderViewHost() || !GetRenderViewHost()->GetProcess())
655 base::ProcessHandle handle = GetRenderViewHost()->GetProcess()->GetHandle();
656 if (handle == base::kNullProcessHandle)
658 #if !defined(OS_MACOSX)
659 process_metrics_.reset(base::ProcessMetrics::CreateProcessMetrics(handle));
661 process_metrics_.reset(base::ProcessMetrics::CreateProcessMetrics(
663 content::BrowserChildProcessHost::GetPortProvider()));
667 return process_metrics_.get();
670 void PrerenderContents::DestroyWhenUsingTooManyResources() {
671 base::ProcessMetrics* metrics = MaybeGetProcessMetrics();
675 size_t private_bytes, shared_bytes;
676 if (metrics->GetMemoryBytes(&private_bytes, &shared_bytes) &&
677 private_bytes > prerender_manager_->config().max_bytes) {
678 Destroy(FINAL_STATUS_MEMORY_LIMIT_EXCEEDED);
682 WebContents* PrerenderContents::ReleasePrerenderContents() {
683 prerender_contents_->SetDelegate(NULL);
684 content::WebContentsObserver::Observe(NULL);
685 SessionStorageNamespace* session_storage_namespace =
686 GetSessionStorageNamespace();
687 if (session_storage_namespace && origin_ == ORIGIN_LOCAL_PREDICTOR)
688 session_storage_namespace->RemoveTransactionLogProcessId(child_id_);
689 return prerender_contents_.release();
692 RenderViewHost* PrerenderContents::GetRenderViewHostMutable() {
693 return const_cast<RenderViewHost*>(GetRenderViewHost());
696 const RenderViewHost* PrerenderContents::GetRenderViewHost() const {
697 if (!prerender_contents_.get())
699 return prerender_contents_->GetRenderViewHost();
702 void PrerenderContents::DidNavigate(
703 const history::HistoryAddPageArgs& add_page_args) {
704 add_page_vector_.push_back(add_page_args);
707 void PrerenderContents::CommitHistory(WebContents* tab) {
708 HistoryTabHelper* history_tab_helper = HistoryTabHelper::FromWebContents(tab);
709 for (size_t i = 0; i < add_page_vector_.size(); ++i)
710 history_tab_helper->UpdateHistoryForNavigation(add_page_vector_[i]);
713 Value* PrerenderContents::GetAsValue() const {
714 if (!prerender_contents_.get())
716 DictionaryValue* dict_value = new DictionaryValue();
717 dict_value->SetString("url", prerender_url_.spec());
718 base::TimeTicks current_time = base::TimeTicks::Now();
719 base::TimeDelta duration = current_time - load_start_time_;
720 dict_value->SetInteger("duration", duration.InSeconds());
721 dict_value->SetBoolean("is_loaded", prerender_contents_ &&
722 !prerender_contents_->IsLoading());
726 bool PrerenderContents::IsCrossSiteNavigationPending() const {
727 if (!prerender_contents_)
729 return (prerender_contents_->GetSiteInstance() !=
730 prerender_contents_->GetPendingSiteInstance());
733 SessionStorageNamespace* PrerenderContents::GetSessionStorageNamespace() const {
734 if (!prerender_contents())
736 return prerender_contents()->GetController().
737 GetDefaultSessionStorageNamespace();
740 void PrerenderContents::OnCancelPrerenderForPrinting() {
741 Destroy(FINAL_STATUS_WINDOW_PRINT);
744 } // namespace prerender