| 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..8213dedd8701b4abb3250e952cc564b2297ef250 100644
|
| --- a/chrome/browser/prerender/prerender_link_manager.cc
|
| +++ b/chrome/browser/prerender/prerender_link_manager.cc
|
| @@ -4,6 +4,7 @@
|
|
|
| #include "chrome/browser/prerender/prerender_link_manager.h"
|
|
|
| +#include <functional>
|
| #include <limits>
|
| #include <set>
|
| #include <utility>
|
| @@ -43,10 +44,54 @@ 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) {}
|
| +
|
| + virtual ~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);
|
| + } 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() {
|
| for (std::list<LinkPrerender>::iterator i = prerenders_.begin();
|
| @@ -77,11 +122,27 @@ void PrerenderLinkManager::OnAddPrerender(int launcher_child_id,
|
| if (rph && rph->IsGuest())
|
| return;
|
|
|
| + // Check if the launcher is itself an unswapped prerender.
|
| + PrerenderContents* prerender_contents =
|
| + manager_->GetPrerenderContentsForRoute(launcher_child_id,
|
| + render_view_route_id);
|
| + 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 +199,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 +248,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 +387,32 @@ 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::vector<std::list<LinkPrerender>::iterator> to_erase;
|
| + for (std::list<LinkPrerender>::iterator i = prerenders_.begin();
|
| + i != prerenders_.end(); ++i) {
|
| + if (i->deferred_launcher == launcher) {
|
| + DCHECK(!i->handle);
|
| + to_erase.push_back(i);
|
| + }
|
| + }
|
| + std::for_each(to_erase.begin(), to_erase.end(),
|
| + std::bind1st(std::mem_fun(&std::list<LinkPrerender>::erase),
|
| + &prerenders_));
|
| +}
|
| +
|
| void PrerenderLinkManager::Shutdown() {
|
| has_shutdown_ = true;
|
| }
|
|
|