summaryrefslogtreecommitdiffstats
path: root/chrome/browser/prerender
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser/prerender')
-rw-r--r--chrome/browser/prerender/prerender_browsertest.cc48
-rw-r--r--chrome/browser/prerender/prerender_contents.cc40
-rw-r--r--chrome/browser/prerender/prerender_contents.h36
-rw-r--r--chrome/browser/prerender/prerender_manager.cc101
-rw-r--r--chrome/browser/prerender/prerender_manager.h20
-rw-r--r--chrome/browser/prerender/prerender_manager_unittest.cc4
6 files changed, 131 insertions, 118 deletions
diff --git a/chrome/browser/prerender/prerender_browsertest.cc b/chrome/browser/prerender/prerender_browsertest.cc
index c888cc3..dc17d15e 100644
--- a/chrome/browser/prerender/prerender_browsertest.cc
+++ b/chrome/browser/prerender/prerender_browsertest.cc
@@ -115,7 +115,7 @@ class TestPrerenderContents : public PrerenderContents {
was_hidden_(false),
was_shown_(false),
should_be_shown_(expected_final_status == FINAL_STATUS_USED),
- quit_message_loop_on_destruction_(true) {
+ expected_pending_prerenders_(0) {
if (expected_number_of_loads == 0)
MessageLoopForUI::current()->Quit();
}
@@ -143,8 +143,7 @@ class TestPrerenderContents : public PrerenderContents {
// When the PrerenderContents is destroyed, quit the UI message loop.
// This happens on navigation to used prerendered pages, and soon
// after cancellation of unused prerendered pages.
- if (quit_message_loop_on_destruction_)
- MessageLoopForUI::current()->Quit();
+ MessageLoopForUI::current()->Quit();
}
virtual void RenderViewGone() OVERRIDE {
@@ -181,18 +180,33 @@ class TestPrerenderContents : public PrerenderContents {
}
}
+ virtual void AddPendingPrerender(Origin origin,
+ const GURL& url,
+ const GURL& referrer) {
+ PrerenderContents::AddPendingPrerender(origin, url, referrer);
+ if (expected_pending_prerenders_ > 0 &&
+ pending_prerender_list()->size() == expected_pending_prerenders_) {
+ MessageLoop::current()->Quit();
+ }
+ }
+
+ // Waits until the prerender has |expected_pending_prerenders| pending
+ // prerenders.
+ void WaitForPendingPrerenders(size_t expected_pending_prerenders) {
+ if (pending_prerender_list()->size() < expected_pending_prerenders) {
+ expected_pending_prerenders_ = expected_pending_prerenders;
+ ui_test_utils::RunMessageLoop();
+ expected_pending_prerenders_ = 0;
+ }
+
+ EXPECT_EQ(expected_pending_prerenders, pending_prerender_list()->size());
+ }
+
// For tests that open the prerender in a new background tab, the RenderView
// will not have been made visible when the PrerenderContents is destroyed
// even though it is used.
void set_should_be_shown(bool value) { should_be_shown_ = value; }
- // Some of the ui_test_utils calls that we use assume that no one will quit
- // the message loop that they run internally. So we dont quit the message
- // loop in the destructor so as not to interfere.
- void set_quit_message_loop_on_destruction(bool value) {
- quit_message_loop_on_destruction_ = value;
- }
-
int number_of_loads() const { return number_of_loads_; }
private:
@@ -246,7 +260,9 @@ class TestPrerenderContents : public PrerenderContents {
// FINAL_STATUS_USED, and false otherwise.
bool should_be_shown_;
- bool quit_message_loop_on_destruction_;
+ // Total number of pending prerenders we're currently waiting for. Zero
+ // indicates we currently aren't waiting for any.
+ size_t expected_pending_prerenders_;
};
// PrerenderManager that uses TestPrerenderContents.
@@ -530,7 +546,7 @@ class PrerenderBrowserTest : public InProcessBrowserTest {
bool UrlIsPendingInPrerenderManager(const std::string& html_file) {
GURL dest_url = test_server()->GetURL(html_file);
- return (prerender_manager()->FindPendingEntry(dest_url) != NULL);
+ return prerender_manager()->IsPendingEntry(dest_url);
}
void set_use_https_src(bool use_https_src_server) {
@@ -1077,6 +1093,8 @@ IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, PrerenderInfiniteLoop) {
expected_final_status_queue.push_back(FINAL_STATUS_APP_TERMINATING);
PrerenderTestURL(kHtmlFileA, expected_final_status_queue, 1);
+ ASSERT_TRUE(GetPrerenderContents());
+ GetPrerenderContents()->WaitForPendingPrerenders(1u);
// Next url should be in pending list but not an active entry.
EXPECT_FALSE(UrlIsInPrerenderManager(kHtmlFileB));
@@ -1092,9 +1110,7 @@ IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, PrerenderInfiniteLoop) {
// Checks that we don't prerender in an infinite loop and multiple links are
// handled correctly.
-// Flaky, http://crbug.com/77323, but failing in a CHECK so disabled.
-IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest,
- DISABLED_PrerenderInfiniteLoopMultiple) {
+IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, PrerenderInfiniteLoopMultiple) {
const char* const kHtmlFileA =
"files/prerender/prerender_infinite_a_multiple.html";
const char* const kHtmlFileB =
@@ -1111,6 +1127,8 @@ IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest,
expected_final_status_queue.push_back(FINAL_STATUS_APP_TERMINATING);
PrerenderTestURL(kHtmlFileA, expected_final_status_queue, 1);
+ ASSERT_TRUE(GetPrerenderContents());
+ GetPrerenderContents()->WaitForPendingPrerenders(2u);
// Next url should be in pending list but not an active entry.
EXPECT_FALSE(UrlIsInPrerenderManager(kHtmlFileB));
diff --git a/chrome/browser/prerender/prerender_contents.cc b/chrome/browser/prerender/prerender_contents.cc
index 7541afc..fbc8b5b 100644
--- a/chrome/browser/prerender/prerender_contents.cc
+++ b/chrome/browser/prerender/prerender_contents.cc
@@ -70,6 +70,15 @@ class PrerenderContentsFactoryImpl : public PrerenderContents::Factory {
}
};
+PrerenderContents::PendingPrerenderData::PendingPrerenderData(
+ Origin origin,
+ const GURL& url,
+ const GURL& referrer)
+ : origin(origin),
+ url(url),
+ referrer(referrer) {
+}
+
// TabContentsDelegateImpl -----------------------------------------------------
class PrerenderContents::TabContentsDelegateImpl
@@ -134,6 +143,37 @@ class PrerenderContents::TabContentsDelegateImpl
PrerenderContents* prerender_contents_;
};
+void PrerenderContents::AddPendingPrerender(Origin origin,
+ const GURL& url,
+ const GURL& referrer) {
+ pending_prerender_list_.push_back(
+ PendingPrerenderData(origin, url, referrer));
+}
+
+bool PrerenderContents::IsPendingEntry(const GURL& url) const {
+ for (PendingPrerenderList::const_iterator it =
+ pending_prerender_list_.begin();
+ it != pending_prerender_list_.end();
+ ++it) {
+ if (it->url == url)
+ return true;
+ }
+ return false;
+}
+
+void PrerenderContents::StartPendingPrerenders() {
+ PendingPrerenderList pending_prerender_list;
+ pending_prerender_list.swap(pending_prerender_list_);
+ for (PendingPrerenderList::iterator it = pending_prerender_list.begin();
+ it != pending_prerender_list.end();
+ ++it) {
+ prerender_manager_->AddPrerender(it->origin,
+ std::make_pair(child_id_, route_id_),
+ it->url,
+ it->referrer);
+ }
+}
+
PrerenderContents::PrerenderContents(PrerenderManager* prerender_manager,
PrerenderTracker* prerender_tracker,
Profile* profile,
diff --git a/chrome/browser/prerender/prerender_contents.h b/chrome/browser/prerender/prerender_contents.h
index a0c2d17..874502e 100644
--- a/chrome/browser/prerender/prerender_contents.h
+++ b/chrome/browser/prerender/prerender_contents.h
@@ -6,6 +6,7 @@
#define CHROME_BROWSER_PRERENDER_PRERENDER_CONTENTS_H_
#pragma once
+#include <list>
#include <string>
#include <vector>
@@ -68,6 +69,16 @@ class PrerenderContents : public NotificationObserver,
DISALLOW_COPY_AND_ASSIGN(Factory);
};
+ // Information on pages that the prerendered page has tried to prerender.
+ struct PendingPrerenderData {
+ PendingPrerenderData(Origin origin, const GURL& url, const GURL& referrer);
+
+ Origin origin;
+ GURL url;
+ GURL referrer;
+ };
+ typedef std::list<PendingPrerenderData> PendingPrerenderList;
+
virtual ~PrerenderContents();
bool Init();
@@ -167,6 +178,18 @@ class PrerenderContents : public NotificationObserver,
// MouseEvent being dispatched by a link to a website installed as an app.
bool IsCrossSiteNavigationPending() const;
+ // Adds a pending prerender to the list.
+ virtual void AddPendingPrerender(Origin origin,
+ const GURL& url,
+ const GURL& referrer);
+
+ // Returns true if |url| corresponds to a pending prerender.
+ bool IsPendingEntry(const GURL& url) const;
+
+ // Reissues any pending prerender requests from the prerendered page. Also
+ // clears the list of pending requests.
+ void StartPendingPrerenders();
+
protected:
PrerenderContents(PrerenderManager* prerender_manager,
PrerenderTracker* prerender_tracker,
@@ -176,13 +199,17 @@ class PrerenderContents : public NotificationObserver,
Origin origin,
uint8 experiment_id);
+ // Called whenever a RenderViewHost is created for prerendering. Only called
+ // once the RenderViewHost has a RenderView and RenderWidgetHostView.
+ virtual void OnRenderViewHostCreated(RenderViewHost* new_render_view_host);
+
NotificationRegistrar& notification_registrar() {
return notification_registrar_;
}
- // Called whenever a RenderViewHost is created for prerendering. Only called
- // once the RenderViewHost has a RenderView and RenderWidgetHostView.
- virtual void OnRenderViewHostCreated(RenderViewHost* new_render_view_host);
+ const PendingPrerenderList* pending_prerender_list() const {
+ return &pending_prerender_list_;
+ }
private:
class TabContentsDelegateImpl;
@@ -276,6 +303,9 @@ class PrerenderContents : public NotificationObserver,
// Experiment during which this prerender is performed.
uint8 experiment_id_;
+ // List of all pages the prerendered page has tried to prerender.
+ PendingPrerenderList pending_prerender_list_;
+
// Offset by which to offset prerendered pages
static const int32 kPrerenderPageIdOffset = 10;
diff --git a/chrome/browser/prerender/prerender_manager.cc b/chrome/browser/prerender/prerender_manager.cc
index 61a8867..755dbcb 100644
--- a/chrome/browser/prerender/prerender_manager.cc
+++ b/chrome/browser/prerender/prerender_manager.cc
@@ -158,17 +158,6 @@ struct PrerenderManager::NavigationRecord {
}
};
-struct PrerenderManager::PendingContentsData {
- PendingContentsData(const GURL& url,
- const GURL& referrer,
- Origin origin)
- : url_(url), referrer_(referrer), origin_(origin) { }
- ~PendingContentsData() {}
- GURL url_;
- GURL referrer_;
- Origin origin_;
-};
-
class PrerenderManager::MostVisitedSites : public NotificationObserver {
public:
explicit MostVisitedSites(Profile* profile) :
@@ -229,6 +218,18 @@ bool PrerenderManager::IsTopSite(const GURL& url) {
return most_visited_->IsTopSite(url);
}
+bool PrerenderManager::IsPendingEntry(const GURL& url) const {
+ DCHECK(CalledOnValidThread());
+ for (std::list<PrerenderContentsData>::const_iterator it =
+ prerender_list_.begin();
+ it != prerender_list_.end();
+ ++it) {
+ if (it->contents_->IsPendingEntry(url))
+ return true;
+ }
+ return false;
+}
+
PrerenderManager::PrerenderManager(Profile* profile,
PrerenderTracker* prerender_tracker)
: enabled_(true),
@@ -288,9 +289,11 @@ bool PrerenderManager::AddPrerender(
histograms_->RecordPrerender(origin, url_arg);
// If the referring page is prerendering, defer the prerender.
- if (FindPrerenderContentsForChildRouteIdPair(child_route_id_pair) !=
- prerender_list_.end()) {
- AddPendingPrerender(origin, child_route_id_pair, url_arg, referrer);
+ std::list<PrerenderContentsData>::iterator source_prerender =
+ FindPrerenderContentsForChildRouteIdPair(child_route_id_pair);
+ if (source_prerender != prerender_list_.end()) {
+ source_prerender->contents_->AddPendingPrerender(
+ origin, url_arg, referrer);
return true;
}
@@ -371,24 +374,6 @@ bool PrerenderManager::AddPrerender(
return true;
}
-void PrerenderManager::AddPendingPrerender(
- Origin origin,
- const std::pair<int, int>& child_route_id_pair,
- const GURL& url,
- const GURL& referrer) {
- DCHECK(FindPrerenderContentsForChildRouteIdPair(child_route_id_pair) !=
- prerender_list_.end());
- PendingPrerenderList::iterator it =
- pending_prerender_list_.find(child_route_id_pair);
- if (it == pending_prerender_list_.end()) {
- PendingPrerenderList::value_type el = std::make_pair(child_route_id_pair,
- std::vector<PendingContentsData>());
- it = pending_prerender_list_.insert(el).first;
- }
-
- it->second.push_back(PendingContentsData(url, referrer, origin));
-}
-
std::list<PrerenderManager::PrerenderContentsData>::iterator
PrerenderManager::FindPrerenderContentsForChildRouteIdPair(
const std::pair<int, int>& child_route_id_pair) {
@@ -579,20 +564,9 @@ bool PrerenderManager::MaybeUsePrerenderedPage(TabContents* tab_contents,
DCHECK(prerender_tab_helper != NULL);
prerender_tab_helper->PrerenderSwappedIn();
- // See if we have any pending prerender requests for this routing id and start
- // the preload if we do.
- std::pair<int, int> child_route_pair = std::make_pair(child_id, route_id);
- PendingPrerenderList::iterator pending_it =
- pending_prerender_list_.find(child_route_pair);
- if (pending_it != pending_prerender_list_.end()) {
- for (std::vector<PendingContentsData>::iterator content_it =
- pending_it->second.begin();
- content_it != pending_it->second.end(); ++content_it) {
- AddPrerender(content_it->origin_, child_route_pair,
- content_it->url_, content_it->referrer_);
- }
- pending_prerender_list_.erase(pending_it);
- }
+ // Start pending prerender requests from the PrerenderContents, if there are
+ // any.
+ prerender_contents->StartPendingPrerenders();
if (old_tab_contents->tab_contents()->NeedToFireBeforeUnload()) {
// Schedule the delete to occur after the tab has run its unload handlers.
@@ -617,7 +591,6 @@ void PrerenderManager::MoveEntryToPendingDelete(PrerenderContents* entry) {
it != prerender_list_.end();
++it) {
if (it->contents_ == entry) {
- RemovePendingPrerender(entry);
prerender_list_.erase(it);
break;
}
@@ -732,40 +705,6 @@ PrerenderContents* PrerenderManager::FindEntry(const GURL& url) {
return NULL;
}
-PrerenderManager::PendingContentsData*
- PrerenderManager::FindPendingEntry(const GURL& url) {
- DCHECK(CalledOnValidThread());
- for (PendingPrerenderList::iterator map_it = pending_prerender_list_.begin();
- map_it != pending_prerender_list_.end();
- ++map_it) {
- for (std::vector<PendingContentsData>::iterator content_it =
- map_it->second.begin();
- content_it != map_it->second.end();
- ++content_it) {
- if (content_it->url_ == url) {
- return &(*content_it);
- }
- }
- }
-
- return NULL;
-}
-
-void PrerenderManager::RemovePendingPrerender(PrerenderContents* entry) {
- DCHECK(CalledOnValidThread());
- int child_id;
- int route_id;
- bool has_child_id = entry->GetChildId(&child_id);
- bool has_route_id = has_child_id && entry->GetRouteId(&route_id);
-
- // If the entry doesn't have a RenderViewHost then it didn't start
- // prerendering and there shouldn't be any pending preloads to remove.
- if (has_child_id && has_route_id) {
- std::pair<int, int> child_route_pair = std::make_pair(child_id, route_id);
- pending_prerender_list_.erase(child_route_pair);
- }
-}
-
bool PrerenderManager::DoesRateLimitAllowPrerender() const {
DCHECK(CalledOnValidThread());
base::TimeDelta elapsed_time =
diff --git a/chrome/browser/prerender/prerender_manager.h b/chrome/browser/prerender/prerender_manager.h
index acdf410..7f4d20e 100644
--- a/chrome/browser/prerender/prerender_manager.h
+++ b/chrome/browser/prerender/prerender_manager.h
@@ -7,9 +7,7 @@
#pragma once
#include <list>
-#include <map>
#include <string>
-#include <vector>
#include "base/hash_tables.h"
#include "base/memory/scoped_ptr.h"
@@ -210,19 +208,20 @@ class PrerenderManager : public base::SupportsWeakPtr<PrerenderManager>,
bool IsTopSite(const GURL& url);
+ bool IsPendingEntry(const GURL& url) const;
+
protected:
// Test that needs needs access to internal functions.
FRIEND_TEST_ALL_PREFIXES(PrerenderManagerTest, ExpireTest);
FRIEND_TEST_ALL_PREFIXES(PrerenderManagerTest, ExtractURLInQueryStringTest);
- struct PendingContentsData;
-
void SetPrerenderContentsFactory(
PrerenderContents::Factory* prerender_contents_factory);
- PendingContentsData* FindPendingEntry(const GURL& url);
-
private:
+ // Needs access to AddPrerender.
+ friend class PrerenderContents;
+
// Test that needs needs access to internal functions.
friend class PrerenderBrowserTest;
@@ -298,10 +297,6 @@ class PrerenderManager : public base::SupportsWeakPtr<PrerenderManager>,
// observed.
bool WithinWindow() const;
- // Called when removing a preload to ensure we clean up any pending preloads
- // that might remain in the map.
- void RemovePendingPrerender(PrerenderContents* entry);
-
bool DoesRateLimitAllowPrerender() const;
// Deletes old TabContents that have been replaced by prerendered ones. This
@@ -363,11 +358,6 @@ class PrerenderManager : public base::SupportsWeakPtr<PrerenderManager>,
// (for the control group).
base::hash_set<TabContents*> would_be_prerendered_tab_contents_set_;
- // Map of child/route id pairs to pending prerender data.
- typedef std::map<std::pair<int, int>, std::vector<PendingContentsData> >
- PendingPrerenderList;
- PendingPrerenderList pending_prerender_list_;
-
scoped_ptr<PrerenderContents::Factory> prerender_contents_factory_;
static PrerenderManagerMode mode_;
diff --git a/chrome/browser/prerender/prerender_manager_unittest.cc b/chrome/browser/prerender/prerender_manager_unittest.cc
index 3184de4..9389d2d 100644
--- a/chrome/browser/prerender/prerender_manager_unittest.cc
+++ b/chrome/browser/prerender/prerender_manager_unittest.cc
@@ -127,10 +127,6 @@ class TestPrerenderManager : public PrerenderManager {
GURL());
}
- bool IsPendingEntry(const GURL& url) {
- return (PrerenderManager::FindPendingEntry(url) != NULL);
- }
-
void set_rate_limit_enabled(bool enabled) {
mutable_config().rate_limit_enabled = enabled;
}