summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorcbentzel@chromium.org <cbentzel@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-03-09 14:06:50 +0000
committercbentzel@chromium.org <cbentzel@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-03-09 14:06:50 +0000
commita0358d77904f3c4959f0411a53448e5944019689 (patch)
tree95336b076c8820c040853fdbece0456394f9e328
parent874a8fc3c78909bf1db133e26ca38ed948b235ff (diff)
downloadchromium_src-a0358d77904f3c4959f0411a53448e5944019689.zip
chromium_src-a0358d77904f3c4959f0411a53448e5944019689.tar.gz
chromium_src-a0358d77904f3c4959f0411a53448e5944019689.tar.bz2
Prerendered pages are swapped in at browser::Navigate time.
They used to get swapped in by observing provisional loads. This is being changed to Navigate so renderer-issued navigations into a prerender can be handled with the same mechanism that is used to handle renderer-issued navigations which need to cross process boundaries, such as clicking into a hosted app. For browser issued navigations, this means that we will immediately swap in the prerender, instead of sending a Navigate message to the render view and swapping in on the provisional load statement. For renderer issued navigations, decidePolicyForNavigation will ultimately cancel the navigation in the renderer and send an OpenURL up to the browser process. In order to make the renderer know that a navigation could be prerendered, a set of prerendered URLs need to be sent to a render process. BUG=104493 TEST=Existing browser tests, manual tests that omnibox prerenders work. There should be no user-visible changes. Review URL: http://codereview.chromium.org/9623018 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@125836 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/prerender/prerender_browsertest.cc74
-rw-r--r--chrome/browser/prerender/prerender_contents.cc46
-rw-r--r--chrome/browser/prerender/prerender_contents.h3
-rw-r--r--chrome/browser/prerender/prerender_manager.cc17
-rw-r--r--chrome/browser/prerender/prerender_manager.h12
-rw-r--r--chrome/browser/prerender/prerender_manager_unittest.cc8
-rw-r--r--chrome/browser/prerender/prerender_tab_helper.cc16
-rw-r--r--chrome/browser/prerender/prerender_tab_helper.h8
-rw-r--r--chrome/browser/ui/browser_navigator.cc17
-rw-r--r--chrome/browser/ui/webui/net_internals/net_internals_ui_browsertest.cc2
-rw-r--r--chrome/chrome_renderer.gypi2
-rw-r--r--chrome/common/common_message_generator.h3
-rw-r--r--chrome/common/prerender_messages.h25
-rw-r--r--chrome/common/render_messages.h6
-rw-r--r--chrome/renderer/chrome_content_renderer_client.cc12
-rw-r--r--chrome/renderer/chrome_content_renderer_client.h5
-rw-r--r--chrome/renderer/chrome_render_view_observer.cc3
-rw-r--r--chrome/renderer/plugins/plugin_placeholder.cc3
-rw-r--r--chrome/renderer/prerender/prerender_dispatcher.cc60
-rw-r--r--chrome/renderer/prerender/prerender_dispatcher.h41
-rw-r--r--chrome/renderer/prerender/prerender_helper.cc6
-rw-r--r--chrome/renderer/prerender/prerender_webmediaplayer.cc4
-rw-r--r--chrome/test/data/prerender/prerender_loader.html6
-rw-r--r--chrome/test/data/prerender/prerender_loader_with_session_storage.html2
-rw-r--r--chrome/test/data/prerender/prerender_loader_with_unload.html2
-rw-r--r--content/browser/tab_contents/tab_contents.cc7
-rw-r--r--content/browser/tab_contents/tab_contents.h8
-rw-r--r--content/browser/tab_contents/tab_contents_view_helper.cc1
-rw-r--r--content/public/browser/web_contents.h3
-rw-r--r--ipc/ipc_message_utils.h1
30 files changed, 316 insertions, 87 deletions
diff --git a/chrome/browser/prerender/prerender_browsertest.cc b/chrome/browser/prerender/prerender_browsertest.cc
index 8d624d7..81d63bd 100644
--- a/chrome/browser/prerender/prerender_browsertest.cc
+++ b/chrome/browser/prerender/prerender_browsertest.cc
@@ -172,8 +172,13 @@ 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();
+ if (quit_message_loop_on_destruction_) {
+ // The message loop may not be running if this is swapped in
+ // synchronously on a Navigation.
+ MessageLoop* loop = MessageLoopForUI::current();
+ if (loop->is_running())
+ loop->Quit();
+ }
}
virtual void RenderViewGone(base::TerminationStatus status) OVERRIDE {
@@ -488,7 +493,8 @@ class PrerenderBrowserTest : public InProcessBrowserTest {
const std::string& html_file,
const std::deque<FinalStatus>& expected_final_status_queue,
int expected_number_of_loads) {
- PrerenderTestURLImpl(test_server()->GetURL(html_file),
+ GURL url = test_server()->GetURL(html_file);
+ PrerenderTestURLImpl(url, url,
expected_final_status_queue,
expected_number_of_loads);
}
@@ -499,7 +505,19 @@ class PrerenderBrowserTest : public InProcessBrowserTest {
int expected_number_of_loads) {
std::deque<FinalStatus> expected_final_status_queue(1,
expected_final_status);
- PrerenderTestURLImpl(url,
+ PrerenderTestURLImpl(url, url,
+ expected_final_status_queue,
+ expected_number_of_loads);
+ }
+
+ void PrerenderTestURL(
+ const GURL& prerender_url,
+ const GURL& destination_url,
+ FinalStatus expected_final_status,
+ int expected_number_of_loads) {
+ std::deque<FinalStatus> expected_final_status_queue(1,
+ expected_final_status);
+ PrerenderTestURLImpl(prerender_url, destination_url,
expected_final_status_queue,
expected_number_of_loads);
}
@@ -691,14 +709,18 @@ class PrerenderBrowserTest : public InProcessBrowserTest {
private:
void PrerenderTestURLImpl(
- const GURL& url,
+ const GURL& prerender_url,
+ const GURL& destination_url,
const std::deque<FinalStatus>& expected_final_status_queue,
int expected_number_of_loads) {
- dest_url_ = url;
+ // TODO(cbentzel): Remove dest_url_?
+ dest_url_ = destination_url;
std::vector<net::TestServer::StringPair> replacement_text;
replacement_text.push_back(
- make_pair("REPLACE_WITH_PRERENDER_URL", dest_url_.spec()));
+ make_pair("REPLACE_WITH_PRERENDER_URL", prerender_url.spec()));
+ replacement_text.push_back(
+ make_pair("REPLACE_WITH_DESTINATION_URL", destination_url.spec()));
std::string replacement_path;
ASSERT_TRUE(net::TestServer::GetFilePathWithReplacements(
loader_path_,
@@ -789,17 +811,11 @@ class PrerenderBrowserTest : public InProcessBrowserTest {
}
}
- // ui_test_utils::NavigateToURL waits until DidStopLoading is called on
- // the current tab. As that tab is going to end up deleted, and may never
- // finish loading before that happens, exit the message loop on the deletion
- // of the used prerender contents instead.
- //
- // As PrerenderTestURL waits until the prerendered page has completely
- // loaded, there is no race between loading |dest_url| and swapping the
- // prerendered TabContents into the tab.
+ // Navigate to the prerendered URL, but don't run the message loop. Browser
+ // issued navigations to prerendered pages will synchronously swap in the
+ // prerendered page.
ui_test_utils::NavigateToURLWithDisposition(
browser(), dest_url, disposition, ui_test_utils::BROWSER_TEST_NONE);
- ui_test_utils::RunMessageLoop();
// Make sure the PrerenderContents found earlier was used or removed.
EXPECT_TRUE(GetPrerenderContents() == NULL);
@@ -965,6 +981,19 @@ IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest,
NavigateToURL("files/prerender/prerender_page.html");
}
+// Checks that client-issued redirects work with prerendering.
+// This version navigates to the final destination page, rather than the
+// page which does the redirection via a mouse click.
+IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest,
+ PrerenderClientRedirectNavigateToSecondViaClick) {
+ GURL prerender_url = test_server()->GetURL(
+ CreateClientRedirect("files/prerender/prerender_page.html"));
+ GURL destination_url = test_server()->GetURL(
+ "files/prerender/prerender_page.html");
+ PrerenderTestURL(prerender_url, destination_url, FINAL_STATUS_USED, 2);
+ OpenDestURLViaClick();
+}
+
// Checks that a prerender for an https will prevent a prerender from happening.
IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, PrerenderHttps) {
net::TestServer https_server(net::TestServer::TYPE_HTTPS,
@@ -1056,6 +1085,19 @@ IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest,
NavigateToURL("files/prerender/prerender_page.html");
}
+// Checks that server-issued redirects work with prerendering.
+// This version navigates to the final destination page, rather than the
+// page which does the redirection via a mouse click.
+IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest,
+ PrerenderServerRedirectNavigateToSecondViaClick) {
+ GURL prerender_url = test_server()->GetURL(
+ CreateServerRedirect("files/prerender/prerender_page.html"));
+ GURL destination_url = test_server()->GetURL(
+ "files/prerender/prerender_page.html");
+ PrerenderTestURL(prerender_url, destination_url, FINAL_STATUS_USED, 1);
+ OpenDestURLViaClick();
+}
+
// Checks that server-issued redirects from an http to an https
// location will cancel prerendering.
IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest,
diff --git a/chrome/browser/prerender/prerender_contents.cc b/chrome/browser/prerender/prerender_contents.cc
index 92ba801..93d1029 100644
--- a/chrome/browser/prerender/prerender_contents.cc
+++ b/chrome/browser/prerender/prerender_contents.cc
@@ -21,7 +21,7 @@
#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
#include "chrome/common/chrome_notification_types.h"
#include "chrome/common/icon_messages.h"
-#include "chrome/common/render_messages.h"
+#include "chrome/common/prerender_messages.h"
#include "chrome/common/url_constants.h"
#include "content/browser/renderer_host/resource_request_details.h"
#include "content/public/browser/browser_child_process_host.h"
@@ -59,6 +59,29 @@ struct PrerenderURLPredicate {
GURL url_;
};
+// 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);
+}
+
} // end namespace
class PrerenderContentsFactoryImpl : public PrerenderContents::Factory {
@@ -225,7 +248,8 @@ PrerenderContents::PrerenderContents(
child_id_(-1),
route_id_(-1),
origin_(origin),
- experiment_id_(experiment_id) {
+ experiment_id_(experiment_id),
+ creator_child_id_(-1) {
DCHECK(prerender_manager != NULL);
}
@@ -246,6 +270,13 @@ void PrerenderContents::StartPrerendering(
DCHECK(prerender_contents_.get() == NULL);
prerendering_has_started_ = true;
+ DCHECK(creator_child_id_ == -1);
+ DCHECK(alias_urls_.size() == 1);
+ if (source_render_view_host)
+ creator_child_id_ = source_render_view_host->GetProcess()->GetID();
+ InformRenderProcessAboutPrerender(prerender_url_, true,
+ creator_child_id_);
+
WebContents* new_contents = WebContents::Create(
profile_, NULL, MSG_ROUTING_NONE, NULL, session_storage_namespace);
prerender_contents_.reset(new TabContentsWrapper(new_contents));
@@ -361,8 +392,14 @@ PrerenderContents::~PrerenderContents() {
match_complete_status_,
final_status_);
- if (child_id_ != -1 && route_id_ != -1)
+ if (child_id_ != -1 && route_id_ != -1) {
prerender_tracker_->OnPrerenderingFinished(child_id_, route_id_);
+ 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 TabContents, clean up anything we need to and then
// destroy it.
@@ -417,7 +454,7 @@ void PrerenderContents::Observe(int type,
// first navigation, so there's no need to send the message just after
// the TabContents is created.
new_render_view_host->Send(
- new ChromeViewMsg_SetIsPrerendering(
+ new PrerenderMsg_SetIsPrerendering(
new_render_view_host->GetRoutingID(),
true));
@@ -474,6 +511,7 @@ bool PrerenderContents::AddAliasURL(const GURL& url) {
}
alias_urls_.push_back(url);
+ InformRenderProcessAboutPrerender(url, true, creator_child_id_);
prerender_tracker_->AddPrerenderURLOnUIThread(url);
return true;
}
diff --git a/chrome/browser/prerender/prerender_contents.h b/chrome/browser/prerender/prerender_contents.h
index 139e4ff..85aa433 100644
--- a/chrome/browser/prerender/prerender_contents.h
+++ b/chrome/browser/prerender/prerender_contents.h
@@ -339,6 +339,9 @@ class PrerenderContents : public content::NotificationObserver,
// List of all pages the prerendered page has tried to prerender.
PendingPrerenderList pending_prerender_list_;
+ // The process that created the child id.
+ int creator_child_id_;
+
DISALLOW_COPY_AND_ASSIGN(PrerenderContents);
};
diff --git a/chrome/browser/prerender/prerender_manager.cc b/chrome/browser/prerender/prerender_manager.cc
index 0b8589f..d10838c 100644
--- a/chrome/browser/prerender/prerender_manager.cc
+++ b/chrome/browser/prerender/prerender_manager.cc
@@ -35,7 +35,7 @@
#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
#include "chrome/common/chrome_notification_types.h"
#include "chrome/common/chrome_switches.h"
-#include "chrome/common/render_messages.h"
+#include "chrome/common/prerender_messages.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/devtools_agent_host_registry.h"
#include "content/public/browser/navigation_controller.h"
@@ -324,9 +324,9 @@ void PrerenderManager::CancelOmniboxPrerenders() {
}
bool PrerenderManager::MaybeUsePrerenderedPage(WebContents* web_contents,
- const GURL& url,
- const GURL& opener_url) {
+ const GURL& url) {
DCHECK(CalledOnValidThread());
+ DCHECK(!IsWebContentsPrerendering(web_contents));
RecordNavigation(url);
scoped_ptr<PrerenderContents> prerender_contents(
@@ -334,11 +334,8 @@ bool PrerenderManager::MaybeUsePrerenderedPage(WebContents* web_contents,
if (prerender_contents.get() == NULL)
return false;
- // Do not use the prerendered version if the opener url corresponding to the
- // window.opener property has the same origin as the url.
- // NOTE: This is broken in the cases where the document domain is modified
- // using the javascript property for "document.domain".
- if (opener_url.GetOrigin() == url.GetOrigin()) {
+ // Do not use the prerendered version if there is an opener object.
+ if (web_contents->HasOpener()) {
prerender_contents.release()->Destroy(FINAL_STATUS_WINDOW_OPENER);
return false;
}
@@ -424,8 +421,8 @@ bool PrerenderManager::MaybeUsePrerenderedPage(WebContents* web_contents,
prerender_contents->set_final_status(FINAL_STATUS_USED);
new_render_view_host->Send(
- new ChromeViewMsg_SetIsPrerendering(new_render_view_host->GetRoutingID(),
- false));
+ new PrerenderMsg_SetIsPrerendering(new_render_view_host->GetRoutingID(),
+ false));
TabContentsWrapper* new_tab_contents =
prerender_contents->ReleasePrerenderContents();
diff --git a/chrome/browser/prerender/prerender_manager.h b/chrome/browser/prerender/prerender_manager.h
index 2d515b5..7a39614 100644
--- a/chrome/browser/prerender/prerender_manager.h
+++ b/chrome/browser/prerender/prerender_manager.h
@@ -125,15 +125,11 @@ class PrerenderManager : public base::SupportsWeakPtr<PrerenderManager>,
// Cancels all active prerenders with the ORIGIN_OMNIBOX origin.
void CancelOmniboxPrerenders();
- // For a given WebContents that wants to navigate to the URL supplied,
- // determines whether a prerendered version of the URL can be used,
- // and substitutes the prerendered RVH into the WebContents. |opener_url| is
- // set to the window.opener url that the WebContents should have set and
- // will be empty if there is no opener set. Returns whether or not a
- // prerendered RVH could be used or not.
+ // If |url| matches a valid prerendered page, try to swap it into
+ // |web_contents| and merge browsing histories. Returns |true| if a
+ // prerendered page is swapped in, |false| otherwise.
bool MaybeUsePrerenderedPage(content::WebContents* web_contents,
- const GURL& url,
- const GURL& opener_url);
+ const GURL& url);
// Moves a PrerenderContents to the pending delete list from the list of
// active prerenders when prerendering should be cancelled.
diff --git a/chrome/browser/prerender/prerender_manager_unittest.cc b/chrome/browser/prerender/prerender_manager_unittest.cc
index 8eb1aec..73c27e5 100644
--- a/chrome/browser/prerender/prerender_manager_unittest.cc
+++ b/chrome/browser/prerender/prerender_manager_unittest.cc
@@ -236,13 +236,7 @@ class PrerenderManagerTest : public testing::Test {
TEST_F(PrerenderManagerTest, EmptyTest) {
EXPECT_FALSE(prerender_manager()->MaybeUsePrerenderedPage(
NULL,
- GURL("http://www.google.com/"),
- GURL()));
-
- EXPECT_FALSE(prerender_manager()->MaybeUsePrerenderedPage(
- NULL,
- GURL("http://www.google.com/search"),
- GURL("http://www.google.com")));
+ GURL("http://www.google.com/")));
}
TEST_F(PrerenderManagerTest, FoundTest) {
diff --git a/chrome/browser/prerender/prerender_tab_helper.cc b/chrome/browser/prerender/prerender_tab_helper.cc
index badb85c..9c614ce 100644
--- a/chrome/browser/prerender/prerender_tab_helper.cc
+++ b/chrome/browser/prerender/prerender_tab_helper.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -184,15 +184,12 @@ void PrerenderTabHelper::ProvisionalChangeToMainFrameUrl(
RecordPageviewEvent(PAGEVIEW_EVENT_NEW_URL);
if (IsTopSite(url))
RecordPageviewEvent(PAGEVIEW_EVENT_TOP_SITE_NEW_URL);
- if (!tab_->core_tab_helper()->delegate())
- return; // PrerenderManager needs a delegate to handle the swap.
PrerenderManager* prerender_manager = MaybeGetPrerenderManager();
if (!prerender_manager)
return;
if (prerender_manager->IsWebContentsPrerendering(web_contents()))
return;
prerender_manager->MarkWebContentsAsNotPrerendered(web_contents());
- MaybeUsePrerenderedPage(url, opener_url);
}
void PrerenderTabHelper::UpdateTargetURL(int32 page_id, const GURL& url) {
@@ -247,17 +244,6 @@ PrerenderManager* PrerenderTabHelper::MaybeGetPrerenderManager() const {
Profile::FromBrowserContext(web_contents()->GetBrowserContext()));
}
-bool PrerenderTabHelper::MaybeUsePrerenderedPage(const GURL& url,
- const GURL& opener_url) {
- PrerenderManager* prerender_manager = MaybeGetPrerenderManager();
- if (!prerender_manager)
- return false;
- DCHECK(!prerender_manager->IsWebContentsPrerendering(web_contents()));
- return prerender_manager->MaybeUsePrerenderedPage(web_contents(),
- url,
- opener_url);
-}
-
bool PrerenderTabHelper::IsPrerendering() {
PrerenderManager* prerender_manager = MaybeGetPrerenderManager();
if (!prerender_manager)
diff --git a/chrome/browser/prerender/prerender_tab_helper.h b/chrome/browser/prerender/prerender_tab_helper.h
index 156bcc5..1b3ebe2 100644
--- a/chrome/browser/prerender/prerender_tab_helper.h
+++ b/chrome/browser/prerender/prerender_tab_helper.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -47,12 +47,6 @@ class PrerenderTabHelper : public content::WebContentsObserver {
// Retrieves the PrerenderManager, or NULL, if none was found.
PrerenderManager* MaybeGetPrerenderManager() const;
- // Checks with the PrerenderManager if the specified URL has been preloaded,
- // and if so, swap the RenderViewHost with the preload into this TabContents
- // object. |opener_url| denotes the window.opener url that is set for this
- // tab and is empty if there is no opener set.
- bool MaybeUsePrerenderedPage(const GURL& url, const GURL& opener_url);
-
// Returns whether the TabContents being observed is currently prerendering.
bool IsPrerendering();
diff --git a/chrome/browser/ui/browser_navigator.cc b/chrome/browser/ui/browser_navigator.cc
index 6dd05b2..80aa319 100644
--- a/chrome/browser/ui/browser_navigator.cc
+++ b/chrome/browser/ui/browser_navigator.cc
@@ -16,6 +16,8 @@
#include "chrome/browser/google/google_util.h"
#include "chrome/browser/prefs/incognito_mode_prefs.h"
#include "chrome/browser/prefs/pref_service.h"
+#include "chrome/browser/prerender/prerender_manager.h"
+#include "chrome/browser/prerender/prerender_manager_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/rlz/rlz.h"
#include "chrome/browser/tab_contents/tab_util.h"
@@ -361,6 +363,18 @@ void InitializeExtraHeaders(browser::NavigateParams* params,
#endif
}
+// If a prerendered page exists for |url|, replace the page at |target_contents|
+// with it.
+bool SwapInPrerender(TabContentsWrapper* target_contents, const GURL& url) {
+ prerender::PrerenderManager* prerender_manager =
+ prerender::PrerenderManagerFactory::GetForProfile(
+ target_contents->profile());
+ if (!prerender_manager)
+ return false;
+ return prerender_manager->MaybeUsePrerenderedPage(
+ target_contents->web_contents(), url);
+}
+
} // namespace
namespace browser {
@@ -535,6 +549,9 @@ void Navigate(NavigateParams* params) {
InitializeExtraHeaders(params, params->target_contents->profile(),
&extra_headers);
+ if (SwapInPrerender(params->target_contents, url))
+ return;
+
// Try to handle non-navigational URLs that popup dialogs and such, these
// should not actually navigate.
if (!HandleNonNavigationAboutURL(url)) {
diff --git a/chrome/browser/ui/webui/net_internals/net_internals_ui_browsertest.cc b/chrome/browser/ui/webui/net_internals/net_internals_ui_browsertest.cc
index 79d7a88..03ebc0c 100644
--- a/chrome/browser/ui/webui/net_internals/net_internals_ui_browsertest.cc
+++ b/chrome/browser/ui/webui/net_internals/net_internals_ui_browsertest.cc
@@ -340,6 +340,8 @@ GURL NetInternalsTest::CreatePrerenderLoaderUrl(
std::vector<net::TestServer::StringPair> replacement_text;
replacement_text.push_back(
make_pair("REPLACE_WITH_PRERENDER_URL", prerender_url.spec()));
+ replacement_text.push_back(
+ make_pair("REPLACE_WITH_DESTINATION_URL", prerender_url.spec()));
std::string replacement_path;
EXPECT_TRUE(net::TestServer::GetFilePathWithReplacements(
"files/prerender/prerender_loader.html",
diff --git a/chrome/chrome_renderer.gypi b/chrome/chrome_renderer.gypi
index 668d10b..15e708b3 100644
--- a/chrome/chrome_renderer.gypi
+++ b/chrome/chrome_renderer.gypi
@@ -181,6 +181,8 @@
'renderer/plugins/plugin_placeholder.h',
'renderer/plugins/plugin_uma.cc',
'renderer/plugins/plugin_uma.h',
+ 'renderer/prerender/prerender_dispatcher.cc',
+ 'renderer/prerender/prerender_dispatcher.h',
'renderer/prerender/prerender_helper.cc',
'renderer/prerender/prerender_helper.h',
'renderer/prerender/prerender_webmediaplayer.cc',
diff --git a/chrome/common/common_message_generator.h b/chrome/common/common_message_generator.h
index 4b231f2..fc818fb 100644
--- a/chrome/common/common_message_generator.h
+++ b/chrome/common/common_message_generator.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -10,6 +10,7 @@
#include "chrome/common/chrome_utility_messages.h"
#include "chrome/common/extensions/extension_messages.h"
#include "chrome/common/icon_messages.h"
+#include "chrome/common/prerender_messages.h"
#include "chrome/common/print_messages.h"
#include "chrome/common/render_messages.h"
#include "chrome/common/safe_browsing/safebrowsing_messages.h"
diff --git a/chrome/common/prerender_messages.h b/chrome/common/prerender_messages.h
new file mode 100644
index 0000000..4c965a9
--- /dev/null
+++ b/chrome/common/prerender_messages.h
@@ -0,0 +1,25 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Multiply-included message file, no traditional include guard.
+#include "googleurl/src/gurl.h"
+#include "ipc/ipc_message.h"
+#include "ipc/ipc_message_macros.h"
+#include "ipc/ipc_param_traits.h"
+
+#define IPC_MESSAGE_START PrerenderMsgStart
+
+// Tells a renderer if it's currently being prerendered. Must only be set
+// to true before any navigation occurs, and only set to false at most once
+// after that.
+IPC_MESSAGE_ROUTED1(PrerenderMsg_SetIsPrerendering,
+ bool /* whether the RenderView is prerendering */)
+
+// Specifies that a URL is currently being prerendered.
+IPC_MESSAGE_CONTROL1(PrerenderMsg_AddPrerenderURL,
+ GURL /* url */)
+
+// Specifies that a URL is no longer being prerendered.
+IPC_MESSAGE_CONTROL1(PrerenderMsg_RemovePrerenderURL,
+ GURL /* url */)
diff --git a/chrome/common/render_messages.h b/chrome/common/render_messages.h
index 44933a6..a338c89 100644
--- a/chrome/common/render_messages.h
+++ b/chrome/common/render_messages.h
@@ -307,12 +307,6 @@ IPC_MESSAGE_ROUTED4(ChromeViewMsg_TranslatePage,
IPC_MESSAGE_ROUTED1(ChromeViewMsg_RevertTranslation,
int /* page id */)
-// Tells a renderer if it's currently being prerendered. Must only be set
-// to true before any navigation occurs, and only set to false at most once
-// after that.
-IPC_MESSAGE_ROUTED1(ChromeViewMsg_SetIsPrerendering,
- bool /* whether the RenderView is prerendering */)
-
// Sent on process startup to indicate whether this process is running in
// incognito mode.
IPC_MESSAGE_CONTROL1(ChromeViewMsg_SetIsIncognitoProcess,
diff --git a/chrome/renderer/chrome_content_renderer_client.cc b/chrome/renderer/chrome_content_renderer_client.cc
index badc417..6da46db 100644
--- a/chrome/renderer/chrome_content_renderer_client.cc
+++ b/chrome/renderer/chrome_content_renderer_client.cc
@@ -50,6 +50,7 @@
#include "chrome/renderer/page_load_histograms.h"
#include "chrome/renderer/plugins/plugin_placeholder.h"
#include "chrome/renderer/plugins/plugin_uma.h"
+#include "chrome/renderer/prerender/prerender_dispatcher.h"
#include "chrome/renderer/prerender/prerender_helper.h"
#include "chrome/renderer/prerender/prerender_webmediaplayer.h"
#include "chrome/renderer/print_web_view_helper.h"
@@ -157,6 +158,7 @@ void ChromeContentRendererClient::RenderThreadStarted() {
#if defined(ENABLE_SAFE_BROWSING)
phishing_classifier_.reset(safe_browsing::PhishingClassifierFilter::Create());
#endif
+ prerender_dispatcher_.reset(new prerender::PrerenderDispatcher());
RenderThread* thread = RenderThread::Get();
@@ -168,6 +170,7 @@ void ChromeContentRendererClient::RenderThreadStarted() {
#endif
thread->AddObserver(spellcheck_.get());
thread->AddObserver(visited_link_slave_.get());
+ thread->AddObserver(prerender_dispatcher_.get());
thread->RegisterExtension(extensions_v8::ExternalExtension::Get());
thread->RegisterExtension(extensions_v8::LoadTimesExtension::Get());
@@ -642,6 +645,15 @@ bool ChromeContentRendererClient::ShouldFork(WebFrame* frame,
const GURL& url,
bool is_initial_navigation,
bool* send_referrer) {
+ DCHECK(!frame->parent());
+
+ // If |url| matches one of the prerendered URLs, stop this navigation and try
+ // to swap in the prerendered page on the browser process. If the prerendered
+ // page no longer exists by the time the OpenURL IPC is handled, a normal
+ // navigation is attempted.
+ if (prerender_dispatcher_.get() && prerender_dispatcher_->IsPrerenderURL(url))
+ return true;
+
const ExtensionSet* extensions = extension_dispatcher_->extensions();
// Determine if the new URL is an extension (excluding bookmark apps).
diff --git a/chrome/renderer/chrome_content_renderer_client.h b/chrome/renderer/chrome_content_renderer_client.h
index 6cbf7d9..c18d866 100644
--- a/chrome/renderer/chrome_content_renderer_client.h
+++ b/chrome/renderer/chrome_content_renderer_client.h
@@ -26,6 +26,10 @@ class VisitedLinkSlave;
struct ChromeViewHostMsg_GetPluginInfo_Status;
+namespace prerender {
+class PrerenderDispatcher;
+}
+
namespace safe_browsing {
class PhishingClassifierFilter;
}
@@ -159,6 +163,7 @@ class ChromeContentRendererClient : public content::ContentRendererClient {
scoped_ptr<SpellCheck> spellcheck_;
scoped_ptr<VisitedLinkSlave> visited_link_slave_;
scoped_ptr<safe_browsing::PhishingClassifierFilter> phishing_classifier_;
+ scoped_ptr<prerender::PrerenderDispatcher> prerender_dispatcher_;
};
} // namespace chrome
diff --git a/chrome/renderer/chrome_render_view_observer.cc b/chrome/renderer/chrome_render_view_observer.cc
index fffdbec..11f5994 100644
--- a/chrome/renderer/chrome_render_view_observer.cc
+++ b/chrome/renderer/chrome_render_view_observer.cc
@@ -14,6 +14,7 @@
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/icon_messages.h"
+#include "chrome/common/prerender_messages.h"
#include "chrome/common/render_messages.h"
#include "chrome/common/thumbnail_score.h"
#include "chrome/common/url_constants.h"
@@ -267,7 +268,7 @@ bool ChromeRenderViewObserver::OnMessageReceived(const IPC::Message& message) {
// Filter only.
IPC_BEGIN_MESSAGE_MAP(ChromeRenderViewObserver, message)
- IPC_MESSAGE_HANDLER(ChromeViewMsg_SetIsPrerendering, OnSetIsPrerendering);
+ IPC_MESSAGE_HANDLER(PrerenderMsg_SetIsPrerendering, OnSetIsPrerendering);
IPC_END_MESSAGE_MAP()
return handled;
diff --git a/chrome/renderer/plugins/plugin_placeholder.cc b/chrome/renderer/plugins/plugin_placeholder.cc
index 5d2d269..0bd9c0c 100644
--- a/chrome/renderer/plugins/plugin_placeholder.cc
+++ b/chrome/renderer/plugins/plugin_placeholder.cc
@@ -13,6 +13,7 @@
#include "base/values.h"
#include "chrome/common/jstemplate_builder.h"
#include "chrome/common/render_messages.h"
+#include "chrome/common/prerender_messages.h"
#include "chrome/renderer/chrome_content_renderer_client.h"
#include "chrome/renderer/custom_menu_commands.h"
#include "chrome/renderer/plugins/plugin_uma.h"
@@ -219,7 +220,7 @@ bool PluginPlaceholder::OnMessageReceived(const IPC::Message& message) {
// interest in them.
IPC_BEGIN_MESSAGE_MAP(PluginPlaceholder, message)
IPC_MESSAGE_HANDLER(ChromeViewMsg_LoadBlockedPlugins, OnLoadBlockedPlugins)
- IPC_MESSAGE_HANDLER(ChromeViewMsg_SetIsPrerendering, OnSetIsPrerendering)
+ IPC_MESSAGE_HANDLER(PrerenderMsg_SetIsPrerendering, OnSetIsPrerendering)
IPC_END_MESSAGE_MAP()
return false;
diff --git a/chrome/renderer/prerender/prerender_dispatcher.cc b/chrome/renderer/prerender/prerender_dispatcher.cc
new file mode 100644
index 0000000..500d4be
--- /dev/null
+++ b/chrome/renderer/prerender/prerender_dispatcher.cc
@@ -0,0 +1,60 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/renderer/prerender/prerender_dispatcher.h"
+
+#include "base/logging.h"
+#include "chrome/common/prerender_messages.h"
+#include "googleurl/src/gurl.h"
+
+namespace prerender {
+
+PrerenderDispatcher::PrerenderDispatcher() {
+}
+
+PrerenderDispatcher::~PrerenderDispatcher() {
+}
+
+bool PrerenderDispatcher::IsPrerenderURL(const GURL& url) const {
+ return prerender_urls_.find(url) != prerender_urls_.end();
+}
+
+bool PrerenderDispatcher::OnControlMessageReceived(
+ const IPC::Message& message) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(PrerenderDispatcher, message)
+ IPC_MESSAGE_HANDLER(PrerenderMsg_AddPrerenderURL, OnAddPrerenderURL)
+ IPC_MESSAGE_HANDLER(PrerenderMsg_RemovePrerenderURL, OnRemovePrerenderURL)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+
+ return handled;
+}
+
+void PrerenderDispatcher::OnAddPrerenderURL(const GURL& url) {
+ PrerenderMap::iterator it = prerender_urls_.find(url);
+ if (it != prerender_urls_.end()) {
+ DCHECK(it->second > 0);
+ it->second += 1;
+ } else {
+ prerender_urls_[url] = 1;
+ }
+}
+
+void PrerenderDispatcher::OnRemovePrerenderURL(const GURL& url) {
+ PrerenderMap::iterator it = prerender_urls_.find(url);
+ // This is possible with a spurious remove.
+ // TODO(cbentzel): We'd also want to send the map of active prerenders when
+ // creating a new render process, so the Add/Remove go relative to that.
+ // This may not be that big of a deal in practice, since the newly created tab
+ // is unlikely to go to the prerendered page.
+ if (it == prerender_urls_.end())
+ return;
+ DCHECK(it->second > 0);
+ it->second -= 1;
+ if (it->second == 0)
+ prerender_urls_.erase(it);
+}
+
+} // namespace prerender
diff --git a/chrome/renderer/prerender/prerender_dispatcher.h b/chrome/renderer/prerender/prerender_dispatcher.h
new file mode 100644
index 0000000..5537401
--- /dev/null
+++ b/chrome/renderer/prerender/prerender_dispatcher.h
@@ -0,0 +1,41 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_RENDERER_PRERENDER_PRERENDER_DISPATCHER_H_
+#define CHROME_RENDERER_PRERENDER_PRERENDER_DISPATCHER_H_
+#pragma once
+
+#include <map>
+
+#include "base/compiler_specific.h"
+#include "content/public/renderer/render_process_observer.h"
+
+class GURL;
+
+namespace prerender {
+
+// PrerenderDispatcher keeps track of which URLs are being prerendered. There
+// is only one PrerenderDispatcher per render process, and it will only be
+// aware of prerenders that are triggered by this render process.
+class PrerenderDispatcher : public content::RenderProcessObserver {
+ public:
+ PrerenderDispatcher();
+ virtual ~PrerenderDispatcher();
+
+ bool IsPrerenderURL(const GURL & url) const;
+
+ private:
+ void OnAddPrerenderURL(const GURL& url);
+ void OnRemovePrerenderURL(const GURL& url);
+
+ // RenderProcessObserver:
+ virtual bool OnControlMessageReceived(const IPC::Message& message) OVERRIDE;
+
+ typedef std::map<GURL, int> PrerenderMap;
+ PrerenderMap prerender_urls_;
+};
+
+} // namespace prerender
+
+#endif // CHROME_RENDERER_PRERENDER_PRERENDER_DISPATCHER_H_
diff --git a/chrome/renderer/prerender/prerender_helper.cc b/chrome/renderer/prerender/prerender_helper.cc
index 84dc1d7..853a2f7 100644
--- a/chrome/renderer/prerender/prerender_helper.cc
+++ b/chrome/renderer/prerender/prerender_helper.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -6,7 +6,7 @@
#include "base/metrics/field_trial.h"
#include "base/metrics/histogram.h"
-#include "chrome/common/render_messages.h"
+#include "chrome/common/prerender_messages.h"
#include "content/public/renderer/document_state.h"
#include "content/public/renderer/render_view.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
@@ -131,7 +131,7 @@ void PrerenderHelper::DidStartProvisionalLoad(WebKit::WebFrame* frame) {
bool PrerenderHelper::OnMessageReceived(
const IPC::Message& message) {
IPC_BEGIN_MESSAGE_MAP(PrerenderHelper, message)
- IPC_MESSAGE_HANDLER(ChromeViewMsg_SetIsPrerendering, OnSetIsPrerendering)
+ IPC_MESSAGE_HANDLER(PrerenderMsg_SetIsPrerendering, OnSetIsPrerendering)
IPC_END_MESSAGE_MAP()
// Return false on ViewMsg_SetIsPrerendering so other observers can see the
// message.
diff --git a/chrome/renderer/prerender/prerender_webmediaplayer.cc b/chrome/renderer/prerender/prerender_webmediaplayer.cc
index 8189b4f..8fcc299 100644
--- a/chrome/renderer/prerender/prerender_webmediaplayer.cc
+++ b/chrome/renderer/prerender/prerender_webmediaplayer.cc
@@ -4,7 +4,7 @@
#include "chrome/renderer/prerender/prerender_webmediaplayer.h"
-#include "chrome/common/render_messages.h"
+#include "chrome/common/prerender_messages.h"
#include "content/public/renderer/render_view.h"
#include "media/base/filter_collection.h"
#include "media/base/media_log.h"
@@ -59,7 +59,7 @@ void PrerenderWebMediaPlayer::cancelLoad() {
bool PrerenderWebMediaPlayer::OnMessageReceived(const IPC::Message& message) {
IPC_BEGIN_MESSAGE_MAP(PrerenderWebMediaPlayer, message)
- IPC_MESSAGE_HANDLER(ChromeViewMsg_SetIsPrerendering, OnSetIsPrerendering)
+ IPC_MESSAGE_HANDLER(PrerenderMsg_SetIsPrerendering, OnSetIsPrerendering)
IPC_END_MESSAGE_MAP()
return false;
diff --git a/chrome/test/data/prerender/prerender_loader.html b/chrome/test/data/prerender/prerender_loader.html
index 66d4afe..9fed87a 100644
--- a/chrome/test/data/prerender/prerender_loader.html
+++ b/chrome/test/data/prerender/prerender_loader.html
@@ -56,7 +56,7 @@
}
function WindowOpen() {
- window.open('REPLACE_WITH_PRERENDER_URL');
+ window.open('REPLACE_WITH_DESTINATION_URL');
}
</script>
@@ -66,7 +66,7 @@
document.write('<link rel="prerender" href="REPLACE_WITH_PRERENDER_URL"/>');
</script>
<a target="_blank" id="toClickTarget"
- href="REPLACE_WITH_PRERENDER_URL">Link To click in new window</a>
-<a id="toClick" href="REPLACE_WITH_PRERENDER_URL">Link to click</a>
+ href="REPLACE_WITH_DESTINATION_URL">Link To click in new window</a>
+<a id="toClick" href="REPLACE_WITH_DESTINATION_URL">Link to click</a>
</body>
</html>
diff --git a/chrome/test/data/prerender/prerender_loader_with_session_storage.html b/chrome/test/data/prerender/prerender_loader_with_session_storage.html
index 9b8e282..5221086 100644
--- a/chrome/test/data/prerender/prerender_loader_with_session_storage.html
+++ b/chrome/test/data/prerender/prerender_loader_with_session_storage.html
@@ -32,6 +32,6 @@
window.onload = loader;
</script>
-<a id="toClick" href="REPLACE_WITH_PRERENDER_URL">Link to click</a>
+<a id="toClick" href="REPLACE_WITH_DESTINATION_URL">Link to click</a>
</body>
</html>
diff --git a/chrome/test/data/prerender/prerender_loader_with_unload.html b/chrome/test/data/prerender/prerender_loader_with_unload.html
index 4819015..50336fa 100644
--- a/chrome/test/data/prerender/prerender_loader_with_unload.html
+++ b/chrome/test/data/prerender/prerender_loader_with_unload.html
@@ -15,6 +15,6 @@
<script>
document.write('<link rel="prerender" href="REPLACE_WITH_PRERENDER_URL"/>');
</script>
-<a href="REPLACE_WITH_PRERENDER_URL">Link To Click</a>
+<a href="REPLACE_WITH_DESTINATION_URL">Link To Click</a>
</body>
</html>
diff --git a/content/browser/tab_contents/tab_contents.cc b/content/browser/tab_contents/tab_contents.cc
index 239ec8e..84d54de 100644
--- a/content/browser/tab_contents/tab_contents.cc
+++ b/content/browser/tab_contents/tab_contents.cc
@@ -265,7 +265,8 @@ TabContents::TabContents(content::BrowserContext* browser_context,
static_cast<int>(content::kMaximumZoomFactor * 100)),
temporary_zoom_settings_(false),
content_restrictions_(0),
- view_type_(content::VIEW_TYPE_TAB_CONTENTS) {
+ view_type_(content::VIEW_TYPE_TAB_CONTENTS),
+ has_opener_(false) {
render_manager_.Init(browser_context, site_instance, routing_id);
// We have the initial size of the view be based on the size of the passed in
@@ -1351,6 +1352,10 @@ bool TabContents::GotResponseToLockMouseRequest(bool allowed) {
GetRenderViewHostImpl()->GotResponseToLockMouseRequest(allowed) : false;
}
+bool TabContents::HasOpener() const {
+ return has_opener_;
+}
+
bool TabContents::FocusLocationBarByDefault() {
content::WebUI* web_ui = GetWebUIForCurrentState();
if (web_ui)
diff --git a/content/browser/tab_contents/tab_contents.h b/content/browser/tab_contents/tab_contents.h
index b2bca01..74dab24 100644
--- a/content/browser/tab_contents/tab_contents.h
+++ b/content/browser/tab_contents/tab_contents.h
@@ -115,6 +115,10 @@ class CONTENT_EXPORT TabContents
opener_web_ui_type_ = opener_web_ui_type;
}
+ void set_has_opener(bool has_opener) {
+ has_opener_ = has_opener;
+ }
+
JavaBridgeDispatcherHostManager* java_bridge_dispatcher_host_manager() const {
return java_bridge_dispatcher_host_manager_.get();
}
@@ -218,6 +222,7 @@ class CONTENT_EXPORT TabContents
virtual content::WebUI::TypeID GetWebUITypeForCurrentState() OVERRIDE;
virtual content::WebUI* GetWebUIForCurrentState() OVERRIDE;
virtual bool GotResponseToLockMouseRequest(bool allowed) OVERRIDE;
+ virtual bool HasOpener() const OVERRIDE;
// Implementation of PageNavigator.
virtual content::WebContents* OpenURL(
@@ -662,6 +667,9 @@ class CONTENT_EXPORT TabContents
// Our view type. Default is VIEW_TYPE_TAB_CONTENTS.
content::ViewType view_type_;
+ // Is there an opener associated with this?
+ bool has_opener_;
+
DISALLOW_COPY_AND_ASSIGN(TabContents);
};
diff --git a/content/browser/tab_contents/tab_contents_view_helper.cc b/content/browser/tab_contents/tab_contents_view_helper.cc
index 2edfab2..3992daa 100644
--- a/content/browser/tab_contents/tab_contents_view_helper.cc
+++ b/content/browser/tab_contents/tab_contents_view_helper.cc
@@ -81,6 +81,7 @@ TabContents* TabContentsViewHelper::CreateNewWindow(
NULL);
new_contents->set_opener_web_ui_type(
web_contents->GetWebUITypeForCurrentState());
+ new_contents->set_has_opener(!params.opener_url.is_empty());
if (params.opener_suppressed) {
// When the opener is suppressed, the original renderer cannot access the
diff --git a/content/public/browser/web_contents.h b/content/public/browser/web_contents.h
index f73813b..abd656a 100644
--- a/content/public/browser/web_contents.h
+++ b/content/public/browser/web_contents.h
@@ -363,6 +363,9 @@ class WebContents : public PageNavigator {
// Focuses the location bar.
virtual void SetFocusToLocationBar(bool select_all) = 0;
+
+ // Does this have an opener associated with it?
+ virtual bool HasOpener() const = 0;
};
} // namespace content
diff --git a/ipc/ipc_message_utils.h b/ipc/ipc_message_utils.h
index 3908b12..912bc04 100644
--- a/ipc/ipc_message_utils.h
+++ b/ipc/ipc_message_utils.h
@@ -100,6 +100,7 @@ enum IPCMessageStart {
GamepadMsgStart,
ShellMsgStart,
AccessibilityMsgStart,
+ PrerenderMsgStart,
LastIPCMsgStart // Must come last.
};