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..d3f757801d2e7ef7d398c9dc3a3d8a01d273d962 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,25 @@ 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 && p->prerender_handle->IsPrerendering() && |
+ p->prerender_handle->Matches(url, NULL)) { |
+ 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 +1122,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 +1159,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 +1181,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 +1201,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 +1286,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); |