Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/prerender/prerender_manager.h" | 5 #include "chrome/browser/prerender/prerender_manager.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <functional> | 8 #include <functional> |
| 9 #include <string> | 9 #include <string> |
| 10 #include <vector> | 10 #include <vector> |
| (...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 217 break; | 217 break; |
| 218 default: | 218 default: |
| 219 break; | 219 break; |
| 220 } | 220 } |
| 221 } | 221 } |
| 222 | 222 |
| 223 PrerenderManager::~PrerenderManager() { | 223 PrerenderManager::~PrerenderManager() { |
| 224 // The earlier call to ProfileKeyedService::Shutdown() should have emptied | 224 // The earlier call to ProfileKeyedService::Shutdown() should have emptied |
| 225 // these vectors already. | 225 // these vectors already. |
| 226 DCHECK(active_prerenders_.empty()); | 226 DCHECK(active_prerenders_.empty()); |
| 227 DCHECK(pending_prerenders_.empty()); | |
| 228 DCHECK(to_delete_prerenders_.empty()); | 227 DCHECK(to_delete_prerenders_.empty()); |
| 229 } | 228 } |
| 230 | 229 |
| 231 void PrerenderManager::Shutdown() { | 230 void PrerenderManager::Shutdown() { |
| 232 DestroyAllContents(FINAL_STATUS_MANAGER_SHUTDOWN); | 231 DestroyAllContents(FINAL_STATUS_MANAGER_SHUTDOWN); |
| 233 STLDeleteElements(&prerender_conditions_); | 232 STLDeleteElements(&prerender_conditions_); |
| 234 on_close_tab_contents_deleters_.clear(); | 233 on_close_tab_contents_deleters_.clear(); |
| 235 // Must happen before |profile_| is set to NULL as | 234 // Must happen before |profile_| is set to NULL as |
| 236 // |local_predictor_| accesses it. | 235 // |local_predictor_| accesses it. |
| 237 if (local_predictor_) | 236 if (local_predictor_) |
| 238 local_predictor_->Shutdown(); | 237 local_predictor_->Shutdown(); |
| 239 profile_ = NULL; | 238 profile_ = NULL; |
| 240 | 239 |
| 241 DCHECK(active_prerenders_.empty()); | 240 DCHECK(active_prerenders_.empty()); |
| 242 pending_prerenders_.clear(); | |
| 243 } | 241 } |
| 244 | 242 |
| 245 PrerenderHandle* PrerenderManager::AddPrerenderFromLinkRelPrerender( | 243 PrerenderHandle* PrerenderManager::AddPrerenderFromLinkRelPrerender( |
| 246 int process_id, | 244 int process_id, |
| 247 int route_id, | 245 int route_id, |
| 248 const GURL& url, | 246 const GURL& url, |
| 249 const content::Referrer& referrer, | 247 const content::Referrer& referrer, |
| 250 const gfx::Size& size) { | 248 const gfx::Size& size) { |
| 251 #if defined(OS_ANDROID) | 249 #if defined(OS_ANDROID) |
| 252 // TODO(jcivelli): http://crbug.com/113322 We should have an option to disable | 250 // TODO(jcivelli): http://crbug.com/113322 We should have an option to disable |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 272 session_storage_namespace = | 270 session_storage_namespace = |
| 273 source_web_contents->GetController() | 271 source_web_contents->GetController() |
| 274 .GetDefaultSessionStorageNamespace(); | 272 .GetDefaultSessionStorageNamespace(); |
| 275 } | 273 } |
| 276 | 274 |
| 277 if (PrerenderData* parent_prerender_data = | 275 if (PrerenderData* parent_prerender_data = |
| 278 FindPrerenderDataForChildAndRoute(process_id, route_id)) { | 276 FindPrerenderDataForChildAndRoute(process_id, route_id)) { |
| 279 // Instead of prerendering from inside of a running prerender, we will defer | 277 // Instead of prerendering from inside of a running prerender, we will defer |
| 280 // this request until its launcher is made visible. | 278 // this request until its launcher is made visible. |
| 281 if (PrerenderContents* contents = parent_prerender_data->contents()) { | 279 if (PrerenderContents* contents = parent_prerender_data->contents()) { |
| 282 pending_prerenders_.push_back(new PrerenderData(this)); | |
| 283 PrerenderHandle* prerender_handle = | 280 PrerenderHandle* prerender_handle = |
| 284 new PrerenderHandle(pending_prerenders_.back()); | 281 new PrerenderHandle(static_cast<PrerenderData*>(NULL)); |
| 285 DCHECK(prerender_handle->IsPending()); | |
| 286 | |
| 287 scoped_ptr<PrerenderContents::PendingPrerenderInfo> | 282 scoped_ptr<PrerenderContents::PendingPrerenderInfo> |
| 288 pending_prerender_info(new PrerenderContents::PendingPrerenderInfo( | 283 pending_prerender_info(new PrerenderContents::PendingPrerenderInfo( |
| 289 prerender_handle->weak_ptr_factory_.GetWeakPtr(), | 284 prerender_handle->weak_ptr_factory_.GetWeakPtr(), |
| 290 origin, url, referrer, size)); | 285 origin, url, referrer, size)); |
| 291 | 286 |
| 292 contents->AddPendingPrerender(pending_prerender_info.Pass()); | 287 contents->AddPendingPrerender(pending_prerender_info.Pass()); |
| 293 return prerender_handle; | 288 return prerender_handle; |
| 294 } | 289 } |
| 295 } | 290 } |
| 296 | 291 |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 424 | 419 |
| 425 RenderViewHost* new_render_view_host = | 420 RenderViewHost* new_render_view_host = |
| 426 prerender_contents->prerender_contents()->web_contents()-> | 421 prerender_contents->prerender_contents()->web_contents()-> |
| 427 GetRenderViewHost(); | 422 GetRenderViewHost(); |
| 428 new_render_view_host->Send( | 423 new_render_view_host->Send( |
| 429 new PrerenderMsg_SetIsPrerendering(new_render_view_host->GetRoutingID(), | 424 new PrerenderMsg_SetIsPrerendering(new_render_view_host->GetRoutingID(), |
| 430 false)); | 425 false)); |
| 431 | 426 |
| 432 // Start pending prerender requests from the PrerenderContents, if there are | 427 // Start pending prerender requests from the PrerenderContents, if there are |
| 433 // any. | 428 // any. |
| 434 prerender_contents->StartPendingPrerenders(); | 429 prerender_contents->PrepareForUse(); |
| 435 | 430 |
| 436 TabContents* new_tab_contents = | 431 TabContents* new_tab_contents = |
| 437 prerender_contents->ReleasePrerenderContents(); | 432 prerender_contents->ReleasePrerenderContents(); |
| 438 TabContents* old_tab_contents = TabContents::FromWebContents(web_contents); | 433 TabContents* old_tab_contents = TabContents::FromWebContents(web_contents); |
| 439 DCHECK(new_tab_contents); | 434 DCHECK(new_tab_contents); |
| 440 DCHECK(old_tab_contents); | 435 DCHECK(old_tab_contents); |
| 441 | 436 |
| 442 MarkWebContentsAsPrerendered(new_tab_contents->web_contents(), | 437 MarkWebContentsAsPrerendered(new_tab_contents->web_contents(), |
| 443 prerender_contents->origin()); | 438 prerender_contents->origin()); |
| 444 | 439 |
| (...skipping 405 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 850 CleanUpOldNavigations(); | 845 CleanUpOldNavigations(); |
| 851 } | 846 } |
| 852 | 847 |
| 853 // protected | 848 // protected |
| 854 struct PrerenderManager::PrerenderData::OrderByExpiryTime { | 849 struct PrerenderManager::PrerenderData::OrderByExpiryTime { |
| 855 bool operator()(const PrerenderData* a, const PrerenderData* b) const { | 850 bool operator()(const PrerenderData* a, const PrerenderData* b) const { |
| 856 return a->expiry_time() < b->expiry_time(); | 851 return a->expiry_time() < b->expiry_time(); |
| 857 } | 852 } |
| 858 }; | 853 }; |
| 859 | 854 |
| 860 PrerenderManager::PrerenderData::PrerenderData(PrerenderManager* manager) | |
| 861 : manager_(manager), contents_(NULL), handle_count_(0) { | |
| 862 } | |
| 863 | |
| 864 PrerenderManager::PrerenderData::PrerenderData(PrerenderManager* manager, | 855 PrerenderManager::PrerenderData::PrerenderData(PrerenderManager* manager, |
| 865 PrerenderContents* contents, | 856 PrerenderContents* contents, |
| 866 base::TimeTicks expiry_time) | 857 base::TimeTicks expiry_time) |
| 867 : manager_(manager), | 858 : manager_(manager), |
| 868 contents_(contents), | 859 contents_(contents), |
| 869 handle_count_(0), | 860 handle_count_(0), |
| 870 expiry_time_(expiry_time) { | 861 expiry_time_(expiry_time) { |
| 871 } | 862 } |
| 872 | 863 |
| 873 PrerenderManager::PrerenderData::~PrerenderData() { | 864 PrerenderManager::PrerenderData::~PrerenderData() { |
| 874 } | 865 } |
| 875 | 866 |
| 876 void PrerenderManager::PrerenderData::MakeIntoMatchCompleteReplacement() { | 867 void PrerenderManager::PrerenderData::MakeIntoMatchCompleteReplacement() { |
| 877 DCHECK(contents_); | 868 DCHECK(contents_); |
| 878 contents_->set_match_complete_status( | 869 contents_->set_match_complete_status( |
| 879 PrerenderContents::MATCH_COMPLETE_REPLACED); | 870 PrerenderContents::MATCH_COMPLETE_REPLACED); |
| 880 PrerenderData* to_delete = new PrerenderData(manager_, contents_.release(), | 871 PrerenderData* to_delete = new PrerenderData(manager_, contents_.release(), |
| 881 expiry_time_); | 872 expiry_time_); |
| 882 contents_.reset(to_delete->contents_->CreateMatchCompleteReplacement()); | 873 contents_.reset(to_delete->contents_->CreateMatchCompleteReplacement()); |
| 883 manager_->to_delete_prerenders_.push_back(to_delete); | 874 manager_->to_delete_prerenders_.push_back(to_delete); |
| 884 } | 875 } |
| 885 | 876 |
| 886 void PrerenderManager::PrerenderData::OnNewHandle() { | 877 void PrerenderManager::PrerenderData::OnHandleCreated(PrerenderHandle* handle) { |
| 887 DCHECK(contents_ || handle_count_ == 0) << | |
| 888 "Cannot create multiple handles to a pending prerender."; | |
| 889 ++handle_count_; | 878 ++handle_count_; |
| 879 DCHECK_NE(static_cast<PrerenderContents*>(NULL), contents_); | |
|
mmenke
2012/12/12 16:54:12
nit: DCHECKs are generally put at the start of fu
mmenke
2012/12/12 16:54:12
May want to put one of these in the constructor as
gavinp
2012/12/13 13:38:03
Done & Done.
| |
| 880 contents_->AddObserver(handle); | |
| 890 } | 881 } |
| 891 | 882 |
| 892 void PrerenderManager::PrerenderData::OnNavigateAwayByHandle() { | 883 void PrerenderManager::PrerenderData::OnHandleNavigatedAway( |
| 893 if (!contents_) { | 884 PrerenderHandle* handle) { |
| 894 DCHECK_EQ(1, handle_count_); | 885 DCHECK_LT(0, handle_count_); |
| 895 // Pending prerenders are not maintained in the active_prerenders_, so they | 886 DCHECK_NE(static_cast<PrerenderContents*>(NULL), contents_); |
| 896 // will not get normal expiry. Since this prerender hasn't even been | 887 // We intentionally don't decrement the handle count here, so that the |
| 897 // launched yet, and it's held by a page that is being prerendered, we will | 888 // prerender won't be canceled until it times out. |
| 898 // just delete it. | 889 manager_->SourceNavigatedAway(this); |
| 899 manager_->DestroyPendingPrerenderData(this); | 890 } |
| 900 } else { | 891 |
| 901 DCHECK_LE(0, handle_count_); | 892 void PrerenderManager::PrerenderData::OnHandleCanceled( |
| 902 // We intentionally don't decrement the handle count here, so that the | 893 PrerenderHandle* handle) { |
| 903 // prerender won't be canceled until it times out. | 894 DCHECK_LE(1, handle_count_); |
| 904 manager_->SourceNavigatedAway(this); | 895 DCHECK_NE(static_cast<PrerenderContents*>(NULL), contents_); |
| 896 | |
| 897 if (--handle_count_ == 0) { | |
| 898 // This will eventually remove this object from active_prerenders_. | |
| 899 contents_->Destroy(FINAL_STATUS_CANCELLED); | |
| 905 } | 900 } |
| 906 } | 901 } |
| 907 | 902 |
| 908 void PrerenderManager::PrerenderData::OnCancelByHandle() { | |
| 909 DCHECK_LE(1, handle_count_); | |
| 910 DCHECK(contents_ || handle_count_ == 1); | |
| 911 | |
| 912 if (--handle_count_ == 0) { | |
| 913 if (contents_) { | |
| 914 // This will eventually remove this object from active_prerenders_. | |
| 915 contents_->Destroy(FINAL_STATUS_CANCELLED); | |
| 916 } else { | |
| 917 manager_->DestroyPendingPrerenderData(this); | |
| 918 } | |
| 919 } | |
| 920 } | |
| 921 | |
| 922 PrerenderContents* PrerenderManager::PrerenderData::ReleaseContents() { | 903 PrerenderContents* PrerenderManager::PrerenderData::ReleaseContents() { |
| 923 return contents_.release(); | 904 return contents_.release(); |
| 924 } | 905 } |
| 925 | 906 |
| 926 void PrerenderManager::SetPrerenderContentsFactory( | 907 void PrerenderManager::SetPrerenderContentsFactory( |
| 927 PrerenderContents::Factory* prerender_contents_factory) { | 908 PrerenderContents::Factory* prerender_contents_factory) { |
| 928 DCHECK(CalledOnValidThread()); | 909 DCHECK(CalledOnValidThread()); |
| 929 prerender_contents_factory_.reset(prerender_contents_factory); | 910 prerender_contents_factory_.reset(prerender_contents_factory); |
| 930 } | 911 } |
| 931 | 912 |
| 932 void PrerenderManager::StartPendingPrerenders( | 913 void PrerenderManager::StartPendingPrerenders( |
| 933 const int process_id, | 914 const int process_id, |
| 934 ScopedVector<PrerenderContents::PendingPrerenderInfo>* pending_prerenders, | 915 ScopedVector<PrerenderContents::PendingPrerenderInfo>* pending_prerenders, |
| 935 content::SessionStorageNamespace* session_storage_namespace) { | 916 content::SessionStorageNamespace* session_storage_namespace) { |
| 936 for (ScopedVector<PrerenderContents::PendingPrerenderInfo>::iterator | 917 for (ScopedVector<PrerenderContents::PendingPrerenderInfo>::iterator |
| 937 it = pending_prerenders->begin(); | 918 it = pending_prerenders->begin(); |
| 938 it != pending_prerenders->end(); ++it) { | 919 it != pending_prerenders->end(); ++it) { |
| 939 PrerenderContents::PendingPrerenderInfo* info = *it; | 920 PrerenderContents::PendingPrerenderInfo* info = *it; |
| 940 PrerenderHandle* existing_prerender_handle = | 921 PrerenderHandle* existing_prerender_handle = |
| 941 info->weak_prerender_handle.get(); | 922 info->weak_prerender_handle.get(); |
| 942 if (!existing_prerender_handle || !existing_prerender_handle->IsValid()) | 923 if (!existing_prerender_handle) |
| 924 continue; | |
| 925 if (existing_prerender_handle->has_been_canceled()) | |
|
mmenke
2012/12/12 16:54:12
Since we delete handles when cancelled, and don't
gavinp
2012/12/13 13:38:03
I think that's a good idea. It simplifies the hand
| |
| 943 continue; | 926 continue; |
| 944 | 927 |
| 945 DCHECK(existing_prerender_handle->IsPending()); | 928 DCHECK(!existing_prerender_handle->IsPrerendering()); |
| 946 DCHECK(process_id == -1 || session_storage_namespace); | 929 DCHECK(process_id == -1 || session_storage_namespace); |
| 947 | 930 |
| 948 scoped_ptr<PrerenderHandle> swap_prerender_handle(AddPrerender( | 931 scoped_ptr<PrerenderHandle> new_prerender_handle(AddPrerender( |
| 949 info->origin, process_id, | 932 info->origin, process_id, |
| 950 info->url, info->referrer, info->size, | 933 info->url, info->referrer, info->size, |
| 951 session_storage_namespace)); | 934 session_storage_namespace)); |
| 952 if (swap_prerender_handle.get()) { | 935 if (new_prerender_handle) { |
| 953 // AddPrerender has returned a new prerender handle to us. We want to make | 936 // AddPrerender has returned a new prerender handle to us. We want to make |
| 954 // |existing_prerender_handle| active, so swap the underlying | 937 // |existing_prerender_handle| active, so move the underlying |
| 955 // PrerenderData between the two handles, and delete our old handle (which | 938 // PrerenderData to our new handle. |
| 956 // will release our entry in the pending_prerender_list_). | 939 existing_prerender_handle->AdoptPrerenderDataFrom( |
| 957 existing_prerender_handle->SwapPrerenderDataWith( | 940 new_prerender_handle.get()); |
| 958 swap_prerender_handle.get()); | |
| 959 swap_prerender_handle->OnCancel(); | |
| 960 continue; | 941 continue; |
| 961 } | 942 } |
| 962 | |
| 963 // We could not start our Prerender. Canceling the existing handle will make | |
| 964 // it return false for PrerenderHandle::IsPending(), and will release the | |
| 965 // PrerenderData from pending_prerender_list_. | |
| 966 existing_prerender_handle->OnCancel(); | |
| 967 } | 943 } |
| 968 } | 944 } |
| 969 | 945 |
| 970 void PrerenderManager::SourceNavigatedAway(PrerenderData* prerender_data) { | 946 void PrerenderManager::SourceNavigatedAway(PrerenderData* prerender_data) { |
| 971 // The expiry time of our prerender data will likely change because of | 947 // The expiry time of our prerender data will likely change because of |
| 972 // this navigation. This requires a resort of active_prerenders_. | 948 // this navigation. This requires a resort of active_prerenders_. |
| 973 ScopedVector<PrerenderData>::iterator it = | 949 ScopedVector<PrerenderData>::iterator it = |
| 974 std::find(active_prerenders_.begin(), active_prerenders_.end(), | 950 std::find(active_prerenders_.begin(), active_prerenders_.end(), |
| 975 prerender_data); | 951 prerender_data); |
| 976 if (it == active_prerenders_.end()) | 952 if (it == active_prerenders_.end()) |
| 977 return; | 953 return; |
| 978 | 954 |
| 979 (*it)->set_expiry_time( | 955 (*it)->set_expiry_time( |
| 980 std::min((*it)->expiry_time(), | 956 std::min((*it)->expiry_time(), |
| 981 GetExpiryTimeForNavigatedAwayPrerender())); | 957 GetExpiryTimeForNavigatedAwayPrerender())); |
| 982 SortActivePrerenders(); | 958 SortActivePrerenders(); |
| 983 } | 959 } |
| 984 | 960 |
| 985 void PrerenderManager::DestroyPendingPrerenderData( | |
| 986 PrerenderData* pending_prerender_data) { | |
| 987 ScopedVector<PrerenderData>::iterator it = | |
| 988 std::find(pending_prerenders_.begin(), pending_prerenders_.end(), | |
| 989 pending_prerender_data); | |
| 990 if (it == pending_prerenders_.end()) | |
| 991 return; | |
| 992 pending_prerenders_.erase(it); | |
| 993 } | |
| 994 | |
| 995 // private | 961 // private |
| 996 PrerenderHandle* PrerenderManager::AddPrerender( | 962 PrerenderHandle* PrerenderManager::AddPrerender( |
| 997 Origin origin, | 963 Origin origin, |
| 998 int process_id, | 964 int process_id, |
| 999 const GURL& url_arg, | 965 const GURL& url_arg, |
| 1000 const content::Referrer& referrer, | 966 const content::Referrer& referrer, |
| 1001 const gfx::Size& size, | 967 const gfx::Size& size, |
| 1002 SessionStorageNamespace* session_storage_namespace) { | 968 SessionStorageNamespace* session_storage_namespace) { |
| 1003 DCHECK(CalledOnValidThread()); | 969 DCHECK(CalledOnValidThread()); |
| 1004 | 970 |
| (...skipping 352 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1357 if (!render_process_host || !render_process_host->GetBrowserContext()) | 1323 if (!render_process_host || !render_process_host->GetBrowserContext()) |
| 1358 return NULL; | 1324 return NULL; |
| 1359 Profile* profile = Profile::FromBrowserContext( | 1325 Profile* profile = Profile::FromBrowserContext( |
| 1360 render_process_host->GetBrowserContext()); | 1326 render_process_host->GetBrowserContext()); |
| 1361 if (!profile) | 1327 if (!profile) |
| 1362 return NULL; | 1328 return NULL; |
| 1363 return PrerenderManagerFactory::GetInstance()->GetForProfile(profile); | 1329 return PrerenderManagerFactory::GetInstance()->GetForProfile(profile); |
| 1364 } | 1330 } |
| 1365 | 1331 |
| 1366 } // namespace prerender | 1332 } // namespace prerender |
| OLD | NEW |