summaryrefslogtreecommitdiffstats
path: root/chrome/browser
diff options
context:
space:
mode:
authorgavinp@chromium.org <gavinp@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-12-15 21:45:18 +0000
committergavinp@chromium.org <gavinp@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-12-15 21:45:18 +0000
commit2610170d745f256d0316a936d0907e02b279d8bd (patch)
treead2be6594e2ae6ad54e6cb0b451716565d9f40cd /chrome/browser
parentaeb5ccec77fbc0691e766ee80b7c4f4efb79bd9d (diff)
downloadchromium_src-2610170d745f256d0316a936d0907e02b279d8bd.zip
chromium_src-2610170d745f256d0316a936d0907e02b279d8bd.tar.gz
chromium_src-2610170d745f256d0316a936d0907e02b279d8bd.tar.bz2
Make PrerenderHandle an observer of PrerenderContents.
The big implication of this is that PrerenderLinkManager is an observer of PrerenderHandle, and so messaging to/from the browser process about prerenders ends up mostly in the same place. Interestingly, we basically can toss out the pending_prerenders_ list in the PrerenderManager; the only thing it bought us was tracking cancelation, which is now done with a bool in PrerenderHandle, just as easily. The earlier work on the lifetime of PrerenderContents and PrerenderHandle was building up to this. This CL depends on https://codereview.chromium.org/11348357/ , and can't land until after it. R=mmenke@chromium.org BUG=None Review URL: https://chromiumcodereview.appspot.com/11316311 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@173322 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r--chrome/browser/prerender/prerender_contents.cc86
-rw-r--r--chrome/browser/prerender/prerender_contents.h22
-rw-r--r--chrome/browser/prerender/prerender_handle.cc110
-rw-r--r--chrome/browser/prerender/prerender_handle.h58
-rw-r--r--chrome/browser/prerender/prerender_link_manager.cc142
-rw-r--r--chrome/browser/prerender/prerender_link_manager.h13
-rw-r--r--chrome/browser/prerender/prerender_manager.cc93
-rw-r--r--chrome/browser/prerender/prerender_manager.h22
-rw-r--r--chrome/browser/prerender/prerender_tracker_unittest.cc1
-rw-r--r--chrome/browser/prerender/prerender_unittest.cc85
10 files changed, 393 insertions, 239 deletions
diff --git a/chrome/browser/prerender/prerender_contents.cc b/chrome/browser/prerender/prerender_contents.cc
index 5e13374..2737f79 100644
--- a/chrome/browser/prerender/prerender_contents.cc
+++ b/chrome/browser/prerender/prerender_contents.cc
@@ -8,7 +8,6 @@
#include <functional>
#include <utility>
-#include "base/process_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/history/history_tab_helper.h"
#include "chrome/browser/history/history_types.h"
@@ -43,33 +42,6 @@ using content::WebContents;
namespace prerender {
-namespace {
-
-// Tells the render process at |child_id| whether |url| is a new prerendered
-// page, or whether |url| is being removed as a prerendered page. Currently
-// this will only inform the render process that created the prerendered page
-// with <link rel="prerender"> tags about it. This means that if the user
-// clicks on a link for a prerendered URL in a different page, the prerender
-// will not be swapped in.
-void InformRenderProcessAboutPrerender(const GURL& url,
- bool is_add,
- int child_id) {
- if (child_id < 0)
- return;
- content::RenderProcessHost* render_process_host =
- content::RenderProcessHost::FromID(child_id);
- if (!render_process_host)
- return;
- IPC::Message* message = NULL;
- if (is_add)
- message = new PrerenderMsg_AddPrerenderURL(url);
- else
- message = new PrerenderMsg_RemovePrerenderURL(url);
- render_process_host->Send(message);
-}
-
-} // namespace
-
class PrerenderContentsFactoryImpl : public PrerenderContents::Factory {
public:
virtual PrerenderContents* CreatePrerenderContents(
@@ -167,6 +139,15 @@ class PrerenderContents::WebContentsDelegateImpl
PrerenderContents* prerender_contents_;
};
+void PrerenderContents::Observer::OnPrerenderAddAlias(
+ PrerenderContents* contents,
+ const GURL& alias_url) {
+}
+
+void PrerenderContents::Observer::OnPrerenderCreatedMatchCompleteReplacement(
+ PrerenderContents* contents, PrerenderContents* replacement) {
+}
+
PrerenderContents::Observer::Observer() {
}
@@ -193,7 +174,9 @@ void PrerenderContents::AddPendingPrerender(
pending_prerenders_.push_back(pending_prerender_info.release());
}
-void PrerenderContents::StartPendingPrerenders() {
+void PrerenderContents::PrepareForUse() {
+ NotifyPrerenderStop();
+
SessionStorageNamespace* session_storage_namespace = NULL;
if (prerender_contents_) {
// TODO(ajwong): This does not correctly handle storage for isolated apps.
@@ -232,7 +215,7 @@ PrerenderContents::PrerenderContents(
DCHECK(prerender_manager != NULL);
}
-PrerenderContents* PrerenderContents::CreateMatchCompleteReplacement() const {
+PrerenderContents* PrerenderContents::CreateMatchCompleteReplacement() {
PrerenderContents* new_contents = prerender_manager_->CreatePrerenderContents(
prerender_url(), referrer(), origin(), experiment_id());
@@ -248,6 +231,7 @@ PrerenderContents* PrerenderContents::CreateMatchCompleteReplacement() const {
new_contents->alias_urls_ = alias_urls_;
new_contents->set_match_complete_status(
PrerenderContents::MATCH_COMPLETE_REPLACEMENT);
+ NotifyPrerenderCreatedMatchCompleteReplacement(new_contents);
return new_contents;
}
@@ -276,9 +260,6 @@ void PrerenderContents::StartPrerendering(
session_storage_namespace_id_ = session_storage_namespace->id();
size_ = size;
- InformRenderProcessAboutPrerender(prerender_url_, true,
- creator_child_id_);
-
DCHECK(load_start_time_.is_null());
load_start_time_ = base::TimeTicks::Now();
@@ -369,11 +350,6 @@ void PrerenderContents::SetFinalStatus(FinalStatus final_status) {
DCHECK(final_status_ == FINAL_STATUS_MAX);
final_status_ = final_status;
-
- if (!prerender_manager_->IsControlGroup(experiment_id()) &&
- prerendering_has_started()) {
- NotifyPrerenderStop();
- }
}
PrerenderContents::~PrerenderContents() {
@@ -385,14 +361,6 @@ PrerenderContents::~PrerenderContents() {
prerender_manager_->RecordFinalStatusWithMatchCompleteStatus(
origin(), experiment_id(), match_complete_status(), final_status());
- if (child_id_ != -1 && route_id_ != -1) {
- for (std::vector<GURL>::const_iterator it = alias_urls_.begin();
- it != alias_urls_.end();
- ++it) {
- InformRenderProcessAboutPrerender(*it, false, creator_child_id_);
- }
- }
-
// If we still have a WebContents, clean up anything we need to and then
// destroy it.
if (prerender_contents_.get())
@@ -404,6 +372,10 @@ void PrerenderContents::AddObserver(Observer* observer) {
observer_list_.AddObserver(observer);
}
+void PrerenderContents::RemoveObserver(Observer* observer) {
+ observer_list_.RemoveObserver(observer);
+}
+
void PrerenderContents::Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) {
@@ -500,6 +472,18 @@ void PrerenderContents::NotifyPrerenderStop() {
observer_list_.Clear();
}
+void PrerenderContents::NotifyPrerenderAddAlias(const GURL& alias_url) {
+ FOR_EACH_OBSERVER(Observer, observer_list_, OnPrerenderAddAlias(this,
+ alias_url));
+}
+
+void PrerenderContents::NotifyPrerenderCreatedMatchCompleteReplacement(
+ PrerenderContents* replacement) {
+ FOR_EACH_OBSERVER(Observer, observer_list_,
+ OnPrerenderCreatedMatchCompleteReplacement(this,
+ replacement));
+}
+
void PrerenderContents::DidUpdateFaviconURL(
int32 page_id,
const std::vector<content::FaviconURL>& urls) {
@@ -534,7 +518,7 @@ bool PrerenderContents::AddAliasURL(const GURL& url) {
}
alias_urls_.push_back(url);
- InformRenderProcessAboutPrerender(url, true, creator_child_id_);
+ NotifyPrerenderAddAlias(url);
return true;
}
@@ -588,6 +572,8 @@ void PrerenderContents::DidFinishLoad(int64 frame_id,
}
void PrerenderContents::Destroy(FinalStatus final_status) {
+ DCHECK_NE(final_status, FINAL_STATUS_USED);
+
if (prerendering_has_been_cancelled_)
return;
@@ -613,6 +599,12 @@ void PrerenderContents::Destroy(FinalStatus final_status) {
prerender_manager_->AddToHistory(this);
prerender_manager_->MoveEntryToPendingDelete(this, final_status);
+ if (!prerender_manager_->IsControlGroup(experiment_id()) &&
+ (prerendering_has_started() ||
+ match_complete_status() == MATCH_COMPLETE_REPLACEMENT)) {
+ NotifyPrerenderStop();
+ }
+
// We may destroy the PrerenderContents before we have initialized the
// RenderViewHost. Otherwise set the Observer's PrerenderContents to NULL to
// avoid any more messages being sent.
diff --git a/chrome/browser/prerender/prerender_contents.h b/chrome/browser/prerender/prerender_contents.h
index b978c36..e264906 100644
--- a/chrome/browser/prerender/prerender_contents.h
+++ b/chrome/browser/prerender/prerender_contents.h
@@ -78,6 +78,15 @@ class PrerenderContents : public content::NotificationObserver,
// Signals that the prerender has stopped running.
virtual void OnPrerenderStop(PrerenderContents* contents) = 0;
+ // Signals the discovery, through redirects, of a new alias for this
+ // prerender.
+ virtual void OnPrerenderAddAlias(PrerenderContents* contents,
+ const GURL& alias_url);
+
+ // Signals that this prerender has just become a MatchComplete replacement.
+ virtual void OnPrerenderCreatedMatchCompleteReplacement(
+ PrerenderContents* contents, PrerenderContents* replacement);
+
protected:
Observer();
virtual ~Observer() = 0;
@@ -128,13 +137,15 @@ class PrerenderContents : public content::NotificationObserver,
virtual ~PrerenderContents();
// All observers of a PrerenderContents are removed after the OnPrerenderStop
- // event is sent, so there is no need for a RemoveObserver() method.
+ // event is sent, so there is no need to call RemoveObserver() in the normal
+ // use case.
void AddObserver(Observer* observer);
+ void RemoveObserver(Observer* observer);
// For MatchComplete correctness, create a dummy replacement prerender
// contents to stand in for this prerender contents that (which we are about
// to destroy).
- PrerenderContents* CreateMatchCompleteReplacement() const;
+ PrerenderContents* CreateMatchCompleteReplacement();
bool Init();
@@ -267,8 +278,8 @@ class PrerenderContents : public content::NotificationObserver,
scoped_ptr<PendingPrerenderInfo> pending_prerender_info);
// Reissues any pending prerender requests from the prerendered page. Also
- // clears the list of pending requests.
- void StartPendingPrerenders();
+ // clears the list of pending requests. Sends notifications.
+ void PrepareForUse();
protected:
PrerenderContents(PrerenderManager* prerender_manager,
@@ -282,6 +293,9 @@ class PrerenderContents : public content::NotificationObserver,
// that NotifyPrerenderStop() also clears the observer list.
void NotifyPrerenderStart();
void NotifyPrerenderStop();
+ void NotifyPrerenderAddAlias(const GURL& alias_url);
+ void NotifyPrerenderCreatedMatchCompleteReplacement(
+ PrerenderContents* replacement);
// Called whenever a RenderViewHost is created for prerendering. Only called
// once the RenderViewHost has a RenderView and RenderWidgetHostView.
diff --git a/chrome/browser/prerender/prerender_handle.cc b/chrome/browser/prerender/prerender_handle.cc
index 24de791..5ef9b4d 100644
--- a/chrome/browser/prerender/prerender_handle.cc
+++ b/chrome/browser/prerender/prerender_handle.cc
@@ -6,66 +6,118 @@
#include <algorithm>
+#include "base/logging.h"
#include "chrome/browser/prerender/prerender_contents.h"
namespace prerender {
-PrerenderHandle::~PrerenderHandle() {
- DCHECK(!IsValid());
- // This shouldn't occur, but we also shouldn't leak if it does.
- if (IsValid())
- OnCancel();
+PrerenderHandle::Observer::Observer() {
}
-void PrerenderHandle::OnNavigateAway() {
- DCHECK(CalledOnValidThread());
- if (!IsValid())
- return;
- prerender_data_->OnNavigateAwayByHandle();
- prerender_data_.reset();
+PrerenderHandle::Observer::~Observer() {
}
-void PrerenderHandle::OnCancel() {
- DCHECK(CalledOnValidThread());
- if (!IsValid())
- return;
- prerender_data_->OnCancelByHandle();
- prerender_data_.reset();
+PrerenderHandle::~PrerenderHandle() {
+ if (prerender_data_) {
+ prerender_data_->contents()->RemoveObserver(this);
+ }
}
-bool PrerenderHandle::IsValid() const {
- return prerender_data_ != NULL;
+void PrerenderHandle::SetObserver(Observer* observer) {
+ DCHECK_NE(static_cast<Observer*>(NULL), observer);
+ observer_ = observer;
}
-bool PrerenderHandle::IsPending() const {
+void PrerenderHandle::OnNavigateAway() {
DCHECK(CalledOnValidThread());
- return prerender_data_ && !prerender_data_->contents();
+ if (prerender_data_)
+ prerender_data_->OnHandleNavigatedAway(this);
+}
+
+void PrerenderHandle::OnCancel() {
+ DCHECK(CalledOnValidThread());
+ if (prerender_data_)
+ prerender_data_->OnHandleCanceled(this);
}
bool PrerenderHandle::IsPrerendering() const {
DCHECK(CalledOnValidThread());
- return prerender_data_ && prerender_data_->contents();
+ return prerender_data_ != NULL;
}
bool PrerenderHandle::IsFinishedLoading() const {
DCHECK(CalledOnValidThread());
- if (!prerender_data_ || IsPending())
+ if (!prerender_data_)
return false;
return prerender_data_->contents()->has_finished_loading();
}
PrerenderHandle::PrerenderHandle(
PrerenderManager::PrerenderData* prerender_data)
- : prerender_data_(prerender_data->AsWeakPtr()),
+ : observer_(NULL),
weak_ptr_factory_(this) {
- prerender_data->OnNewHandle();
+ if (prerender_data) {
+ prerender_data_ = prerender_data->AsWeakPtr();
+ prerender_data->OnHandleCreated(this);
+ }
+}
+
+void PrerenderHandle::AdoptPrerenderDataFrom(PrerenderHandle* other_handle) {
+ DCHECK_EQ(static_cast<PrerenderManager::PrerenderData*>(NULL),
+ prerender_data_);
+ if (other_handle->prerender_data_ &&
+ other_handle->prerender_data_->contents()) {
+ other_handle->prerender_data_->contents()->RemoveObserver(other_handle);
+ }
+
+ prerender_data_ = other_handle->prerender_data_;
+ other_handle->prerender_data_.reset();
+
+ if (prerender_data_) {
+ DCHECK_NE(static_cast<PrerenderContents*>(NULL),
+ prerender_data_->contents());
+ prerender_data_->contents()->AddObserver(this);
+ // We are joining a prerender that has already started so we fire off an
+ // extra start event at ourselves.
+ OnPrerenderStart(prerender_data_->contents());
+ }
+}
+
+void PrerenderHandle::OnPrerenderStart(PrerenderContents* prerender_contents) {
+ DCHECK(CalledOnValidThread());
+ DCHECK(prerender_data_);
+ DCHECK_EQ(prerender_data_->contents(), prerender_contents);
+ if (observer_)
+ observer_->OnPrerenderStart(this);
+}
+
+void PrerenderHandle::OnPrerenderAddAlias(PrerenderContents* prerender_contents,
+ const GURL& alias_url) {
+ DCHECK(CalledOnValidThread());
+ DCHECK(prerender_data_);
+ DCHECK_EQ(prerender_data_->contents(), prerender_contents);
+ if (observer_)
+ observer_->OnPrerenderAddAlias(this, alias_url);
}
-void PrerenderHandle::SwapPrerenderDataWith(
- PrerenderHandle* other_prerender_handle) {
+void PrerenderHandle::OnPrerenderStop(PrerenderContents* prerender_contents) {
DCHECK(CalledOnValidThread());
- DCHECK(other_prerender_handle);
- std::swap(prerender_data_, other_prerender_handle->prerender_data_);
+ if (observer_)
+ observer_->OnPrerenderStop(this);
+}
+
+void PrerenderHandle::OnPrerenderCreatedMatchCompleteReplacement(
+ PrerenderContents* contents, PrerenderContents* replacement) {
+ DCHECK(CalledOnValidThread());
+
+ // This should occur in the middle of the surgery on the PrerenderData, and
+ // so we expect to not have our new contents in our PrerenderData yet. The
+ // switch occurs in
+ // PrerenderManager::PrerenderData::MakeIntoMatchCompleteReplacement, so
+ // this method only needs to switch observing.
+
+ contents->RemoveObserver(this);
+ replacement->AddObserver(this);
}
} // namespace prerender
diff --git a/chrome/browser/prerender/prerender_handle.h b/chrome/browser/prerender/prerender_handle.h
index 90a9dcc..156b92d 100644
--- a/chrome/browser/prerender/prerender_handle.h
+++ b/chrome/browser/prerender/prerender_handle.h
@@ -23,20 +23,40 @@ class PrerenderContents;
// A class representing a running prerender to a client of the PrerenderManager.
// Methods on PrerenderManager which start prerenders return a caller-owned
// PrerenderHandle* to the client (or NULL if they are unable to start a
-// prerender). Because the PrerenderManager can stop running prerenders at any
-// time, callers may wish to check PrerenderHandle::IsValid() before operating
-// on their prerenders.
-class PrerenderHandle : public base::NonThreadSafe {
+// prerender). Calls on the handle of a prerender that is not running at no-ops.
+// Destroying a handle before a prerender starts will prevent it from ever
+// starting. Destroying a handle while a prerendering is running will stop the
+// prerender, without making any calls to the observer.
+class PrerenderHandle : public base::NonThreadSafe,
+ public PrerenderContents::Observer {
public:
+ class Observer {
+ public:
+ // Signals that the prerender has started running.
+ virtual void OnPrerenderStart(PrerenderHandle* handle) = 0;
+
+ // Signals that the prerender has stopped running.
+ virtual void OnPrerenderStop(PrerenderHandle* handle) = 0;
+
+ // Signals the discovery, through redirects, of a new alias for this
+ // prerender.
+ virtual void OnPrerenderAddAlias(PrerenderHandle* handle,
+ const GURL& alias_url) = 0;
+
+ protected:
+ Observer();
+ virtual ~Observer();
+ };
+
// Before calling the destructor, the caller must invalidate the handle by
// calling either OnNavigateAway or OnCancel.
- ~PrerenderHandle();
+ virtual ~PrerenderHandle();
+
+ void SetObserver(Observer* observer);
// The launcher is navigating away from the context that launched this
// prerender. The prerender will likely stay alive briefly though, in case we
- // are going through a redirect chain that will target it. This call
- // invalidates the handle. If the prerender handle is already invalid, this
- // call does nothing.
+ // are going through a redirect chain that will target it.
void OnNavigateAway();
// The launcher has taken explicit action to remove this prerender (for
@@ -45,16 +65,6 @@ class PrerenderHandle : public base::NonThreadSafe {
// nothing.
void OnCancel();
- // True if the prerender handle is still connected to a (pending or running)
- // prerender. Handles can become invalid through explicit requests by the
- // client, such as calling OnCancel() or OnNavigateAway(), and handles
- // also become invalid when the PrerenderManager cancels prerenders.
- bool IsValid() const;
-
- // True if this prerender was launched by a page that was itself being
- // prerendered, and so has not yet been started.
- bool IsPending() const;
-
// True if this prerender is currently active.
bool IsPrerendering() const;
@@ -66,7 +76,17 @@ class PrerenderHandle : public base::NonThreadSafe {
explicit PrerenderHandle(PrerenderManager::PrerenderData* prerender_data);
- void SwapPrerenderDataWith(PrerenderHandle* other_prerender_handle);
+ void AdoptPrerenderDataFrom(PrerenderHandle* other_handle);
+
+ // From PrerenderContents::Observer:
+ virtual void OnPrerenderStart(PrerenderContents* prerender_contents) OVERRIDE;
+ virtual void OnPrerenderStop(PrerenderContents* prerender_contents) OVERRIDE;
+ virtual void OnPrerenderAddAlias(PrerenderContents* prerender_contents,
+ const GURL& alias_url) OVERRIDE;
+ virtual void OnPrerenderCreatedMatchCompleteReplacement(
+ PrerenderContents* contents, PrerenderContents* replacement) OVERRIDE;
+
+ Observer* observer_;
base::WeakPtr<PrerenderManager::PrerenderData> prerender_data_;
base::WeakPtrFactory<PrerenderHandle> weak_ptr_factory_;
diff --git a/chrome/browser/prerender/prerender_link_manager.cc b/chrome/browser/prerender/prerender_link_manager.cc
index ea55997..ea45012 100644
--- a/chrome/browser/prerender/prerender_link_manager.cc
+++ b/chrome/browser/prerender/prerender_link_manager.cc
@@ -5,14 +5,16 @@
#include "chrome/browser/prerender/prerender_link_manager.h"
#include <limits>
-#include <queue>
#include <utility>
+#include "base/memory/scoped_ptr.h"
#include "chrome/browser/prerender/prerender_contents.h"
#include "chrome/browser/prerender/prerender_handle.h"
#include "chrome/browser/prerender/prerender_manager.h"
#include "chrome/browser/prerender/prerender_manager_factory.h"
#include "chrome/browser/profiles/profile.h"
+#include "chrome/common/prerender_messages.h"
+#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/session_storage_namespace.h"
#include "content/public/common/referrer.h"
@@ -22,6 +24,20 @@
using content::RenderViewHost;
using content::SessionStorageNamespace;
+namespace {
+
+void Send(int child_id, IPC::Message* raw_message) {
+ using content::RenderProcessHost;
+ scoped_ptr<IPC::Message> own_message(raw_message);
+
+ RenderProcessHost* render_process_host = RenderProcessHost::FromID(child_id);
+ if (!render_process_host)
+ return;
+ render_process_host->Send(own_message.release());
+}
+
+} // namespace
+
namespace prerender {
PrerenderLinkManager::PrerenderLinkManager(PrerenderManager* manager)
@@ -33,7 +49,9 @@ PrerenderLinkManager::~PrerenderLinkManager() {
it != ids_to_handle_map_.end();
++it) {
PrerenderHandle* prerender_handle = it->second;
- prerender_handle->OnCancel();
+ DCHECK(!prerender_handle->IsPrerendering())
+ << "All running prerenders should stop at the same time as the "
+ << "PrerenderManager.";
delete prerender_handle;
}
}
@@ -51,29 +69,25 @@ bool PrerenderLinkManager::OnAddPrerender(int child_id,
<< ", size = (" << size.width() << ", " << size.height() << ")"
<< ", render_view_route_id = " << render_view_route_id;
- const ChildAndPrerenderIdPair child_and_prerender_id(child_id, prerender_id);
- DCHECK_EQ(0U, ids_to_handle_map_.count(child_and_prerender_id));
- scoped_ptr<PrerenderHandle> prerender_handle(
+ PrerenderHandle* prerender_handle =
manager_->AddPrerenderFromLinkRelPrerender(
- child_id, render_view_route_id, url, referrer, size));
- if (prerender_handle.get()) {
- std::pair<IdPairToPrerenderHandleMap::iterator, bool> insert_result =
- ids_to_handle_map_.insert(std::make_pair(
- child_and_prerender_id, static_cast<PrerenderHandle*>(NULL)));
- DCHECK(insert_result.second);
- delete insert_result.first->second;
- insert_result.first->second = prerender_handle.release();
- return true;
- }
- return false;
+ child_id, render_view_route_id, url, referrer, size);
+ if (!prerender_handle)
+ return false;
+
+ const ChildAndPrerenderIdPair child_and_prerender_id(child_id, prerender_id);
+ DCHECK_EQ(0u, ids_to_handle_map_.count(child_and_prerender_id));
+ ids_to_handle_map_[child_and_prerender_id] = prerender_handle;
+
+ // If we are given a prerender that is already prerendering, we have missed
+ // the start event.
+ if (prerender_handle->IsPrerendering())
+ OnPrerenderStart(prerender_handle);
+ prerender_handle->SetObserver(this);
+ return true;
}
-// TODO(gavinp): Once an observer interface is provided down to the WebKit
-// layer, we should add DCHECK_NE(0L, ids_to_url_map_.count(...)) to both
-// OnCancelPrerender and OnAbandonPrerender. We can't do this now, since
-// the WebKit layer isn't even aware if we didn't add the prerender to the map
-// in OnAddPrerender above.
void PrerenderLinkManager::OnCancelPrerender(int child_id, int prerender_id) {
DVLOG(2) << "OnCancelPrerender, child_id = " << child_id
<< ", prerender_id = " << prerender_id;
@@ -86,7 +100,12 @@ void PrerenderLinkManager::OnCancelPrerender(int child_id, int prerender_id) {
}
PrerenderHandle* prerender_handle = id_to_handle_iter->second;
prerender_handle->OnCancel();
- RemovePrerender(id_to_handle_iter);
+
+ // Because OnCancel() can remove the prerender from the map, we need to
+ // consider our iterator invalid.
+ id_to_handle_iter = ids_to_handle_map_.find(child_and_prerender_id);
+ if (id_to_handle_iter != ids_to_handle_map_.end())
+ RemovePrerender(id_to_handle_iter);
}
void PrerenderLinkManager::OnAbandonPrerender(int child_id, int prerender_id) {
@@ -99,7 +118,6 @@ void PrerenderLinkManager::OnAbandonPrerender(int child_id, int prerender_id) {
return;
PrerenderHandle* prerender_handle = id_to_handle_iter->second;
prerender_handle->OnNavigateAway();
- RemovePrerender(id_to_handle_iter);
}
void PrerenderLinkManager::OnChannelClosing(int child_id) {
@@ -108,18 +126,21 @@ void PrerenderLinkManager::OnChannelClosing(int child_id) {
child_id, std::numeric_limits<int>::min());
const ChildAndPrerenderIdPair child_and_maximum_prerender_id(
child_id, std::numeric_limits<int>::max());
- std::queue<int> prerender_ids_to_abandon;
- for (IdPairToPrerenderHandleMap::iterator
- i = ids_to_handle_map_.lower_bound(child_and_minimum_prerender_id),
- e = ids_to_handle_map_.upper_bound(child_and_maximum_prerender_id);
- i != e; ++i) {
- prerender_ids_to_abandon.push(i->first.second);
- }
- while (!prerender_ids_to_abandon.empty()) {
- DVLOG(4) << "---> abandon prerender_id = "
- << prerender_ids_to_abandon.front();
- OnAbandonPrerender(child_id, prerender_ids_to_abandon.front());
- prerender_ids_to_abandon.pop();
+
+ IdPairToPrerenderHandleMap::iterator
+ it = ids_to_handle_map_.lower_bound(child_and_minimum_prerender_id);
+ IdPairToPrerenderHandleMap::iterator
+ end = ids_to_handle_map_.upper_bound(child_and_maximum_prerender_id);
+ while (it != end) {
+ IdPairToPrerenderHandleMap::iterator next = it;
+ ++next;
+
+ size_t size_before_abandon = ids_to_handle_map_.size();
+ OnAbandonPrerender(child_id, it->first.second);
+ DCHECK_EQ(size_before_abandon, ids_to_handle_map_.size());
+ RemovePrerender(it);
+
+ it = next;
}
}
@@ -134,4 +155,55 @@ void PrerenderLinkManager::RemovePrerender(
ids_to_handle_map_.erase(id_to_handle_iter);
}
+PrerenderLinkManager::IdPairToPrerenderHandleMap::iterator
+PrerenderLinkManager::FindPrerenderHandle(
+ PrerenderHandle* prerender_handle) {
+ for (IdPairToPrerenderHandleMap::iterator it = ids_to_handle_map_.begin();
+ it != ids_to_handle_map_.end(); ++it) {
+ if (it->second == prerender_handle)
+ return it;
+ }
+ return ids_to_handle_map_.end();
+}
+
+// In practice, this is always called from either
+// PrerenderLinkManager::OnAddPrerender in the regular case, or in the pending
+// prerender case, from PrerenderHandle::AdoptPrerenderDataFrom.
+void PrerenderLinkManager::OnPrerenderStart(
+ PrerenderHandle* prerender_handle) {
+ IdPairToPrerenderHandleMap::iterator it =
+ FindPrerenderHandle(prerender_handle);
+ DCHECK(it != ids_to_handle_map_.end());
+ const int child_id = it->first.first;
+ const int prerender_id = it->first.second;
+
+ Send(child_id, new PrerenderMsg_OnPrerenderStart(prerender_id));
+}
+
+void PrerenderLinkManager::OnPrerenderAddAlias(
+ PrerenderHandle* prerender_handle,
+ const GURL& alias_url) {
+ IdPairToPrerenderHandleMap::iterator it =
+ FindPrerenderHandle(prerender_handle);
+ if (it == ids_to_handle_map_.end())
+ return;
+ const int child_id = it->first.first;
+ const int prerender_id = it->first.second;
+
+ Send(child_id, new PrerenderMsg_OnPrerenderAddAlias(prerender_id, alias_url));
+}
+
+void PrerenderLinkManager::OnPrerenderStop(
+ PrerenderHandle* prerender_handle) {
+ IdPairToPrerenderHandleMap::iterator it =
+ FindPrerenderHandle(prerender_handle);
+ if (it == ids_to_handle_map_.end())
+ return;
+ const int child_id = it->first.first;
+ const int prerender_id = it->first.second;
+
+ Send(child_id, new PrerenderMsg_OnPrerenderStop(prerender_id));
+ RemovePrerender(it);
+}
+
} // namespace prerender
diff --git a/chrome/browser/prerender/prerender_link_manager.h b/chrome/browser/prerender/prerender_link_manager.h
index d9e9c00..8795f0a 100644
--- a/chrome/browser/prerender/prerender_link_manager.h
+++ b/chrome/browser/prerender/prerender_link_manager.h
@@ -9,6 +9,7 @@
#include <utility>
#include "base/basictypes.h"
+#include "chrome/browser/prerender/prerender_handle.h"
#include "chrome/browser/profiles/profile_keyed_service.h"
#include "googleurl/src/gurl.h"
@@ -31,7 +32,8 @@ class PrerenderManager;
// being rendered in this chrome instance. It receives messages from the
// renderer indicating addition, cancelation and abandonment of link elements,
// and controls the PrerenderManager accordingly.
-class PrerenderLinkManager : public ProfileKeyedService {
+class PrerenderLinkManager : public ProfileKeyedService,
+ public PrerenderHandle::Observer {
public:
explicit PrerenderLinkManager(PrerenderManager* manager);
virtual ~PrerenderLinkManager();
@@ -77,6 +79,15 @@ class PrerenderLinkManager : public ProfileKeyedService {
bool IsEmpty() const;
+ IdPairToPrerenderHandleMap::iterator FindPrerenderHandle(
+ PrerenderHandle* prerender_handle);
+
+ // From PrerenderHandle::Observer:
+ virtual void OnPrerenderStart(PrerenderHandle* prerender_handle) OVERRIDE;
+ virtual void OnPrerenderStop(PrerenderHandle* prerender_handle) OVERRIDE;
+ virtual void OnPrerenderAddAlias(PrerenderHandle* prerender_handle,
+ const GURL& alias_url) OVERRIDE;
+
PrerenderManager* manager_;
// A map from child process id and prerender id to PrerenderHandles. We map
diff --git a/chrome/browser/prerender/prerender_manager.cc b/chrome/browser/prerender/prerender_manager.cc
index b2121cf..ab6c7aa 100644
--- a/chrome/browser/prerender/prerender_manager.cc
+++ b/chrome/browser/prerender/prerender_manager.cc
@@ -223,7 +223,6 @@ PrerenderManager::~PrerenderManager() {
// The earlier call to ProfileKeyedService::Shutdown() should have emptied
// these vectors already.
DCHECK(active_prerenders_.empty());
- DCHECK(pending_prerenders_.empty());
DCHECK(to_delete_prerenders_.empty());
}
@@ -238,7 +237,6 @@ void PrerenderManager::Shutdown() {
profile_ = NULL;
DCHECK(active_prerenders_.empty());
- pending_prerenders_.clear();
}
PrerenderHandle* PrerenderManager::AddPrerenderFromLinkRelPrerender(
@@ -278,11 +276,8 @@ PrerenderHandle* PrerenderManager::AddPrerenderFromLinkRelPrerender(
// Instead of prerendering from inside of a running prerender, we will defer
// this request until its launcher is made visible.
if (PrerenderContents* contents = parent_prerender_data->contents()) {
- pending_prerenders_.push_back(new PrerenderData(this));
PrerenderHandle* prerender_handle =
- new PrerenderHandle(pending_prerenders_.back());
- DCHECK(prerender_handle->IsPending());
-
+ new PrerenderHandle(static_cast<PrerenderData*>(NULL));
scoped_ptr<PrerenderContents::PendingPrerenderInfo>
pending_prerender_info(new PrerenderContents::PendingPrerenderInfo(
prerender_handle->weak_ptr_factory_.GetWeakPtr(),
@@ -429,7 +424,7 @@ bool PrerenderManager::MaybeUsePrerenderedPage(WebContents* web_contents,
// Start pending prerender requests from the PrerenderContents, if there are
// any.
- prerender_contents->StartPendingPrerenders();
+ prerender_contents->PrepareForUse();
WebContents* new_web_contents =
prerender_contents->ReleasePrerenderContents();
@@ -501,7 +496,7 @@ void PrerenderManager::MoveEntryToPendingDelete(PrerenderContents* entry,
ActuallyPrerendering()) {
// TODO(tburkard): I'd like to DCHECK that we are actually prerendering.
// However, what if new conditions are added and
- // NeedMatchCompleteDummyForFinalStatus, is not being updated. Not sure
+ // NeedMatchCompleteDummyForFinalStatus is not being updated. Not sure
// what's the best thing to do here. For now, I will just check whether
// we are actually prerendering.
(*it)->MakeIntoMatchCompleteReplacement();
@@ -511,7 +506,7 @@ void PrerenderManager::MoveEntryToPendingDelete(PrerenderContents* entry,
}
// Destroy the old WebContents relatively promptly to reduce resource usage,
- // and in the case of HTML5 media, reduce the change of playing any sound.
+ // and in the case of HTML5 media, reduce the chance of playing any sound.
PostCleanupTask();
}
@@ -851,10 +846,6 @@ struct PrerenderManager::PrerenderData::OrderByExpiryTime {
}
};
-PrerenderManager::PrerenderData::PrerenderData(PrerenderManager* manager)
- : manager_(manager), contents_(NULL), handle_count_(0) {
-}
-
PrerenderManager::PrerenderData::PrerenderData(PrerenderManager* manager,
PrerenderContents* contents,
base::TimeTicks expiry_time)
@@ -862,6 +853,7 @@ PrerenderManager::PrerenderData::PrerenderData(PrerenderManager* manager,
contents_(contents),
handle_count_(0),
expiry_time_(expiry_time) {
+ DCHECK_NE(static_cast<PrerenderContents*>(NULL), contents_);
}
PrerenderManager::PrerenderData::~PrerenderData() {
@@ -877,39 +869,29 @@ void PrerenderManager::PrerenderData::MakeIntoMatchCompleteReplacement() {
manager_->to_delete_prerenders_.push_back(to_delete);
}
-void PrerenderManager::PrerenderData::OnNewHandle() {
- DCHECK(contents_ || handle_count_ == 0) <<
- "Cannot create multiple handles to a pending prerender.";
+void PrerenderManager::PrerenderData::OnHandleCreated(PrerenderHandle* handle) {
+ DCHECK_NE(static_cast<PrerenderContents*>(NULL), contents_);
++handle_count_;
+ contents_->AddObserver(handle);
}
-void PrerenderManager::PrerenderData::OnNavigateAwayByHandle() {
- if (!contents_) {
- DCHECK_EQ(1, handle_count_);
- // Pending prerenders are not maintained in the active_prerenders_, so they
- // will not get normal expiry. Since this prerender hasn't even been
- // launched yet, and it's held by a page that is being prerendered, we will
- // just delete it.
- manager_->DestroyPendingPrerenderData(this);
- } else {
- DCHECK_LE(0, handle_count_);
- // We intentionally don't decrement the handle count here, so that the
- // prerender won't be canceled until it times out.
- manager_->SourceNavigatedAway(this);
- }
+void PrerenderManager::PrerenderData::OnHandleNavigatedAway(
+ PrerenderHandle* handle) {
+ DCHECK_LT(0, handle_count_);
+ DCHECK_NE(static_cast<PrerenderContents*>(NULL), contents_);
+ // We intentionally don't decrement the handle count here, so that the
+ // prerender won't be canceled until it times out.
+ manager_->SourceNavigatedAway(this);
}
-void PrerenderManager::PrerenderData::OnCancelByHandle() {
- DCHECK_LE(1, handle_count_);
- DCHECK(contents_ || handle_count_ == 1);
+void PrerenderManager::PrerenderData::OnHandleCanceled(
+ PrerenderHandle* handle) {
+ DCHECK_LT(0, handle_count_);
+ DCHECK_NE(static_cast<PrerenderContents*>(NULL), contents_);
if (--handle_count_ == 0) {
- if (contents_) {
- // This will eventually remove this object from active_prerenders_.
- contents_->Destroy(FINAL_STATUS_CANCELLED);
- } else {
- manager_->DestroyPendingPrerenderData(this);
- }
+ // This will eventually remove this object from active_prerenders_.
+ contents_->Destroy(FINAL_STATUS_CANCELLED);
}
}
@@ -933,31 +915,24 @@ void PrerenderManager::StartPendingPrerenders(
PrerenderContents::PendingPrerenderInfo* info = *it;
PrerenderHandle* existing_prerender_handle =
info->weak_prerender_handle.get();
- if (!existing_prerender_handle || !existing_prerender_handle->IsValid())
+ if (!existing_prerender_handle)
continue;
- DCHECK(existing_prerender_handle->IsPending());
+ DCHECK(!existing_prerender_handle->IsPrerendering());
DCHECK(process_id == -1 || session_storage_namespace);
- scoped_ptr<PrerenderHandle> swap_prerender_handle(AddPrerender(
+ scoped_ptr<PrerenderHandle> new_prerender_handle(AddPrerender(
info->origin, process_id,
info->url, info->referrer, info->size,
session_storage_namespace));
- if (swap_prerender_handle.get()) {
+ if (new_prerender_handle) {
// AddPrerender has returned a new prerender handle to us. We want to make
- // |existing_prerender_handle| active, so swap the underlying
- // PrerenderData between the two handles, and delete our old handle (which
- // will release our entry in the pending_prerender_list_).
- existing_prerender_handle->SwapPrerenderDataWith(
- swap_prerender_handle.get());
- swap_prerender_handle->OnCancel();
+ // |existing_prerender_handle| active, so move the underlying
+ // PrerenderData to our new handle.
+ existing_prerender_handle->AdoptPrerenderDataFrom(
+ new_prerender_handle.get());
continue;
}
-
- // We could not start our Prerender. Canceling the existing handle will make
- // it return false for PrerenderHandle::IsPending(), and will release the
- // PrerenderData from pending_prerender_list_.
- existing_prerender_handle->OnCancel();
}
}
@@ -976,16 +951,6 @@ void PrerenderManager::SourceNavigatedAway(PrerenderData* prerender_data) {
SortActivePrerenders();
}
-void PrerenderManager::DestroyPendingPrerenderData(
- PrerenderData* pending_prerender_data) {
- ScopedVector<PrerenderData>::iterator it =
- std::find(pending_prerenders_.begin(), pending_prerenders_.end(),
- pending_prerender_data);
- if (it == pending_prerenders_.end())
- return;
- pending_prerenders_.erase(it);
-}
-
// private
PrerenderHandle* PrerenderManager::AddPrerender(
Origin origin,
diff --git a/chrome/browser/prerender/prerender_manager.h b/chrome/browser/prerender/prerender_manager.h
index b462b62..d241358 100644
--- a/chrome/browser/prerender/prerender_manager.h
+++ b/chrome/browser/prerender/prerender_manager.h
@@ -268,10 +268,6 @@ class PrerenderManager : public base::SupportsWeakPtr<PrerenderManager>,
public:
struct OrderByExpiryTime;
- // Constructor for a pending prerender, which will get its contents later.
- explicit PrerenderData(PrerenderManager* manager);
-
- // Constructor for an active prerender.
PrerenderData(PrerenderManager* manager,
PrerenderContents* contents,
base::TimeTicks expiry_time);
@@ -283,18 +279,18 @@ class PrerenderManager : public base::SupportsWeakPtr<PrerenderManager>,
void MakeIntoMatchCompleteReplacement();
// A new PrerenderHandle has been created for this PrerenderData.
- void OnNewHandle();
+ void OnHandleCreated(PrerenderHandle* prerender_handle);
// The launcher associated with a handle is navigating away from the context
// that launched this prerender. If the prerender is active, it may stay
// alive briefly though, in case we we going through a redirect chain that
// will eventually land at it.
- void OnNavigateAwayByHandle();
+ void OnHandleNavigatedAway(PrerenderHandle* prerender_handle);
// The launcher associated with a handle has taken explicit action to cancel
// this prerender. We may well destroy the prerender in this case if no
// other handles continue to track it.
- void OnCancelByHandle();
+ void OnHandleCanceled(PrerenderHandle* prerender_handle);
PrerenderContents* contents() { return contents_.get(); }
@@ -312,8 +308,8 @@ class PrerenderManager : public base::SupportsWeakPtr<PrerenderManager>,
scoped_ptr<PrerenderContents> contents_;
// The number of distinct PrerenderHandles created for |this|, including
- // ones that have called PrerenderData::OnNavigateAwayByHandle(), but not
- // counting the ones that have called PrerenderData::OnCancelByHandle(). For
+ // ones that have called PrerenderData::OnHandleNavigatedAway(), but not
+ // counting the ones that have called PrerenderData::OnHandleCanceled(). For
// pending prerenders, this will always be 1, since the PrerenderManager
// only merges handles of running prerenders.
int handle_count_;
@@ -335,11 +331,6 @@ class PrerenderManager : public base::SupportsWeakPtr<PrerenderManager>,
ScopedVector<PrerenderContents::PendingPrerenderInfo>* pending_prerenders,
content::SessionStorageNamespace* session_storage_namespace);
- // Called by a PrerenderData to self-destroy, but only when the PrerenderData
- // is pending (as in not yet active). Should not be called except for
- // objects known to be in |pending_prerender_list_|.
- void DestroyPendingPrerenderData(PrerenderData* pending_prerender_data);
-
// Called by a PrerenderData to signal that the launcher has navigated away
// from the context that launched the prerender. A user may have clicked
// a link in a page containing a <link rel=prerender> element, or the user
@@ -519,9 +510,6 @@ class PrerenderManager : public base::SupportsWeakPtr<PrerenderManager>,
// All running prerenders. Sorted by expiry time, in ascending order.
ScopedVector<PrerenderData> active_prerenders_;
- // All pending prerenders.
- ScopedVector<PrerenderData> pending_prerenders_;
-
// Prerenders awaiting deletion.
ScopedVector<PrerenderData> to_delete_prerenders_;
diff --git a/chrome/browser/prerender/prerender_tracker_unittest.cc b/chrome/browser/prerender/prerender_tracker_unittest.cc
index 7e9a4a6..a736b0b 100644
--- a/chrome/browser/prerender/prerender_tracker_unittest.cc
+++ b/chrome/browser/prerender/prerender_tracker_unittest.cc
@@ -58,6 +58,7 @@ class TestPrerenderContents : public PrerenderContents {
void Use() {
SetFinalStatus(FINAL_STATUS_USED);
+ PrepareForUse();
}
private:
diff --git a/chrome/browser/prerender/prerender_unittest.cc b/chrome/browser/prerender/prerender_unittest.cc
index 27fa12a..45e48f8 100644
--- a/chrome/browser/prerender/prerender_unittest.cc
+++ b/chrome/browser/prerender/prerender_unittest.cc
@@ -135,7 +135,7 @@ class UnitTestPrerenderManager : public PrerenderManager {
active_prerenders_.erase(to_erase);
prerender_contents->SetFinalStatus(FINAL_STATUS_USED);
- prerender_contents->StartPendingPrerenders();
+ prerender_contents->PrepareForUse();
return prerender_contents;
}
@@ -362,12 +362,10 @@ TEST_F(PrerenderTest, DuplicateTest) {
kDefaultChildId, kDefaultRenderViewRouteId, url,
Referrer(url, WebKit::WebReferrerPolicyDefault), kSize));
- EXPECT_TRUE(duplicate_prerender_handle->IsValid());
EXPECT_TRUE(duplicate_prerender_handle->IsPrerendering());
ASSERT_EQ(prerender_contents, prerender_manager()->FindAndUseEntry(url));
- EXPECT_FALSE(duplicate_prerender_handle->IsValid());
EXPECT_FALSE(duplicate_prerender_handle->IsPrerendering());
}
@@ -649,13 +647,12 @@ TEST_F(PrerenderTest, PendingPrerenderTest) {
child_id, route_id, pending_url,
Referrer(url, WebKit::WebReferrerPolicyDefault), kSize));
CHECK(pending_prerender_handle.get());
- EXPECT_TRUE(pending_prerender_handle->IsValid());
- EXPECT_TRUE(pending_prerender_handle->IsPending());
+ EXPECT_FALSE(pending_prerender_handle->IsPrerendering());
EXPECT_TRUE(prerender_contents->prerendering_has_started());
ASSERT_EQ(prerender_contents, prerender_manager()->FindAndUseEntry(url));
- EXPECT_FALSE(pending_prerender_handle->IsPending());
+ EXPECT_TRUE(pending_prerender_handle->IsPrerendering());
ASSERT_EQ(pending_prerender_contents,
prerender_manager()->FindAndUseEntry(pending_url));
}
@@ -686,14 +683,12 @@ TEST_F(PrerenderTest, InvalidPendingPrerenderTest) {
child_id, route_id, pending_url,
Referrer(url, WebKit::WebReferrerPolicyDefault), kSize));
DCHECK(pending_prerender_handle.get());
- EXPECT_TRUE(pending_prerender_handle->IsValid());
- EXPECT_TRUE(pending_prerender_handle->IsPending());
+ EXPECT_FALSE(pending_prerender_handle->IsPrerendering());
EXPECT_TRUE(prerender_contents->prerendering_has_started());
ASSERT_EQ(prerender_contents, prerender_manager()->FindAndUseEntry(url));
- EXPECT_FALSE(pending_prerender_handle->IsValid());
- EXPECT_FALSE(pending_prerender_handle->IsPending());
+ EXPECT_FALSE(pending_prerender_handle->IsPrerendering());
}
TEST_F(PrerenderTest, CancelPendingPrerenderTest) {
@@ -716,13 +711,11 @@ TEST_F(PrerenderTest, CancelPendingPrerenderTest) {
child_id, route_id, pending_url,
Referrer(url, WebKit::WebReferrerPolicyDefault), kSize));
CHECK(pending_prerender_handle.get());
- EXPECT_TRUE(pending_prerender_handle->IsValid());
- EXPECT_TRUE(pending_prerender_handle->IsPending());
+ EXPECT_FALSE(pending_prerender_handle->IsPrerendering());
EXPECT_TRUE(prerender_contents->prerendering_has_started());
- pending_prerender_handle->OnCancel();
- EXPECT_FALSE(pending_prerender_handle->IsValid());
+ pending_prerender_handle.reset();
ASSERT_EQ(prerender_contents, prerender_manager()->FindAndUseEntry(url));
}
@@ -793,6 +786,7 @@ TEST_F(PrerenderTest, PPLTDummy) {
url, FINAL_STATUS_UNSUPPORTED_SCHEME);
EXPECT_TRUE(AddSimplePrerender(url));
EXPECT_TRUE(prerender_contents->prerendering_has_started());
+ EXPECT_FALSE(IsEmptyPrerenderLinkManager());
DummyPrerenderContents* pplt_dummy_contents =
prerender_manager()->CreateNextPrerenderContents(url,
@@ -800,8 +794,10 @@ TEST_F(PrerenderTest, PPLTDummy) {
GURL ftp_url("ftp://ftp.google.com/");
// Adding this ftp URL will force the expected unsupported scheme error.
prerender_contents->AddAliasURL(ftp_url);
+ EXPECT_FALSE(IsEmptyPrerenderLinkManager());
ASSERT_EQ(pplt_dummy_contents, prerender_manager()->FindAndUseEntry(url));
+ EXPECT_TRUE(IsEmptyPrerenderLinkManager());
}
// Tests that our PPLT dummy prerender gets created properly, even
@@ -839,13 +835,14 @@ TEST_F(PrerenderTest, PPLTLateCancel) {
prerender_contents->Destroy(FINAL_STATUS_JAVASCRIPT_ALERT);
ASSERT_EQ(duplicate_prerender_contents, prerender_manager()->FindEntry(url));
+ // Make sure that events on prerender handles propogate to the match
+ // complete replacement.
+ DummyPrerenderContents* null = NULL;
prerender_link_manager()->OnCancelPrerender(kDefaultChildId,
last_prerender_id());
- DummyPrerenderContents* null = NULL;
ASSERT_EQ(null, prerender_manager()->FindEntry(url));
}
-
// Tests that the prerender manager matches include the fragment.
TEST_F(PrerenderTest, FragmentMatchesTest) {
GURL fragment_url("http://www.google.com/#test");
@@ -966,8 +963,6 @@ TEST_F(PrerenderTest, LinkManagerCancelThenAbandon) {
ASSERT_EQ(null, prerender_manager()->FindEntry(url));
}
-// TODO(gavinp): Re-enabmed this test after abandon has an effect on Prerenders,
-// like shortening the timeouts.
TEST_F(PrerenderTest, LinkManagerAbandon) {
EXPECT_TRUE(IsEmptyPrerenderLinkManager());
GURL url("http://www.myexample.com");
@@ -986,7 +981,33 @@ TEST_F(PrerenderTest, LinkManagerAbandon) {
EXPECT_FALSE(prerender_contents->prerendering_has_been_cancelled());
ASSERT_EQ(prerender_contents, prerender_manager()->FindAndUseEntry(url));
+}
+
+TEST_F(PrerenderTest, LinkManagerAbandonThenCancel) {
EXPECT_TRUE(IsEmptyPrerenderLinkManager());
+ GURL url("http://www.myexample.com");
+ DummyPrerenderContents* prerender_contents =
+ prerender_manager()->CreateNextPrerenderContents(
+ url, FINAL_STATUS_CANCELLED);
+
+ EXPECT_TRUE(AddSimplePrerender(url));
+
+ EXPECT_TRUE(prerender_contents->prerendering_has_started());
+ EXPECT_FALSE(prerender_contents->prerendering_has_been_cancelled());
+ ASSERT_EQ(prerender_contents, prerender_manager()->FindEntry(url));
+ EXPECT_FALSE(IsEmptyPrerenderLinkManager());
+ prerender_link_manager()->OnAbandonPrerender(kDefaultChildId,
+ last_prerender_id());
+
+ EXPECT_FALSE(prerender_contents->prerendering_has_been_cancelled());
+ ASSERT_EQ(prerender_contents, prerender_manager()->FindEntry(url));
+
+ prerender_link_manager()->OnCancelPrerender(kDefaultChildId,
+ last_prerender_id());
+ EXPECT_TRUE(IsEmptyPrerenderLinkManager());
+ EXPECT_TRUE(prerender_contents->prerendering_has_been_cancelled());
+ DummyPrerenderContents* null = NULL;
+ ASSERT_EQ(null, prerender_manager()->FindEntry(url));
}
TEST_F(PrerenderTest, LinkManagerCancelTwice) {
@@ -1116,7 +1137,6 @@ TEST_F(PrerenderTest, LinkManagerAddTwiceAbandonTwice) {
prerender_link_manager()->OnAbandonPrerender(kDefaultChildId,
second_prerender_id);
- EXPECT_TRUE(IsEmptyPrerenderLinkManager());
EXPECT_FALSE(prerender_contents->prerendering_has_been_cancelled());
ASSERT_EQ(prerender_contents, prerender_manager()->FindAndUseEntry(url));
}
@@ -1172,9 +1192,6 @@ TEST_F(PrerenderTest, LinkManagerExpireThenAddAgain) {
EXPECT_TRUE(second_prerender_contents->prerendering_has_started());
ASSERT_EQ(second_prerender_contents,
prerender_manager()->FindAndUseEntry(url));
- // The PrerenderLinkManager is not empty since we never removed the first
- // prerender.
- EXPECT_FALSE(IsEmptyPrerenderLinkManager());
}
TEST_F(PrerenderTest, LinkManagerCancelThenAddAgain) {
@@ -1200,7 +1217,29 @@ TEST_F(PrerenderTest, LinkManagerCancelThenAddAgain) {
EXPECT_TRUE(second_prerender_contents->prerendering_has_started());
ASSERT_EQ(second_prerender_contents,
prerender_manager()->FindAndUseEntry(url));
- EXPECT_FALSE(IsEmptyPrerenderLinkManager());
+}
+
+TEST_F(PrerenderTest, LinkManagerChannelClosing) {
+ EXPECT_TRUE(IsEmptyPrerenderLinkManager());
+ GURL url("http://www.myexample.com");
+ DummyPrerenderContents* prerender_contents =
+ prerender_manager()->CreateNextPrerenderContents(
+ url, FINAL_STATUS_TIMED_OUT);
+
+ EXPECT_TRUE(AddSimplePrerender(url));
+ EXPECT_TRUE(prerender_contents->prerendering_has_started());
+ EXPECT_FALSE(prerender_contents->prerendering_has_been_cancelled());
+ ASSERT_EQ(prerender_contents, prerender_manager()->FindEntry(url));
+
+ prerender_link_manager()->OnChannelClosing(kDefaultChildId);
+
+ prerender_manager()->AdvanceTimeTicks(
+ prerender_manager()->config().abandon_time_to_live +
+ TimeDelta::FromSeconds(1));
+
+ DummyPrerenderContents* null = NULL;
+ EXPECT_EQ(null, prerender_manager()->FindEntry(url));
+ EXPECT_TRUE(IsEmptyPrerenderLinkManager());
}
} // namespace prerender