Index: chrome/browser/prerender/prerender_manager.cc |
diff --git a/chrome/browser/prerender/prerender_manager.cc b/chrome/browser/prerender/prerender_manager.cc |
index d287698a04a97350fd78f1cd94b7996ba10f5fa2..2a8aa1494a5dc21ef3445e6c76282479dc649a7a 100644 |
--- a/chrome/browser/prerender/prerender_manager.cc |
+++ b/chrome/browser/prerender/prerender_manager.cc |
@@ -63,6 +63,17 @@ struct PrerenderManager::PrerenderContentsData { |
} |
}; |
+struct PrerenderManager::PendingContentsData { |
+ PendingContentsData(const GURL& url, const std::vector<GURL>& alias_urls, |
+ const GURL& referrer) |
+ : url_(url), alias_urls_(alias_urls), referrer_(referrer) { } |
+ ~PendingContentsData() {} |
+ GURL url_; |
+ std::vector<GURL> alias_urls_; |
+ GURL referrer_; |
+}; |
+ |
+ |
PrerenderManager::PrerenderManager(Profile* profile) |
: rate_limit_enabled_(true), |
profile_(profile), |
@@ -95,6 +106,7 @@ bool PrerenderManager::AddPreload(const GURL& url, |
DeleteOldEntries(); |
if (FindEntry(url)) |
return false; |
+ |
// Do not prerender if there are too many render processes, and we would |
// have to use an existing one. We do not want prerendering to happen in |
// a shared process, so that we can always reliably lower the CPU |
@@ -114,6 +126,7 @@ bool PrerenderManager::AddPreload(const GURL& url, |
// 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(FINAL_STATUS_RATE_LIMIT_EXCEEDED); |
+ |
return false; |
} |
@@ -135,6 +148,52 @@ bool PrerenderManager::AddPreload(const GURL& url, |
return true; |
} |
+void PrerenderManager::AddPendingPreload( |
+ const std::pair<int,int>& child_route_id_pair, |
+ const GURL& url, |
+ const std::vector<GURL>& alias_urls, |
+ const GURL& referrer) { |
+ // Check if this is coming from a valid prerender rvh. |
+ bool is_valid_prerender = false; |
+ for (std::list<PrerenderContentsData>::iterator it = prerender_list_.begin(); |
+ it != prerender_list_.end(); ++it) { |
+ PrerenderContents* pc = it->contents_; |
+ |
+ int child_id; |
+ int route_id; |
+ bool has_child_id = pc->GetChildId(&child_id); |
+ bool has_route_id = has_child_id && pc->GetRouteId(&route_id); |
+ |
+ if (has_child_id && has_route_id && |
+ child_id == child_route_id_pair.first && |
+ route_id == child_route_id_pair.second) { |
+ is_valid_prerender = true; |
+ break; |
+ } |
+ } |
+ |
+ // If not, we could check to see if the RenderViewHost specified by the |
+ // child_route_id_pair exists and if so just start prerendering, as this |
+ // suggests that the link was clicked, though this might prerender something |
+ // that the user has already navigated away from. For now, we'll be |
+ // conservative and skip the prerender which will mean some prerender requests |
+ // from prerendered pages will be missed if the user navigates quickly. |
+ if (!is_valid_prerender) { |
+ RecordFinalStatus(FINAL_STATUS_PENDING_SKIPPED); |
+ return; |
+ } |
+ |
+ PendingPrerenderList::iterator it = |
+ pending_prerender_list_.find(child_route_id_pair); |
+ if (it == pending_prerender_list_.end()) { |
+ PendingPrerenderList::value_type el = std::make_pair(child_route_id_pair, |
+ std::vector<PendingContentsData>()); |
+ it = pending_prerender_list_.insert(el).first; |
+ } |
+ |
+ it->second.push_back(PendingContentsData(url, alias_urls, referrer)); |
+} |
+ |
void PrerenderManager::DeleteOldEntries() { |
while (!prerender_list_.empty()) { |
PrerenderContentsData data = prerender_list_.front(); |
@@ -185,6 +244,11 @@ bool PrerenderManager::MaybeUsePreloadedPage(TabContents* tc, const GURL& url) { |
++prerenders_per_session_count_); |
pc->set_final_status(FINAL_STATUS_USED); |
+ int child_id; |
+ int route_id; |
+ CHECK(pc->GetChildId(&child_id)); |
+ CHECK(pc->GetRouteId(&route_id)); |
+ |
RenderViewHost* rvh = pc->render_view_host(); |
// RenderViewHosts in PrerenderContents start out hidden. |
// Since we are actually using it now, restore it. |
@@ -194,6 +258,21 @@ bool PrerenderManager::MaybeUsePreloadedPage(TabContents* tc, const GURL& url) { |
tc->SwapInRenderViewHost(rvh); |
MarkTabContentsAsPrerendered(tc); |
+ // See if we have any pending prerender requests for this routing id and start |
+ // the preload if we do. |
+ std::pair<int, int> child_route_pair = std::make_pair(child_id, route_id); |
+ PendingPrerenderList::iterator pending_it = |
+ pending_prerender_list_.find(child_route_pair); |
+ if (pending_it != pending_prerender_list_.end()) { |
+ for (std::vector<PendingContentsData>::iterator content_it = |
+ pending_it->second.begin(); |
+ content_it != pending_it->second.end(); ++content_it) { |
+ AddPreload(content_it->url_, content_it->alias_urls_, |
+ content_it->referrer_); |
+ } |
+ pending_prerender_list_.erase(pending_it); |
+ } |
+ |
ViewHostMsg_FrameNavigate_Params* p = pc->navigate_params(); |
if (p != NULL) |
tc->DidNavigate(rvh, *p); |
@@ -218,6 +297,7 @@ void PrerenderManager::RemoveEntry(PrerenderContents* entry) { |
it != prerender_list_.end(); |
++it) { |
if (it->contents_ == entry) { |
+ RemovePendingPreload(entry); |
prerender_list_.erase(it); |
break; |
} |
@@ -305,6 +385,24 @@ PrerenderContents* PrerenderManager::FindEntry(const GURL& url) { |
return NULL; |
} |
+PrerenderManager::PendingContentsData* |
+ PrerenderManager::FindPendingEntry(const GURL& url) { |
+ for (PendingPrerenderList::iterator map_it = pending_prerender_list_.begin(); |
+ map_it != pending_prerender_list_.end(); |
+ ++map_it) { |
+ for (std::vector<PendingContentsData>::iterator content_it = |
+ map_it->second.begin(); |
+ content_it != map_it->second.end(); |
+ ++content_it) { |
+ if (content_it->url_ == url) { |
+ return &(*content_it); |
+ } |
+ } |
+ } |
+ |
+ return NULL; |
+} |
+ |
// static |
void PrerenderManager::RecordPrefetchTagObserved() { |
// Ensure that we are in the UI thread, and post to the UI thread if |
@@ -331,6 +429,20 @@ void PrerenderManager::RecordPrefetchTagObservedOnUIThread() { |
last_prefetch_seen_time_ = base::TimeTicks::Now(); |
} |
+void PrerenderManager::RemovePendingPreload(PrerenderContents* entry) { |
+ int child_id; |
+ int route_id; |
+ bool has_child_id = entry->GetChildId(&child_id); |
+ bool has_route_id = has_child_id && entry->GetRouteId(&route_id); |
+ |
+ // If the entry doesn't have a RenderViewHost then it didn't start |
+ // prerendering and there shouldn't be any pending preloads to remove. |
+ if (has_child_id && has_route_id) { |
+ std::pair<int, int> child_route_pair = std::make_pair(child_id, route_id); |
+ pending_prerender_list_.erase(child_route_pair); |
+ } |
+} |
+ |
// static |
bool PrerenderManager::ShouldRecordWindowedPPLT() { |
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |