Chromium Code Reviews| Index: chrome/browser/prerender/prerender_local_predictor.cc |
| diff --git a/chrome/browser/prerender/prerender_local_predictor.cc b/chrome/browser/prerender/prerender_local_predictor.cc |
| index cc3b1f57bd55e3d1b9fbe3ee377e6c3bb357a8f0..23d78ffe6a071d494d329bdc99903ff061b21f42 100644 |
| --- a/chrome/browser/prerender/prerender_local_predictor.cc |
| +++ b/chrome/browser/prerender/prerender_local_predictor.cc |
| @@ -32,9 +32,12 @@ |
| #include "chrome/browser/safe_browsing/database_manager.h" |
| #include "chrome/browser/safe_browsing/safe_browsing_service.h" |
| #include "chrome/browser/ui/tab_contents/tab_contents_iterator.h" |
| +#include "chrome/common/prefetch_messages.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "content/public/browser/navigation_controller.h" |
| #include "content/public/browser/navigation_entry.h" |
| +#include "content/public/browser/render_frame_host.h" |
| +#include "content/public/browser/render_process_host.h" |
| #include "content/public/browser/web_contents.h" |
| #include "content/public/common/page_transition_types.h" |
| #include "crypto/secure_hash.h" |
| @@ -50,6 +53,7 @@ using base::ListValue; |
| using base::Value; |
| using content::BrowserThread; |
| using content::PageTransition; |
| +using content::RenderFrameHost; |
| using content::SessionStorageNamespace; |
| using content::WebContents; |
| using history::URLID; |
| @@ -64,6 +68,8 @@ namespace { |
| static const size_t kURLHashSize = 5; |
| static const int kNumPrerenderCandidates = 5; |
| +static const int kInvalidProcessId = -1; |
| +static const int kInvalidFrameId = -1; |
| } // namespace |
| @@ -90,9 +96,16 @@ struct PrerenderLocalPredictor::CandidatePrerenderInfo { |
| LocalPredictorURLInfo source_url_; |
| vector<LocalPredictorURLInfo> candidate_urls_; |
| scoped_refptr<SessionStorageNamespace> session_storage_namespace_; |
| + // Render Process ID and Route ID of the page causing the prerender to be |
| + // issued. Needed so that we can cause its renderer to issue prefetches within |
| + // its context. |
| + int render_process_id_; |
| + int render_frame_id_; |
| scoped_ptr<gfx::Size> size_; |
| base::Time start_time_; // used for various time measurements |
| - explicit CandidatePrerenderInfo(URLID source_id) { |
| + explicit CandidatePrerenderInfo(URLID source_id) |
| + : render_process_id_(kInvalidProcessId), |
| + render_frame_id_(kInvalidFrameId) { |
| source_url_.id = source_id; |
| } |
| void MaybeAddCandidateURLFromLocalData(URLID id, double priority) { |
| @@ -598,6 +611,9 @@ void PrerenderLocalPredictor::OnLookupURL( |
| info->session_storage_namespace_ = |
| source_web_contents->GetController().GetDefaultSessionStorageNamespace(); |
| + RenderFrameHost* rfh = source_web_contents->GetMainFrame(); |
| + info->render_process_id_ = rfh->GetProcess()->GetID(); |
| + info->render_frame_id_ = rfh->GetRoutingID(); |
| gfx::Rect container_bounds = source_web_contents->GetContainerBounds(); |
| info->size_.reset(new gfx::Size(container_bounds.size())); |
| @@ -1053,10 +1069,23 @@ bool PrerenderLocalPredictor::DoesPrerenderMatchPLTRecord( |
| } |
| PrerenderLocalPredictor::PrerenderProperties* |
| -PrerenderLocalPredictor::GetIssuedPrerenderSlotForPriority(double priority) { |
| +PrerenderLocalPredictor::GetIssuedPrerenderSlotForPriority(const GURL& url, |
| + double priority) { |
| int num_prerenders = GetLocalPredictorMaxConcurrentPrerenders(); |
| while (static_cast<int>(issued_prerenders_.size()) < num_prerenders) |
| issued_prerenders_.push_back(new PrerenderProperties()); |
| + // First, check if we already have a prerender for the same URL issued. |
| + // If yes, we don't want to prerender this URL again, so we return NULL |
| + // (on matching slot found). |
| + for (int i = 0; i < static_cast<int>(issued_prerenders_.size()); i++) { |
| + PrerenderProperties* p = issued_prerenders_[i]; |
| + DCHECK(p != NULL); |
| + if (p->prerender_handle->Matches(url, NULL)) |
|
davidben
2014/06/19 20:08:23
This should check p->prerender_handle and also p->
tburkard
2014/06/19 20:12:16
Done.
|
| + return NULL; |
| + } |
| + // Otherwise, let's see if there are any empty slots. If yes, return the first |
| + // one we find. Otherwise, if the lowest priority prerender has a lower |
| + // priority than the page we want to prerender, use its slot. |
| PrerenderProperties* lowest_priority_prerender = NULL; |
| for (int i = 0; i < static_cast<int>(issued_prerenders_.size()); i++) { |
| PrerenderProperties* p = issued_prerenders_[i]; |
| @@ -1091,8 +1120,10 @@ void PrerenderLocalPredictor::ContinuePrerenderCheck( |
| g_browser_process->safe_browsing_service()->database_manager(); |
| #endif |
| PrerenderProperties* prerender_properties = NULL; |
| - |
| + int num_issued = 0; |
| for (int i = 0; i < static_cast<int>(info->candidate_urls_.size()); i++) { |
| + if (num_issued > GetLocalPredictorMaxLaunchPrerenders()) |
| + return; |
| RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_EXAMINE_NEXT_URL); |
| url_info.reset(new LocalPredictorURLInfo(info->candidate_urls_[i])); |
| if (url_info->local_history_based) { |
| @@ -1126,7 +1157,7 @@ void PrerenderLocalPredictor::ContinuePrerenderCheck( |
| continue; |
| } |
| prerender_properties = |
| - GetIssuedPrerenderSlotForPriority(url_info->priority); |
| + GetIssuedPrerenderSlotForPriority(url_info->url, url_info->priority); |
| if (!prerender_properties) { |
| RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_PRIORITY_TOO_LOW); |
| url_info.reset(NULL); |
| @@ -1148,7 +1179,9 @@ void PrerenderLocalPredictor::ContinuePrerenderCheck( |
| // For root pages, we assume that they are reasonably safe, and we |
| // will just prerender them without any additional checks. |
| RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_ROOT_PAGE); |
| - break; |
| + IssuePrerender(info.get(), url_info.get(), prerender_properties); |
| + num_issued++; |
| + continue; |
| } |
| if (IsLogOutURL(url_info->url)) { |
| RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_LOGOUT_URL); |
| @@ -1166,40 +1199,48 @@ void PrerenderLocalPredictor::ContinuePrerenderCheck( |
| // If a page is on the side-effect free whitelist, we will just prerender |
| // it without any additional checks. |
| RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_ON_SIDE_EFFECT_FREE_WHITELIST); |
| - break; |
| + IssuePrerender(info.get(), url_info.get(), prerender_properties); |
| + num_issued++; |
| + continue; |
| } |
| #endif |
| if (!SkipLocalPredictorServiceWhitelist() && |
| url_info->service_whitelist && url_info->service_whitelist_lookup_ok) { |
| RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_ON_SERVICE_WHITELIST); |
| - break; |
| + IssuePrerender(info.get(), url_info.get(), prerender_properties); |
| + num_issued++; |
| + continue; |
| } |
| if (!SkipLocalPredictorLoggedIn() && |
| !url_info->logged_in && url_info->logged_in_lookup_ok) { |
| RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_NOT_LOGGED_IN); |
| - break; |
| + IssuePrerender(info.get(), url_info.get(), prerender_properties); |
| + num_issued++; |
| + continue; |
| } |
| if (!SkipLocalPredictorDefaultNoPrerender()) { |
| RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_FALLTHROUGH_NOT_PRERENDERING); |
| url_info.reset(NULL); |
| } else { |
| RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_FALLTHROUGH_PRERENDERING); |
| + IssuePrerender(info.get(), url_info.get(), prerender_properties); |
| + num_issued++; |
| + continue; |
| } |
| } |
| - if (!url_info.get()) |
| - return; |
| - RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_ISSUING_PRERENDER); |
| - DCHECK(prerender_properties != NULL); |
| - if (IsLocalPredictorPrerenderLaunchEnabled()) { |
| - IssuePrerender(info.Pass(), url_info.Pass(), prerender_properties); |
| - } |
| } |
| void PrerenderLocalPredictor::IssuePrerender( |
| - scoped_ptr<CandidatePrerenderInfo> info, |
| - scoped_ptr<LocalPredictorURLInfo> url_info, |
| + CandidatePrerenderInfo* info, |
| + LocalPredictorURLInfo* url_info, |
| PrerenderProperties* prerender_properties) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| + RecordEvent(EVENT_CONTINUE_PRERENDER_CHECK_ISSUING_PRERENDER); |
| + DCHECK(prerender_properties != NULL); |
| + DCHECK(info != NULL); |
| + DCHECK(url_info != NULL); |
| + if (!IsLocalPredictorPrerenderLaunchEnabled()) |
| + return; |
| URLID url_id = url_info->id; |
| const GURL& url = url_info->url; |
| double priority = url_info->priority; |
| @@ -1243,6 +1284,16 @@ void PrerenderLocalPredictor::IssuePrerender( |
| new_prerender_handle->OnCancel(); |
| RecordEvent(EVENT_ISSUE_PRERENDER_CANCELLED_OLD_PRERENDER); |
| } |
| + // If we are prefetching rather than prerendering, now is the time to launch |
| + // the prefetch. |
| + if (IsLocalPredictorPrerenderPrefetchEnabled()) { |
| + // Obtain the render frame host that caused this prefetch. |
| + RenderFrameHost* rfh = RenderFrameHost::FromID(info->render_process_id_, |
| + info->render_frame_id_); |
| + // If it is still alive, launch the prefresh. |
| + if (rfh) |
| + rfh->Send(new PrefetchMsg_Prefetch(rfh->GetRoutingID(), url)); |
| + } |
| } |
| RecordEvent(EVENT_ADD_VISIT_PRERENDERING); |