Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(6771)

Unified Diff: chrome/browser/prerender/prerender_manager.cc

Issue 10553029: Handle interface to prerenders. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fix a build and a unit test leak Created 8 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/prerender/prerender_manager.cc
diff --git a/chrome/browser/prerender/prerender_manager.cc b/chrome/browser/prerender/prerender_manager.cc
index 5d0409120bd9b15b85f9f769da5bb525017f5737..6eee18a1182ec0649edf7d5c864de602fed8d9fc 100644
--- a/chrome/browser/prerender/prerender_manager.cc
+++ b/chrome/browser/prerender/prerender_manager.cc
@@ -4,7 +4,8 @@
#include "chrome/browser/prerender/prerender_manager.h"
-#include <set>
+#include <algorithm>
+#include <functional>
#include <string>
#include <vector>
@@ -24,6 +25,7 @@
#include "chrome/browser/prerender/prerender_contents.h"
#include "chrome/browser/prerender/prerender_field_trial.h"
#include "chrome/browser/prerender/prerender_final_status.h"
+#include "chrome/browser/prerender/prerender_handle.h"
#include "chrome/browser/prerender/prerender_histograms.h"
#include "chrome/browser/prerender/prerender_history.h"
#include "chrome/browser/prerender/prerender_local_predictor.h"
@@ -106,10 +108,8 @@ bool NeedMatchCompleteDummyForFinalStatus(FinalStatus final_status) {
final_status != FINAL_STATUS_MANAGER_SHUTDOWN &&
final_status != FINAL_STATUS_APP_TERMINATING &&
final_status != FINAL_STATUS_WINDOW_OPENER &&
- final_status != FINAL_STATUS_FRAGMENT_MISMATCH &&
final_status != FINAL_STATUS_CACHE_OR_HISTORY_CLEARED &&
final_status != FINAL_STATUS_CANCELLED &&
- final_status != FINAL_STATUS_SESSION_STORAGE_NAMESPACE_MISMATCH &&
final_status != FINAL_STATUS_DEVTOOLS_ATTACHED &&
final_status != FINAL_STATUS_CROSS_SITE_NAVIGATION_PENDING;
}
@@ -171,18 +171,6 @@ int PrerenderManager::prerenders_per_session_count_ = 0;
PrerenderManager::PrerenderManagerMode PrerenderManager::mode_ =
PRERENDER_MODE_ENABLED;
-struct PrerenderManager::PrerenderContentsData {
- PrerenderContents* contents_;
- base::Time start_time_;
- int active_count_;
- PrerenderContentsData(PrerenderContents* contents, base::Time start_time)
- : contents_(contents),
- start_time_(start_time),
- active_count_(1) {
- CHECK(contents);
- }
-};
-
struct PrerenderManager::NavigationRecord {
GURL url_;
base::TimeTicks time_;
@@ -217,25 +205,32 @@ void PrerenderManager::Shutdown() {
DoShutdown();
}
-bool PrerenderManager::AddPrerenderFromLinkRelPrerender(
+PrerenderHandle* PrerenderManager::AddPrerenderFromLinkRelPrerender(
int process_id,
int route_id,
const GURL& url,
const content::Referrer& referrer,
- gfx::Size size) {
+ const gfx::Size& size) {
#if defined(OS_ANDROID)
// TODO(jcivelli): http://crbug.com/113322 We should have an option to disable
// link-prerender and enable omnibox-prerender only.
return false;
#else
- std::pair<int, int> child_route_id_pair(process_id, route_id);
- PrerenderContentsDataList::iterator it =
- FindPrerenderContentsForChildRouteIdPair(child_route_id_pair);
- if (it != prerender_list_.end()) {
+ DCHECK(!size.IsEmpty());
+ if (PrerenderData* parent_prerender_data =
+ FindPrerenderDataForChildAndRoute(process_id, route_id)) {
// Instead of prerendering from inside of a running prerender, we will defer
// this request until its launcher is made visible.
- it->contents_->AddPendingPrerender(url, referrer, size);
- return true;
+ if (PrerenderContents* contents = parent_prerender_data->contents_) {
+ pending_prerender_list_.push_back(
+ linked_ptr<PrerenderData>(new PrerenderData(this)));
+ PrerenderHandle* prerender_handle =
+ new PrerenderHandle(pending_prerender_list_.back().get());
+ contents->AddPendingPrerender(
+ prerender_handle->weak_ptr_factory_.GetWeakPtr(),
+ url, referrer, size);
+ return prerender_handle;
+ }
}
// Unit tests pass in a process_id == -1.
@@ -243,21 +238,10 @@ bool PrerenderManager::AddPrerenderFromLinkRelPrerender(
if (process_id != -1) {
RenderViewHost* source_render_view_host =
RenderViewHost::FromID(process_id, route_id);
- if (!source_render_view_host || !source_render_view_host->GetView())
- return false;
+ if (!source_render_view_host)
+ return NULL;
session_storage_namespace =
source_render_view_host->GetSessionStorageNamespace();
-
- if (size.IsEmpty()) {
- // Use the size of the tab requesting the prerendering.
- WebContents* web_contents =
- WebContents::FromRenderViewHost(source_render_view_host);
- if (web_contents && web_contents->GetView()) {
- gfx::Rect container_bounds;
- web_contents->GetView()->GetContainerBounds(&container_bounds);
- size = container_bounds.size();
- }
- }
}
return AddPrerender(ORIGIN_LINK_REL_PRERENDER,
@@ -266,44 +250,31 @@ bool PrerenderManager::AddPrerenderFromLinkRelPrerender(
#endif
}
-bool PrerenderManager::AddPrerenderFromOmnibox(
+PrerenderHandle* PrerenderManager::AddPrerenderFromOmnibox(
const GURL& url,
SessionStorageNamespace* session_storage_namespace,
- gfx::Size size) {
+ const gfx::Size& size) {
if (!IsOmniboxEnabled(profile_))
- return false;
- return AddPrerender(ORIGIN_OMNIBOX, -1, url,
- content::Referrer(), size,
+ return NULL;
+ return AddPrerender(ORIGIN_OMNIBOX, -1, url, content::Referrer(), size,
session_storage_namespace);
}
-void PrerenderManager::MaybeCancelPrerender(const GURL& url) {
- PrerenderContentsDataList::iterator it = FindPrerenderContentsForURL(url);
- if (it == prerender_list_.end())
- return;
- PrerenderContentsData& prerender_contents_data = *it;
- if (--prerender_contents_data.active_count_ == 0)
- prerender_contents_data.contents_->Destroy(FINAL_STATUS_CANCELLED);
-}
-
void PrerenderManager::DestroyPrerenderForRenderView(
int process_id, int view_id, FinalStatus final_status) {
DCHECK(CalledOnValidThread());
- PrerenderContentsDataList::iterator it =
- FindPrerenderContentsForChildRouteIdPair(
- std::make_pair(process_id, view_id));
- if (it != prerender_list_.end()) {
- PrerenderContents* prerender_contents = it->contents_;
- prerender_contents->Destroy(final_status);
+ if (PrerenderData* prerender_data =
+ FindPrerenderDataForChildAndRoute(process_id, view_id)) {
+ prerender_data->contents_->Destroy(final_status);
}
}
void PrerenderManager::CancelAllPrerenders() {
DCHECK(CalledOnValidThread());
- while (!prerender_list_.empty()) {
- PrerenderContentsData data = prerender_list_.front();
- DCHECK(data.contents_);
- data.contents_->Destroy(FINAL_STATUS_CANCELLED);
+ while (!active_prerender_list_.empty()) {
+ PrerenderContents* prerender_contents =
+ active_prerender_list_.front()->contents();
+ prerender_contents->Destroy(FINAL_STATUS_CANCELLED);
}
}
@@ -312,27 +283,37 @@ bool PrerenderManager::MaybeUsePrerenderedPage(WebContents* web_contents,
DCHECK(CalledOnValidThread());
DCHECK(!IsWebContentsPrerendering(web_contents));
- scoped_ptr<PrerenderContents> prerender_contents(
- GetEntryButNotSpecifiedWC(url, web_contents));
- if (prerender_contents.get() == NULL)
+ RenderViewHost* old_render_view_host = web_contents->GetRenderViewHost();
+
+ DeleteOldEntries();
+ DeletePendingDeleteEntries();
+ PrerenderData* prerender_data = FindPrerenderData(
+ url, old_render_view_host->GetSessionStorageNamespace());
+ if (!prerender_data)
+ return false;
+ DCHECK(prerender_data->contents_);
+ if (IsNoSwapInExperiment(prerender_data->contents_->experiment_id()))
return false;
+ if (TabContents* new_tab_contents =
+ prerender_data->contents_->prerender_contents()) {
+ if (web_contents == new_tab_contents->web_contents())
+ return false; // Do not swap in to ourself.
+ }
+
+ scoped_ptr<PrerenderContents> prerender_contents(prerender_data->contents_);
+ std::list<linked_ptr<PrerenderData> >::iterator to_erase =
+ FindIteratorForPrerenderContents(prerender_contents.get());
+ DCHECK(active_prerender_list_.end() != to_erase);
+ DCHECK_EQ(prerender_data, to_erase->get());
+ active_prerender_list_.erase(to_erase);
+
// Do not use the prerendered version if there is an opener object.
if (web_contents->HasOpener()) {
prerender_contents.release()->Destroy(FINAL_STATUS_WINDOW_OPENER);
return false;
}
- // Even if we match, the location.hash might be different. Record this as a
- // separate final status.
- GURL matching_url;
- bool url_matches = prerender_contents->MatchesURL(url, &matching_url);
- DCHECK(url_matches);
- if (url_matches && url.ref() != matching_url.ref()) {
- prerender_contents.release()->Destroy(FINAL_STATUS_FRAGMENT_MISMATCH);
- return false;
- }
-
// If we are just in the control group (which can be detected by noticing
// that prerendering hasn't even started yet), record that |web_contents| now
// would be showing a prerendered contents, but otherwise, don't do anything.
@@ -359,22 +340,6 @@ bool PrerenderManager::MaybeUsePrerenderedPage(WebContents* web_contents,
return false;
}
- // If the session storage namespaces don't match, cancel the prerender.
- RenderViewHost* old_render_view_host = web_contents->GetRenderViewHost();
- RenderViewHost* new_render_view_host =
- prerender_contents->prerender_contents()->web_contents()->
- GetRenderViewHost();
- DCHECK(old_render_view_host);
- DCHECK(new_render_view_host);
- if (old_render_view_host->GetSessionStorageNamespace() !=
- new_render_view_host->GetSessionStorageNamespace()) {
- DestroyAndMarkMatchCompleteAsUsed(
- prerender_contents.release(),
- FINAL_STATUS_SESSION_STORAGE_NAMESPACE_MISMATCH);
- return false;
- }
-
- // If we don't want to use prerenders at all, we are done.
// For bookkeeping purposes, we need to mark this WebContents to
// reflect that it would have been prerendered.
if (GetMode() == PRERENDER_MODE_EXPERIMENT_NO_USE_GROUP) {
@@ -393,6 +358,8 @@ bool PrerenderManager::MaybeUsePrerenderedPage(WebContents* web_contents,
if (!prerender_tracker_->TryUse(child_id, route_id))
return false;
+ // At this point, we've determined that we will use the prerender.
+
if (!prerender_contents->load_start_time().is_null()) {
histograms_->RecordTimeUntilUsed(GetCurrentTimeTicks() -
prerender_contents->load_start_time(),
@@ -403,10 +370,17 @@ bool PrerenderManager::MaybeUsePrerenderedPage(WebContents* web_contents,
histograms_->RecordUsedPrerender(prerender_contents->origin());
prerender_contents->set_final_status(FINAL_STATUS_USED);
+ RenderViewHost* new_render_view_host =
+ prerender_contents->prerender_contents()->web_contents()->
+ GetRenderViewHost();
new_render_view_host->Send(
new PrerenderMsg_SetIsPrerendering(new_render_view_host->GetRoutingID(),
false));
+ // Start pending prerender requests from the PrerenderContents, if there are
+ // any.
+ prerender_contents->StartPendingPrerenders();
+
TabContents* new_tab_contents =
prerender_contents->ReleasePrerenderContents();
TabContents* old_tab_contents = TabContents::FromWebContents(web_contents);
@@ -439,10 +413,6 @@ bool PrerenderManager::MaybeUsePrerenderedPage(WebContents* web_contents,
DCHECK(prerender_tab_helper != NULL);
prerender_tab_helper->PrerenderSwappedIn();
- // Start pending prerender requests from the PrerenderContents, if there are
- // any.
- prerender_contents->StartPendingPrerenders();
-
if (old_tab_contents->web_contents()->NeedToFireBeforeUnload()) {
// Schedule the delete to occur after the tab has run its unload handlers.
on_close_tab_contents_deleters_.push_back(
@@ -469,50 +439,46 @@ void PrerenderManager::MoveEntryToPendingDelete(PrerenderContents* entry,
DCHECK_EQ(0, std::count(pending_delete_list_.begin(),
pending_delete_list_.end(), entry));
- for (PrerenderContentsDataList::iterator it = prerender_list_.begin();
- it != prerender_list_.end();
- ++it) {
- if (it->contents_ == entry) {
- bool swapped_in_dummy_replacement = false;
-
- // If this PrerenderContents is being deleted due to a cancellation,
- // we need to create a dummy replacement for PPLT accounting purposes
- // for the Match Complete group.
- // This is the case if the cancellation is for any reason that would not
- // occur in the control group case.
- if (entry->match_complete_status() ==
- PrerenderContents::MATCH_COMPLETE_DEFAULT &&
- NeedMatchCompleteDummyForFinalStatus(final_status) &&
- ActuallyPrerendering()) {
- // TODO(tburkard): I'd like to DCHECK that we are actually prerendering.
- // However, what if new conditions are added and
- // NeedMatchCompleteDummyForFinalStatus, is not being updated. Not sure
- // what's the best thing to do here. For now, I will just check whether
- // we are actually prerendering.
- entry->set_match_complete_status(
- PrerenderContents::MATCH_COMPLETE_REPLACED);
- if (PrerenderContents* dummy_replacement_prerender_contents =
- CreatePrerenderContents(entry->prerender_url(),
- entry->referrer(),
- entry->origin(),
- entry->experiment_id())) {
- dummy_replacement_prerender_contents->set_match_complete_status(
- PrerenderContents::MATCH_COMPLETE_REPLACEMENT_PENDING);
- if (!dummy_replacement_prerender_contents->Init())
- break;
- dummy_replacement_prerender_contents->
- AddAliasURLsFromOtherPrerenderContents(entry);
- dummy_replacement_prerender_contents->set_match_complete_status(
- PrerenderContents::MATCH_COMPLETE_REPLACEMENT);
- it->contents_ = dummy_replacement_prerender_contents;
- swapped_in_dummy_replacement = true;
- }
- }
- if (!swapped_in_dummy_replacement)
- prerender_list_.erase(it);
- break;
+ std::list<linked_ptr<PrerenderData> >::iterator it =
+ FindIteratorForPrerenderContents(entry);
+
+ // If this PrerenderContents is being deleted due to a cancellation,
+ // we need to create a dummy replacement for PPLT accounting purposes
+ // for the Match Complete group.
+ // This is the case if the cancellation is for any reason that would not
+ // occur in the control group case.
+ if (it != active_prerender_list_.end()) {
+ if (entry->match_complete_status() ==
+ PrerenderContents::MATCH_COMPLETE_DEFAULT &&
+ NeedMatchCompleteDummyForFinalStatus(final_status) &&
+ ActuallyPrerendering()) {
+ // TODO(tburkard): I'd like to DCHECK that we are actually prerendering.
+ // However, what if new conditions are added and
+ // NeedMatchCompleteDummyForFinalStatus, is not being updated. Not sure
+ // what's the best thing to do here. For now, I will just check whether
+ // we are actually prerendering.
+ entry->set_match_complete_status(
+ PrerenderContents::MATCH_COMPLETE_REPLACED);
+ PrerenderContents* dummy_replacement_prerender_contents =
+ CreatePrerenderContents(entry->prerender_url(), entry->referrer(),
+ entry->origin(), entry->experiment_id());
+ dummy_replacement_prerender_contents->MakeIntoDummyReplacementOf(entry);
+ DCHECK(dummy_replacement_prerender_contents);
+
+ dummy_replacement_prerender_contents->set_match_complete_status(
+ PrerenderContents::MATCH_COMPLETE_REPLACEMENT_PENDING);
+ DCHECK(dummy_replacement_prerender_contents->Init());
+ dummy_replacement_prerender_contents->
+ AddAliasURLsFromOtherPrerenderContents(entry);
+ dummy_replacement_prerender_contents->set_match_complete_status(
+ PrerenderContents::MATCH_COMPLETE_REPLACEMENT);
+
+ it->get()->contents_ = dummy_replacement_prerender_contents;
+ } else {
+ active_prerender_list_.erase(it);
}
}
+
AddToHistory(entry);
pending_delete_list_.push_back(entry);
@@ -623,10 +589,12 @@ bool PrerenderManager::IsNoUseGroup() {
bool PrerenderManager::IsWebContentsPrerendering(
WebContents* web_contents) const {
DCHECK(CalledOnValidThread());
- for (PrerenderContentsDataList::const_iterator it = prerender_list_.begin();
- it != prerender_list_.end();
+ for (std::list<linked_ptr<PrerenderData> >::const_iterator it =
+ active_prerender_list_.begin();
+ it != active_prerender_list_.end();
++it) {
- TabContents* prerender_tab_contents = it->contents_->prerender_contents();
+ TabContents* prerender_tab_contents =
+ it->get()->contents_->prerender_contents();
if (prerender_tab_contents &&
prerender_tab_contents->web_contents() == web_contents) {
return true;
@@ -647,12 +615,6 @@ bool PrerenderManager::IsWebContentsPrerendering(
return false;
}
-bool PrerenderManager::DidPrerenderFinishLoading(const GURL& url) const {
- DCHECK(CalledOnValidThread());
- PrerenderContents* contents = FindEntry(url);
- return contents ? contents->has_finished_loading() : false;
-}
-
void PrerenderManager::MarkWebContentsAsPrerendered(WebContents* web_contents) {
DCHECK(CalledOnValidThread());
prerendered_tab_contents_set_.insert(web_contents);
@@ -768,22 +730,6 @@ void PrerenderManager::AddCondition(const PrerenderCondition* condition) {
prerender_conditions_.push_back(condition);
}
-bool PrerenderManager::IsPendingEntry(const GURL& url) const {
- DCHECK(CalledOnValidThread());
- for (PrerenderContentsDataList::const_iterator it = prerender_list_.begin();
- it != prerender_list_.end();
- ++it) {
- if (it->contents_->IsPendingEntry(url))
- return true;
- }
- return false;
-}
-
-bool PrerenderManager::IsPrerendering(const GURL& url) const {
- DCHECK(CalledOnValidThread());
- return (FindEntry(url) != NULL);
-}
-
void PrerenderManager::RecordNavigation(const GURL& url) {
DCHECK(CalledOnValidThread());
@@ -792,31 +738,134 @@ void PrerenderManager::RecordNavigation(const GURL& url) {
}
// protected
+PrerenderManager::PrerenderData::PrerenderData(PrerenderManager* manager)
+ : manager_(manager), contents_(NULL), handle_count_(0) {
+}
+
+PrerenderManager::PrerenderData::PrerenderData(PrerenderManager* manager,
+ PrerenderContents* contents)
+ : manager_(manager), contents_(contents), handle_count_(0) {
+}
+
+void PrerenderManager::PrerenderData::OnNewHandle() {
+ DCHECK(contents_ || handle_count_ == 0) <<
+ "Cannot create multiple handles to a pending prerender.";
+ ++handle_count_;
+}
+
+void PrerenderManager::PrerenderData::OnNavigateAwayByHandle() {
+ // TODO(gavinp): Implement reasonable behaviour for navigation away from
+ // launcher. We can't just call OnCancel, because many cases have redirect
+ // chains that will eventually lead to the correct prerendered page, and we
+ // don't want to delete our prerender just as it is going to be used.
+
+ if (!contents_) {
+ DCHECK_EQ(1, handle_count_);
+ // Pending prerenders are not maintained in the active_prerender_list_, so
+ // they will not get normal expiry. Since this prerender hasn't even been
+ // launched yet, and it's held by a page that is being prerendered, we will
+ // just delete it.
+ manager_->DestroyPendingPrerenderData(this);
+ }
+}
+
+void PrerenderManager::PrerenderData::OnCancelByHandle() {
+ DCHECK_LE(1, handle_count_);
+ DCHECK(contents_ || handle_count_ == 1);
+
+ if (--handle_count_ == 0) {
+ if (contents_) {
+ // This will eventually remove this object from active_prerender_list_,
+ // triggering the linked_ptr auto deletion.
+ contents_->Destroy(FINAL_STATUS_CANCELLED);
+ } else {
+ manager_->DestroyPendingPrerenderData(this);
+ }
+ }
+}
+
+PrerenderManager::PrerenderData::~PrerenderData() {
+}
+
void PrerenderManager::SetPrerenderContentsFactory(
PrerenderContents::Factory* prerender_contents_factory) {
DCHECK(CalledOnValidThread());
prerender_contents_factory_.reset(prerender_contents_factory);
}
+void PrerenderManager::StartPendingPrerender(
+ PrerenderHandle* existing_prerender_handle,
+ Origin origin,
+ int process_id,
+ const GURL& url,
+ const content::Referrer& referrer,
+ const gfx::Size& size,
+ content::SessionStorageNamespace* session_storage_namespace) {
+ DCHECK(existing_prerender_handle);
+ DCHECK(existing_prerender_handle->IsValid());
+ DCHECK(existing_prerender_handle->IsPending());
+
+ DVLOG(6) << "StartPendingPrerender";
+ DVLOG(6) << "existing_prerender_handle->handle_count_ = " <<
+ existing_prerender_handle->prerender_data_->handle_count_;
+
+ DCHECK(process_id == -1 || session_storage_namespace);
+
+ scoped_ptr<PrerenderHandle> swap_prerender_handle(AddPrerender(
+ origin, process_id, url, referrer, size, session_storage_namespace));
+ if (swap_prerender_handle.get()) {
+ // AddPrerender has returned a new prerender handle to us. We want to make
+ // |existing_prerender_handle| active, so swap the underlying PrerenderData
+ // between the two handles, and delete our old handle (which will release
+ // our entry in the pending_prerender_list_).
+ existing_prerender_handle->SwapPrerenderDataWith(
+ swap_prerender_handle.get());
+ swap_prerender_handle->OnCancel();
+ return;
+ }
+
+ // We could not start our Prerender. Canceling the existing handle will make
+ // it return false for PrerenderHandle::IsPending(), and will release the
+ // PrerenderData from pending_prerender_list_.
+ existing_prerender_handle->OnCancel();
+}
+
+void PrerenderManager::DestroyPendingPrerenderData(
+ PrerenderData* pending_prerender_data) {
+ for (std::list<linked_ptr<PrerenderData> >::iterator
+ it = pending_prerender_list_.begin();
+ it != pending_prerender_list_.end();
+ ++it) {
+ if (it->get() == pending_prerender_data) {
+ DCHECK_GE(1, it->get()->handle_count_);
+ pending_prerender_list_.erase(it);
+ return;
+ }
+ }
+ NOTREACHED();
+}
+
void PrerenderManager::DoShutdown() {
DestroyAllContents(FINAL_STATUS_MANAGER_SHUTDOWN);
STLDeleteElements(&prerender_conditions_);
on_close_tab_contents_deleters_.reset();
profile_ = NULL;
+
+ DCHECK(active_prerender_list_.empty());
}
// private
-bool PrerenderManager::AddPrerender(
+PrerenderHandle* PrerenderManager::AddPrerender(
Origin origin,
int process_id,
const GURL& url_arg,
const content::Referrer& referrer,
- gfx::Size size,
+ const gfx::Size& size,
SessionStorageNamespace* session_storage_namespace) {
DCHECK(CalledOnValidThread());
if (!IsEnabled())
- return false;
+ return NULL;
if (origin == ORIGIN_LINK_REL_PRERENDER &&
IsGoogleSearchResultURL(referrer.url)) {
@@ -840,10 +889,10 @@ bool PrerenderManager::AddPrerender(
// histogram tracking.
histograms_->RecordPrerender(origin, url_arg);
- if (PrerenderContentsData* prerender_contents_data = FindEntryData(url)) {
- ++prerender_contents_data->active_count_;
+ if (PrerenderData* preexisting_prerender_data =
+ FindPrerenderData(url, session_storage_namespace)) {
RecordFinalStatus(origin, experiment, FINAL_STATUS_DUPLICATE);
- return true;
+ return new PrerenderHandle(preexisting_prerender_data);
}
// Do not prerender if there are too many render processes, and we would
@@ -861,7 +910,7 @@ bool PrerenderManager::AddPrerender(
profile_, url) &&
!content::RenderProcessHost::run_renderer_in_process()) {
RecordFinalStatus(origin, experiment, FINAL_STATUS_TOO_MANY_PROCESSES);
- return false;
+ return NULL;
}
#endif
@@ -871,64 +920,39 @@ bool PrerenderManager::AddPrerender(
// this doesn't make sense as the next prerender request will be triggered
// by a navigation and is unlikely to be the same site.
RecordFinalStatus(origin, experiment, FINAL_STATUS_RATE_LIMIT_EXCEEDED);
- return false;
+ return NULL;
}
PrerenderContents* prerender_contents = CreatePrerenderContents(
url, referrer, origin, experiment);
if (!prerender_contents || !prerender_contents->Init())
- return false;
+ return NULL;
histograms_->RecordPrerenderStarted(origin);
// TODO(cbentzel): Move invalid checks here instead of PrerenderContents?
- PrerenderContentsData data(prerender_contents, GetCurrentTime());
-
- prerender_list_.push_back(data);
+ active_prerender_list_.push_back(
+ linked_ptr<PrerenderData>(new PrerenderData(this, prerender_contents)));
+ PrerenderHandle* prerender_handle =
+ new PrerenderHandle(active_prerender_list_.back().get());
last_prerender_start_time_ = GetCurrentTimeTicks();
- if (size.IsEmpty())
- size = config_.default_tab_bounds.size();
+ gfx::Size contents_size =
+ size.IsEmpty() ? config_.default_tab_bounds.size() : size;
- data.contents_->StartPrerendering(process_id, size, session_storage_namespace,
- control_group_behavior);
+ prerender_contents->StartPrerendering(process_id, contents_size,
+ session_storage_namespace,
+ control_group_behavior);
- while (prerender_list_.size() > config_.max_elements) {
- data = prerender_list_.front();
- prerender_list_.pop_front();
- data.contents_->Destroy(FINAL_STATUS_EVICTED);
+ while (active_prerender_list_.size() > config_.max_elements) {
+ prerender_contents = active_prerender_list_.front()->contents_;
+ DCHECK(prerender_contents);
+ prerender_contents->Destroy(FINAL_STATUS_EVICTED);
}
- StartSchedulingPeriodicCleanups();
- return true;
-}
-
-PrerenderContents* PrerenderManager::GetEntry(const GURL& url) {
- return GetEntryButNotSpecifiedWC(url, NULL);
-}
-PrerenderContents* PrerenderManager::GetEntryButNotSpecifiedWC(
- const GURL& url,
- WebContents* wc) {
- DCHECK(CalledOnValidThread());
- DeleteOldEntries();
- DeletePendingDeleteEntries();
- for (PrerenderContentsDataList::iterator it = prerender_list_.begin();
- it != prerender_list_.end();
- ++it) {
- PrerenderContents* prerender_contents = it->contents_;
- if (prerender_contents->MatchesURL(url, NULL) &&
- !IsNoSwapInExperiment(prerender_contents->experiment_id())) {
- if (!prerender_contents->prerender_contents() ||
- !wc ||
- prerender_contents->prerender_contents()->web_contents() != wc) {
- prerender_list_.erase(it);
- return prerender_contents;
- }
- }
- }
- // Entry not found.
- return NULL;
+ StartSchedulingPeriodicCleanups();
+ return prerender_handle;
}
void PrerenderManager::StartSchedulingPeriodicCleanups() {
@@ -941,10 +965,7 @@ void PrerenderManager::StartSchedulingPeriodicCleanups() {
&PrerenderManager::PeriodicCleanup);
}
-void PrerenderManager::MaybeStopSchedulingPeriodicCleanups() {
- if (!prerender_list_.empty())
- return;
-
+void PrerenderManager::StopSchedulingPeriodicCleanups() {
DCHECK(CalledOnValidThread());
repeating_timer_.Stop();
}
@@ -953,22 +974,22 @@ void PrerenderManager::PeriodicCleanup() {
DCHECK(CalledOnValidThread());
DeleteOldTabContents();
DeleteOldEntries();
+ if (active_prerender_list_.empty())
+ StopSchedulingPeriodicCleanups();
// Grab a copy of the current PrerenderContents pointers, so that we
// will not interfere with potential deletions of the list.
std::vector<PrerenderContents*> prerender_contents;
- for (PrerenderContentsDataList::iterator it = prerender_list_.begin();
- it != prerender_list_.end();
- ++it) {
- DCHECK(it->contents_);
- prerender_contents.push_back(it->contents_);
- }
- for (std::vector<PrerenderContents*>::iterator it =
- prerender_contents.begin();
- it != prerender_contents.end();
- ++it) {
- (*it)->DestroyWhenUsingTooManyResources();
+ prerender_contents.reserve(active_prerender_list_.size());
+ for (std::list<linked_ptr<PrerenderData> >::iterator
+ it = active_prerender_list_.begin();
+ it != active_prerender_list_.end();
+ ++it) {
+ prerender_contents.push_back(it->get()->contents_);
}
+ std::for_each(prerender_contents.begin(), prerender_contents.end(),
+ std::mem_fun(
+ &PrerenderContents::DestroyWhenUsingTooManyResources));
DeletePendingDeleteEntries();
}
@@ -986,21 +1007,20 @@ base::TimeDelta PrerenderManager::GetMaxAge() const {
base::TimeDelta::FromSeconds(300) : config_.max_age);
}
-bool PrerenderManager::IsPrerenderElementFresh(const base::Time start) const {
+bool PrerenderManager::IsPrerenderFresh(const base::TimeTicks start) const {
DCHECK(CalledOnValidThread());
- base::Time now = GetCurrentTime();
- return (now - start < GetMaxAge());
+ return GetCurrentTimeTicks() - start < GetMaxAge();
}
void PrerenderManager::DeleteOldEntries() {
DCHECK(CalledOnValidThread());
- while (!prerender_list_.empty()) {
- PrerenderContentsData data = prerender_list_.front();
- if (IsPrerenderElementFresh(data.start_time_))
+ while (!active_prerender_list_.empty()) {
+ PrerenderContents* contents = active_prerender_list_.front()->contents_;
+ DCHECK(contents);
+ if (IsPrerenderFresh(contents->load_start_time()))
return;
- data.contents_->Destroy(FINAL_STATUS_TIMED_OUT);
+ contents->Destroy(FINAL_STATUS_TIMED_OUT);
}
- MaybeStopSchedulingPeriodicCleanups();
}
base::Time PrerenderManager::GetCurrentTime() const {
@@ -1030,58 +1050,53 @@ void PrerenderManager::DeletePendingDeleteEntries() {
}
}
-PrerenderManager::PrerenderContentsData* PrerenderManager::FindEntryData(
- const GURL& url) {
- DCHECK(CalledOnValidThread());
- PrerenderContentsDataList::iterator it = FindPrerenderContentsForURL(url);
- if (it == prerender_list_.end())
- return NULL;
- PrerenderContentsData& prerender_contents_data = *it;
- return &prerender_contents_data;
-}
-
-PrerenderContents* PrerenderManager::FindEntry(const GURL& url) const {
- DCHECK(CalledOnValidThread());
- for (PrerenderContentsDataList::const_iterator it = prerender_list_.begin();
- it != prerender_list_.end();
+PrerenderManager::PrerenderData* PrerenderManager::FindPrerenderData(
+ const GURL& url,
+ const SessionStorageNamespace* session_storage_namespace) {
+ for (std::list<linked_ptr<PrerenderData> >::iterator
+ it = active_prerender_list_.begin();
+ it != active_prerender_list_.end();
++it) {
- if (it->contents_->MatchesURL(url, NULL))
- return it->contents_;
+ PrerenderContents* prerender_contents = it->get()->contents_;
+ if (prerender_contents->Matches(url, session_storage_namespace))
+ return it->get();
}
- // Entry not found.
return NULL;
}
-PrerenderManager::PrerenderContentsDataList::iterator
- PrerenderManager::FindPrerenderContentsForChildRouteIdPair(
- const std::pair<int, int>& child_route_id_pair) {
- PrerenderContentsDataList::iterator it = prerender_list_.begin();
- for (; it != prerender_list_.end(); ++it) {
- PrerenderContents* prerender_contents = it->contents_;
+PrerenderManager::PrerenderData*
+PrerenderManager::FindPrerenderDataForChildAndRoute(
+ const int child_id, const int route_id) {
+ for (std::list<linked_ptr<PrerenderData> >::iterator
+ it = active_prerender_list_.begin();
+ it != active_prerender_list_.end();
+ ++it) {
+ PrerenderContents* prerender_contents = it->get()->contents_;
- int child_id;
- int route_id;
- bool has_child_id = prerender_contents->GetChildId(&child_id);
- bool has_route_id = has_child_id &&
- prerender_contents->GetRouteId(&route_id);
+ int contents_child_id;
+ if (!prerender_contents->GetChildId(&contents_child_id))
+ continue;
+ int contents_route_id;
+ if (!prerender_contents->GetRouteId(&contents_route_id))
+ continue;
- if (has_child_id && has_route_id &&
- child_id == child_route_id_pair.first &&
- route_id == child_route_id_pair.second) {
- break;
- }
+ if (contents_child_id == child_id && contents_route_id == route_id)
+ return it->get();
}
- return it;
+ return NULL;
}
-PrerenderManager::PrerenderContentsDataList::iterator
- PrerenderManager::FindPrerenderContentsForURL(const GURL& url) {
- for (PrerenderContentsDataList::iterator it = prerender_list_.begin();
- it != prerender_list_.end(); ++it) {
- if (it->contents_->MatchesURL(url, NULL))
+std::list<linked_ptr<PrerenderManager::PrerenderData> >::iterator
+PrerenderManager::FindIteratorForPrerenderContents(
+ PrerenderContents* prerender_contents) {
+ for (std::list<linked_ptr<PrerenderData> >::iterator
+ it = active_prerender_list_.begin();
+ it != active_prerender_list_.end();
+ ++it) {
+ if (prerender_contents == it->get()->contents_)
return it;
}
- return prerender_list_.end();
+ return active_prerender_list_.end();
}
bool PrerenderManager::DoesRateLimitAllowPrerender() const {
@@ -1143,23 +1158,21 @@ void PrerenderManager::AddToHistory(PrerenderContents* contents) {
Value* PrerenderManager::GetActivePrerendersAsValue() const {
ListValue* list_value = new ListValue();
- for (PrerenderContentsDataList::const_iterator it = prerender_list_.begin();
- it != prerender_list_.end();
+ for (std::list<linked_ptr<PrerenderData> >::const_iterator it =
+ active_prerender_list_.begin();
+ it != active_prerender_list_.end();
++it) {
- Value* prerender_value = it->contents_->GetAsValue();
- if (!prerender_value)
- continue;
- list_value->Append(prerender_value);
+ if (Value* prerender_value = it->get()->contents_->GetAsValue())
+ list_value->Append(prerender_value);
}
return list_value;
}
void PrerenderManager::DestroyAllContents(FinalStatus final_status) {
DeleteOldTabContents();
- while (!prerender_list_.empty()) {
- PrerenderContentsData data = prerender_list_.front();
- prerender_list_.pop_front();
- data.contents_->Destroy(final_status);
+ while (!active_prerender_list_.empty()) {
+ PrerenderContents* contents = active_prerender_list_.front()->contents_;
+ contents->Destroy(final_status);
}
DeletePendingDeleteEntries();
}
@@ -1218,3 +1231,4 @@ PrerenderManager* FindPrerenderManagerUsingRenderProcessId(
}
} // namespace prerender
+

Powered by Google App Engine
This is Rietveld 408576698