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

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

Issue 146983002: Move pending prerender logic into PrerenderLinkManager. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 11 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_link_manager.cc
diff --git a/chrome/browser/prerender/prerender_link_manager.cc b/chrome/browser/prerender/prerender_link_manager.cc
index 7726016c203f430ee05bb727dc56b28e7e8a7a64..64e336f8ef72aebc8a57f20d9d408892f233df9c 100644
--- a/chrome/browser/prerender/prerender_link_manager.cc
+++ b/chrome/browser/prerender/prerender_link_manager.cc
@@ -14,6 +14,7 @@
#include "chrome/browser/prerender/prerender_manager.h"
#include "chrome/browser/prerender/prerender_manager_factory.h"
#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/tab_contents/tab_util.h"
#include "chrome/common/prerender_messages.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
@@ -43,9 +44,55 @@ void Send(int child_id, IPC::Message* raw_message) {
namespace prerender {
+// Helper class to implement PrerenderContents::Observer and watch prerenders
+// which launch other prerenders.
+class PrerenderLinkManager::PendingPrerenderManager
+ : public PrerenderContents::Observer {
+ public:
+ explicit PendingPrerenderManager(PrerenderLinkManager* link_manager)
+ : link_manager_(link_manager) {
+ }
+
+ ~PendingPrerenderManager() {
+ DCHECK(observed_launchers_.empty());
+ for (std::set<PrerenderContents*>::iterator i = observed_launchers_.begin();
+ i != observed_launchers_.end(); ++i) {
+ (*i)->RemoveObserver(this);
+ }
+ }
+
+ void ObserveLauncher(PrerenderContents* launcher) {
+ DCHECK_EQ(FINAL_STATUS_MAX, launcher->final_status());
+ if (observed_launchers_.find(launcher) != observed_launchers_.end())
+ return;
+ observed_launchers_.insert(launcher);
+ launcher->AddObserver(this);
+ }
+
+ virtual void OnPrerenderStart(PrerenderContents* launcher) OVERRIDE {
+ }
+ virtual void OnPrerenderStop(PrerenderContents* launcher) OVERRIDE {
+ observed_launchers_.erase(launcher);
+ if (launcher->final_status() == FINAL_STATUS_USED) {
+ link_manager_->StartPendingPrerendersForLauncher(launcher);
davidben 2014/01/24 17:50:43 (This does result in AddPrerender being called whi
+ } else {
+ link_manager_->CancelPendingPrerendersForLauncher(launcher);
+ }
+ }
+
+ private:
+ // A pointer to the parent PrerenderLinkManager.
+ PrerenderLinkManager* link_manager_;
+
+ // The set of PrerenderContentses being observed. Lifetimes are managed by
+ // OnPrerenderStop.
+ std::set<PrerenderContents*> observed_launchers_;
+};
+
PrerenderLinkManager::PrerenderLinkManager(PrerenderManager* manager)
: has_shutdown_(false),
- manager_(manager) {
+ manager_(manager),
+ pending_prerender_manager_(new PendingPrerenderManager(this)) {
}
PrerenderLinkManager::~PrerenderLinkManager() {
@@ -77,11 +124,31 @@ void PrerenderLinkManager::OnAddPrerender(int launcher_child_id,
if (rph && rph->IsGuest())
return;
+ // Check if the launcher is itself an unswapped prerender.
+ content::WebContents* web_contents = tab_util::GetWebContentsByID(
+ launcher_child_id, render_view_route_id);
+ if (web_contents == NULL)
+ return;
+ PrerenderContents* prerender_contents =
+ manager_->GetPrerenderContents(web_contents);
+ if (prerender_contents &&
+ prerender_contents->final_status() != FINAL_STATUS_MAX) {
+ // The launcher is a prerender about to be destroyed asynchronously, but
+ // its AddLinkRelPrerender message raced with shutdown. Ignore it.
+ DCHECK_NE(FINAL_STATUS_USED, prerender_contents->final_status());
+ return;
+ }
+
LinkPrerender
prerender(launcher_child_id, prerender_id, url, referrer, size,
- render_view_route_id, manager_->GetCurrentTimeTicks());
+ render_view_route_id, manager_->GetCurrentTimeTicks(),
+ prerender_contents);
prerenders_.push_back(prerender);
- StartPrerenders();
+ if (prerender_contents) {
+ pending_prerender_manager_->ObserveLauncher(prerender_contents);
+ } else {
+ StartPrerenders();
+ }
}
void PrerenderLinkManager::OnCancelPrerender(int child_id, int prerender_id) {
@@ -138,16 +205,19 @@ PrerenderLinkManager::LinkPrerender::LinkPrerender(
const content::Referrer& referrer,
const gfx::Size& size,
int render_view_route_id,
- TimeTicks creation_time) : launcher_child_id(launcher_child_id),
- prerender_id(prerender_id),
- url(url),
- referrer(referrer),
- size(size),
- render_view_route_id(render_view_route_id),
- creation_time(creation_time),
- handle(NULL),
- is_match_complete_replacement(false),
- has_been_abandoned(false) {
+ TimeTicks creation_time,
+ PrerenderContents* deferred_launcher)
+ : launcher_child_id(launcher_child_id),
+ prerender_id(prerender_id),
+ url(url),
+ referrer(referrer),
+ size(size),
+ render_view_route_id(render_view_route_id),
+ creation_time(creation_time),
+ deferred_launcher(deferred_launcher),
+ handle(NULL),
+ is_match_complete_replacement(false),
+ has_been_abandoned(false) {
}
PrerenderLinkManager::LinkPrerender::~LinkPrerender() {
@@ -184,6 +254,9 @@ void PrerenderLinkManager::StartPrerenders() {
// also per launcher.
for (std::list<LinkPrerender>::iterator i = prerenders_.begin();
i != prerenders_.end(); ++i) {
+ // Skip prerenders launched by a prerender.
+ if (i->deferred_launcher)
+ continue;
if (!i->handle) {
pending_prerenders.push_back(i);
} else {
@@ -320,6 +393,30 @@ void PrerenderLinkManager::CancelPrerender(LinkPrerender* prerender) {
NOTREACHED();
}
+void PrerenderLinkManager::StartPendingPrerendersForLauncher(
+ PrerenderContents* launcher) {
+ for (std::list<LinkPrerender>::iterator i = prerenders_.begin();
+ i != prerenders_.end(); ++i) {
+ if (i->deferred_launcher == launcher)
+ i->deferred_launcher = NULL;
+ }
+ StartPrerenders();
+}
+
+void PrerenderLinkManager::CancelPendingPrerendersForLauncher(
+ PrerenderContents* launcher) {
+ // Remove all pending prerenders for this launcher.
+ std::list<LinkPrerender>::iterator iter = prerenders_.begin();
+ while (iter != prerenders_.end()) {
+ // Increment iterator first so it isn't invalidated.
+ std::list<LinkPrerender>::iterator current = iter++;
+ if (current->deferred_launcher == launcher) {
+ DCHECK(!current->handle);
+ prerenders_.erase(current);
+ }
+ }
+}
+
void PrerenderLinkManager::Shutdown() {
has_shutdown_ = true;
}

Powered by Google App Engine
This is Rietveld 408576698