summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authormmenke@chromium.org <mmenke@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-06-30 19:54:20 +0000
committermmenke@chromium.org <mmenke@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-06-30 19:54:20 +0000
commit9a31e7f2ee3c632f829cd34490ba22995c401291 (patch)
tree90af46a27c32a71dd4e5358e42e2a15382f1b45b /chrome
parentb48532fded2bbd1d9b1781c3ba6f645fc54a3070 (diff)
downloadchromium_src-9a31e7f2ee3c632f829cd34490ba22995c401291.zip
chromium_src-9a31e7f2ee3c632f829cd34490ba22995c401291.tar.gz
chromium_src-9a31e7f2ee3c632f829cd34490ba22995c401291.tar.bz2
Fix visibility state of prerendered pages opened
in a new background tab not updating. Also adds a couple tests for the visibility API. BUG=87926 TEST=PrerenderBrowserTest.PrerenderVisibilityBackgroundTab, PrerenderBrowserTest.PrerenderVisibilityForegroundTab, PrerenderBrowserTest.PrerenderVisibility Review URL: http://codereview.chromium.org/7282013 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@91182 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/prerender/prerender_browsertest.cc86
-rw-r--r--chrome/renderer/prerender/prerender_helper.cc11
-rw-r--r--chrome/renderer/prerender/prerender_helper.h4
-rw-r--r--chrome/test/data/prerender/prerender_visibility.html56
-rw-r--r--chrome/test/data/prerender/prerender_visibility_hidden.html55
5 files changed, 201 insertions, 11 deletions
diff --git a/chrome/browser/prerender/prerender_browsertest.cc b/chrome/browser/prerender/prerender_browsertest.cc
index 461af28..06350a3 100644
--- a/chrome/browser/prerender/prerender_browsertest.cc
+++ b/chrome/browser/prerender/prerender_browsertest.cc
@@ -105,6 +105,7 @@ class TestPrerenderContents : public PrerenderContents {
new_render_view_host_(NULL),
was_hidden_(false),
was_shown_(false),
+ should_be_shown_(expected_final_status == FINAL_STATUS_USED),
quit_message_loop_on_destruction_(true) {
}
@@ -124,12 +125,10 @@ class TestPrerenderContents : public PrerenderContents {
// A used PrerenderContents will only be destroyed when we swap out
// TabContents, at the end of a navigation caused by a call to
// NavigateToURLImpl().
- if (final_status() == FINAL_STATUS_USED) {
+ if (final_status() == FINAL_STATUS_USED)
EXPECT_TRUE(new_render_view_host_);
- EXPECT_TRUE(was_shown_);
- } else {
- EXPECT_FALSE(was_shown_);
- }
+
+ EXPECT_EQ(should_be_shown_, was_shown_);
// When the PrerenderContents is destroyed, quit the UI message loop.
// This happens on navigation to used prerendered pages, and soon
@@ -166,6 +165,11 @@ class TestPrerenderContents : public PrerenderContents {
}
}
+ // 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.
@@ -220,6 +224,10 @@ class TestPrerenderContents : public PrerenderContents {
// Set to true when the prerendering RenderWidget is shown, after having been
// hidden.
bool was_shown_;
+ // Expected final value of was_shown_. Defaults to true for
+ // FINAL_STATUS_USED, and false otherwise.
+ bool should_be_shown_;
+
bool quit_message_loop_on_destruction_;
};
@@ -401,7 +409,13 @@ class PrerenderBrowserTest : public InProcessBrowserTest {
}
void NavigateToDestURL() const {
- NavigateToURLImpl(dest_url_);
+ NavigateToDestURLWithDisposition(CURRENT_TAB);
+ }
+
+ // Opens the url in a new tab, with no opener.
+ void NavigateToDestURLWithDisposition(
+ WindowOpenDisposition disposition) const {
+ NavigateToURLImpl(dest_url_, disposition);
}
void OpenDestUrlInNewWindowViaJs() const {
@@ -447,7 +461,7 @@ class PrerenderBrowserTest : public InProcessBrowserTest {
// Should be const but test_server()->GetURL(...) is not const.
void NavigateToURL(const std::string& dest_html_file) {
GURL dest_url = test_server()->GetURL(dest_html_file);
- NavigateToURLImpl(dest_url);
+ NavigateToURLImpl(dest_url, CURRENT_TAB);
}
bool UrlIsInPrerenderManager(const std::string& html_file) {
@@ -576,9 +590,15 @@ class PrerenderBrowserTest : public InProcessBrowserTest {
}
}
- void NavigateToURLImpl(const GURL& dest_url) const {
+ void NavigateToURLImpl(const GURL& dest_url,
+ WindowOpenDisposition disposition) const {
// Make sure in navigating we have a URL to use in the PrerenderManager.
- EXPECT_TRUE(GetPrerenderContents() != NULL);
+ ASSERT_TRUE(GetPrerenderContents() != NULL);
+
+ // If opening the page in a background tab, it won't be shown when swapped
+ // in.
+ if (disposition == NEW_BACKGROUND_TAB)
+ GetPrerenderContents()->set_should_be_shown(false);
// 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
@@ -588,7 +608,8 @@ class PrerenderBrowserTest : public InProcessBrowserTest {
// 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.
- browser()->OpenURL(dest_url, GURL(), CURRENT_TAB, PageTransition::TYPED);
+ 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.
@@ -596,9 +617,26 @@ class PrerenderBrowserTest : public InProcessBrowserTest {
if (call_javascript_) {
// Check if page behaved as expected when actually displayed.
+
+ // Locate the navigated TabContents.
+ TabContents* tab_contents = NULL;
+ switch (disposition) {
+ case CURRENT_TAB:
+ case NEW_FOREGROUND_TAB:
+ tab_contents = browser()->GetSelectedTabContents();
+ break;
+ case NEW_BACKGROUND_TAB:
+ tab_contents =
+ browser()->GetTabContentsAt(browser()->active_index() + 1);
+ break;
+ default:
+ ASSERT_TRUE(false) << "Unsupported creation disposition";
+ }
+ ASSERT_TRUE(tab_contents);
+
bool display_test_result = false;
ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool(
- browser()->GetSelectedTabContents()->render_view_host(), L"",
+ tab_contents->render_view_host(), L"",
L"window.domAutomationController.send(DidDisplayPass())",
&display_test_result));
EXPECT_TRUE(display_test_result);
@@ -621,6 +659,32 @@ IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, PrerenderPage) {
NavigateToDestURL();
}
+// Checks that the visibility API works.
+IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, PrerenderVisibility) {
+ PrerenderTestURL("files/prerender/prerender_visibility.html",
+ FINAL_STATUS_USED,
+ 1);
+ NavigateToDestURL();
+}
+
+// Checks that the visibility API works when opening a page in a new hidden
+// tab.
+IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, PrerenderVisibilityBackgroundTab) {
+ PrerenderTestURL("files/prerender/prerender_visibility_hidden.html",
+ FINAL_STATUS_USED,
+ 1);
+ NavigateToDestURLWithDisposition(NEW_BACKGROUND_TAB);
+}
+
+// Checks that the visibility API works when opening a page in a new foreground
+// tab.
+IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, PrerenderVisibilityForegroundTab) {
+ PrerenderTestURL("files/prerender/prerender_visibility.html",
+ FINAL_STATUS_USED,
+ 1);
+ NavigateToDestURLWithDisposition(NEW_FOREGROUND_TAB);
+}
+
// Checks that the prerendering of a page is canceled correctly when a
// Javascript alert is called.
IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, PrerenderAlertBeforeOnload) {
diff --git a/chrome/renderer/prerender/prerender_helper.cc b/chrome/renderer/prerender/prerender_helper.cc
index 053f4ef..67092dc 100644
--- a/chrome/renderer/prerender/prerender_helper.cc
+++ b/chrome/renderer/prerender/prerender_helper.cc
@@ -10,6 +10,7 @@
#include "content/renderer/navigation_state.h"
#include "content/renderer/render_view.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
// Helper macro for histograms.
#define RECORD_PLT(tag, perceived_page_load_time) { \
@@ -29,6 +30,7 @@ PrerenderHelper::PrerenderHelper(RenderView* render_view)
RenderViewObserverTracker<PrerenderHelper>(render_view),
is_prerendering_(true),
has_unrecorded_data_(false) {
+ UpdateVisibilityState();
}
PrerenderHelper::~PrerenderHelper() {
@@ -155,10 +157,19 @@ void PrerenderHelper::OnSetIsPrerendering(bool is_prerendering) {
is_prerendering_ = false;
prerender_display_time_ = base::Time::Now();
+ UpdateVisibilityState();
}
bool PrerenderHelper::HasUnrecordedData() const {
return !prerender_display_time_.is_null();
}
+void PrerenderHelper::UpdateVisibilityState() {
+ if (render_view()->webview()) {
+ render_view()->webview()->setVisibilityState(
+ render_view()->visibilityState(),
+ false);
+ }
+}
+
} // namespace prerender
diff --git a/chrome/renderer/prerender/prerender_helper.h b/chrome/renderer/prerender/prerender_helper.h
index a2db36f..5c2c87c 100644
--- a/chrome/renderer/prerender/prerender_helper.h
+++ b/chrome/renderer/prerender/prerender_helper.h
@@ -49,6 +49,10 @@ class PrerenderHelper : public RenderViewObserver,
// for the prerender have been recorded.
bool HasUnrecordedData() const;
+ // Updates the visibility state of the RenderView. Must be called whenever
+ // prerendering starts or finishes.
+ void UpdateVisibilityState();
+
// Tracks whether or not observed RenderView is currently prerendering.
bool is_prerendering_;
diff --git a/chrome/test/data/prerender/prerender_visibility.html b/chrome/test/data/prerender/prerender_visibility.html
new file mode 100644
index 0000000..bb52498
--- /dev/null
+++ b/chrome/test/data/prerender/prerender_visibility.html
@@ -0,0 +1,56 @@
+<html>
+<!--
+This test checks the visibility API when a prerendered page is displayed.
+-->
+<head>
+<title>Prerender Visibility</title>
+
+<script>
+// Checks visibility state while the page is still loading.
+var loadingStatePassed = document.webkitHidden &&
+ document.webkitVisibilityState == 'prerender';
+
+// True if any visibility change event has occurred.
+var visibilityChangeCalled = false;
+
+// True if the last visibility change event set the document's state to visible.
+var visibilityChangePassed = false;
+
+// Checks that no visibility change events have occurred, current visibility
+// state is "prerender", and visibility state while the page was loading was
+// also "prerender".
+function DidPrerenderPass() {
+ return !visibilityChangeCalled &&
+ loadingStatePassed &&
+ document.webkitHidden &&
+ 'prerender' == document.webkitVisibilityState;
+}
+
+function onVisibilityChange(event) {
+ // TODO(mmenke): Currently, we get 4 events when a page is shown -
+ // hidden -> visible -> hidden -> visible.
+ // Once that's fixed, add check to make sure we only have
+ // hidden -> visible, or just visible.
+ visibilityChangePassed =
+ !document.webkitHidden &&
+ 'visible' == document.webkitVisibilityState;
+ visibilityChangeCalled = true;
+}
+
+document.addEventListener("webkitvisibilitychange",
+ onVisibilityChange,
+ false);
+
+// Checks that the last visibility change resulted in a visible state, and that
+// the current state is also visible.
+function DidDisplayPass() {
+ return visibilityChangeCalled &&
+ visibilityChangePassed &&
+ !document.webkitHidden &&
+ 'visible' == document.webkitVisibilityState;
+}
+</script>
+
+</head>
+<body></body>
+</html>
diff --git a/chrome/test/data/prerender/prerender_visibility_hidden.html b/chrome/test/data/prerender/prerender_visibility_hidden.html
new file mode 100644
index 0000000..090f998
--- /dev/null
+++ b/chrome/test/data/prerender/prerender_visibility_hidden.html
@@ -0,0 +1,55 @@
+<html>
+<!--
+This test checks the visibility API when a prerendered page is visited without
+being displayed.
+-->
+<head>
+<title>Prerender Visibility Hidden</title>
+
+<script>
+// Checks visibility state while the page is still loading.
+var loadingStatePassed = document.webkitHidden &&
+ document.webkitVisibilityState == 'prerender';
+
+// True if any visibility change event has occurred.
+var visibilityChangeCalled = false;
+
+// True if only one visibility change event has occurred, and that event was the
+// transition to the 'hidden' state.
+var visibilityChangePassed = false;
+
+// Checks that no visibility change events have occurred, current visibility
+// state is "prerender", and visibility state while the page was loading was
+// also "prerender".
+function DidPrerenderPass() {
+ return !visibilityChangeCalled &&
+ loadingStatePassed &&
+ document.webkitHidden &&
+ 'prerender' == document.webkitVisibilityState;
+}
+
+function onVisibilityChange(event) {
+ visibilityChangePassed =
+ !visibilityChangeCalled &&
+ document.webkitHidden &&
+ 'hidden' == document.webkitVisibilityState;
+ visibilityChangeCalled = true;
+}
+
+document.addEventListener("webkitvisibilitychange",
+ onVisibilityChange,
+ false);
+
+// Checks one and only one visibility change even occurred, and resulted in a
+// hidden state, and that current state is also hidden.
+function DidDisplayPass() {
+ return visibilityChangeCalled &&
+ visibilityChangePassed &&
+ document.webkitHidden &&
+ 'hidden' == document.webkitVisibilityState;
+}
+</script>
+
+</head>
+<body></body>
+</html>