diff options
Diffstat (limited to 'chrome/browser/prerender')
-rw-r--r-- | chrome/browser/prerender/prerender_browsertest.cc | 48 | ||||
-rw-r--r-- | chrome/browser/prerender/prerender_contents.cc | 40 | ||||
-rw-r--r-- | chrome/browser/prerender/prerender_contents.h | 36 | ||||
-rw-r--r-- | chrome/browser/prerender/prerender_manager.cc | 101 | ||||
-rw-r--r-- | chrome/browser/prerender/prerender_manager.h | 20 | ||||
-rw-r--r-- | chrome/browser/prerender/prerender_manager_unittest.cc | 4 |
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; } |