Commit 796931a9 authored by cbentzel@chromium.org's avatar cbentzel@chromium.org

A fairly recent change introduced a history of page_ids for each RenderView,...

A fairly recent change introduced a history of page_ids for each RenderView, to validate that Navigation's go to legitimate pages.

In the prerender and instant cases, the history of page_id's was not accurate, because it was not offset to reflect the point in time when the page was swapped in. For example, if the history for the tab looks like

about:blank
http://www.launchprerender.com/
http://www.prerendered_page.com/first_page.html
http://www.prerendered_page.com/second_page.html

The history of page_id's in the prerender-page RenderView should look like

[-1, -1, 13, 14] - with the first two entries being -1 since they are not captured in this render view.

Before this fix, it would look like

[13, 14] - and when the back navigation was attempted, the length was not as long as expected.

BUG=89798
TEST=Go to prerender_test.appspot.com, do a prerender on dev.chromium.org, click on a link within dev.chromium.org, press back and see that it works instead of spinning forever. Also, browser_tests --gtest_filter=*BackToPrerenderedPage, which fails without the change.

Review URL: http://codereview.chromium.org/7491096

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@96109 0039d316-1c4b-4281-b951-d872f2087c98
parent 04dd0d69
...@@ -473,6 +473,26 @@ class PrerenderBrowserTest : public InProcessBrowserTest { ...@@ -473,6 +473,26 @@ class PrerenderBrowserTest : public InProcessBrowserTest {
} }
} }
void OpenDestUrlViaClick() const {
// Make sure in navigating we have a URL to use in the PrerenderManager.
TestPrerenderContents* prerender_contents = GetPrerenderContents();
ASSERT_TRUE(prerender_contents != NULL);
prerender_contents->set_quit_message_loop_on_destruction(false);
bool click_prerendered_link_result = false;
ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool(
browser()->GetSelectedTabContents()->render_view_host(), L"",
L"window.domAutomationController.send(ClickOpenLink())",
&click_prerendered_link_result));
EXPECT_TRUE(click_prerendered_link_result);
// If the prerender contents has not been destroyed, run message loop.
if (GetPrerenderContents() != NULL) {
prerender_contents->set_quit_message_loop_on_destruction(true);
ui_test_utils::RunMessageLoop();
}
}
// Should be const but test_server()->GetURL(...) is not const. // Should be const but test_server()->GetURL(...) is not const.
void NavigateToURL(const std::string& dest_html_file) { void NavigateToURL(const std::string& dest_html_file) {
GURL dest_url = test_server()->GetURL(dest_html_file); GURL dest_url = test_server()->GetURL(dest_html_file);
...@@ -1612,4 +1632,41 @@ IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, PrerenderCancelAll) { ...@@ -1612,4 +1632,41 @@ IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, PrerenderCancelAll) {
EXPECT_TRUE(GetPrerenderContents() == NULL); EXPECT_TRUE(GetPrerenderContents() == NULL);
} }
IN_PROC_BROWSER_TEST_F(PrerenderBrowserTest, BackToPrerenderedPage) {
PrerenderTestURL("files/prerender/prerender_page_with_link.html",
FINAL_STATUS_USED,
1);
OpenDestUrlViaClick();
// Click on the link in the page and wait for it to commit
{
ui_test_utils::WindowedNotificationObserver new_page_observer(
content::NOTIFICATION_NAV_ENTRY_COMMITTED,
NotificationService::AllSources());
bool click_link_result = false;
ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool(
browser()->GetSelectedTabContents()->render_view_host(), L"",
L"window.domAutomationController.send(ClickOpenLink())",
&click_link_result));
EXPECT_TRUE(click_link_result);
new_page_observer.Wait();
}
// Now, go back to the prerendered page.
{
ui_test_utils::WindowedNotificationObserver back_nav_observer(
content::NOTIFICATION_NAV_ENTRY_COMMITTED,
NotificationService::AllSources());
browser()->GoBack(CURRENT_TAB);
back_nav_observer.Wait();
bool original_prerender_page = false;
ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool(
browser()->GetSelectedTabContents()->render_view_host(), L"",
L"window.domAutomationController.send(IsOriginalPrerenderPage())",
&original_prerender_page));
EXPECT_TRUE(original_prerender_page);
}
}
} // namespace prerender } // namespace prerender
...@@ -4,14 +4,21 @@ ...@@ -4,14 +4,21 @@
<script> <script>
function ClickOpenLinkInNewWindow() { function ClickOpenLinkInNewWindow() {
var eventObject = document.createEvent("MouseEvents"); var eventObject = document.createEvent('MouseEvents');
eventObject.initMouseEvent('click'); eventObject.initMouseEvent('click');
document.getElementById("toClick").dispatchEvent(eventObject); document.getElementById('toClickTarget').dispatchEvent(eventObject);
return true;
}
function ClickOpenLink() {
var eventObject = document.createEvent('MouseEvents');
eventObject.initMouseEvent('click');
document.getElementById('toClick').dispatchEvent(eventObject);
return true; return true;
} }
function JsOpenLinkInNewWindow() { function JsOpenLinkInNewWindow() {
window.open("REPLACE_WITH_PRERENDER_URL"); window.open('REPLACE_WITH_PRERENDER_URL');
return true; return true;
} }
</script> </script>
...@@ -21,7 +28,8 @@ ...@@ -21,7 +28,8 @@
<script> <script>
document.write('<link rel="prerender" href="REPLACE_WITH_PRERENDER_URL"/>'); document.write('<link rel="prerender" href="REPLACE_WITH_PRERENDER_URL"/>');
</script> </script>
<a target="_blank" id="toClick" <a target="_blank" id="toClickTarget"
href="REPLACE_WITH_PRERENDER_URL">Link To Click</a> href="REPLACE_WITH_PRERENDER_URL">Link To click in new window</a>
<a id="toClick" href="REPLACE_WITH_PRERENDER_URL">Link to click</a>
</body> </body>
</html> </html>
<html>
<head>
<title>Prerendered page with link</title>
<script>
var pageWasPrerendered = false;
// Make sure plugin was not loaded while prerendering.
function DidPrerenderPass() {
pageWasPrerendered = true;
return true;
}
function ClickOpenLink() {
var eventObject = document.createEvent('MouseEvents');
eventObject.initMouseEvent('click');
document.getElementById('toClick').dispatchEvent(eventObject);
return true;
}
function IsOriginalPrerenderPage() {
return true;
}
</script>
</head>
<body>
<a id="toClick" href="prerender_page.html">Link to click</a>
</body>
</html>
...@@ -931,6 +931,9 @@ void NavigationController::CopyStateFromAndPrune(NavigationController* source, ...@@ -931,6 +931,9 @@ void NavigationController::CopyStateFromAndPrune(NavigationController* source,
if (last_committed_entry_index_ != -1) if (last_committed_entry_index_ != -1)
last_committed_entry_index_--; last_committed_entry_index_--;
} }
// Update the history in the RenderView.
tab_contents_->SetHistoryLengthAndClear(max_source_index);
} }
void NavigationController::PruneAllButActive() { void NavigationController::PruneAllButActive() {
......
...@@ -596,6 +596,14 @@ bool TabContents::NavigateToEntry( ...@@ -596,6 +596,14 @@ bool TabContents::NavigateToEntry(
return true; return true;
} }
void TabContents::SetHistoryLengthAndClear(int history_length) {
RenderViewHost* rvh = render_view_host();
if (!rvh)
return;
rvh->Send(new ViewMsg_SetHistoryLengthAndClear(rvh->routing_id(),
history_length));
}
void TabContents::Stop() { void TabContents::Stop() {
render_manager_.Stop(); render_manager_.Stop();
FOR_EACH_OBSERVER(TabContentsObserver, observers_, StopNavigation()); FOR_EACH_OBSERVER(TabContentsObserver, observers_, StopNavigation());
......
...@@ -623,6 +623,13 @@ class TabContents : public PageNavigator, ...@@ -623,6 +623,13 @@ class TabContents : public PageNavigator,
bool NavigateToEntry(const NavigationEntry& entry, bool NavigateToEntry(const NavigationEntry& entry,
NavigationController::ReloadType reload_type); NavigationController::ReloadType reload_type);
// Sets the history for this tab_contents to |history_length| entries, and
// moves the current page_id to the last entry in the list if it's valid.
// This is mainly used when a prerendered page is swapped into the current
// tab.
void SetHistoryLengthAndClear(int history_length);
// Misc non-view stuff ------------------------------------------------------- // Misc non-view stuff -------------------------------------------------------
// Helper functions for sending notifications. // Helper functions for sending notifications.
......
...@@ -744,6 +744,18 @@ IPC_STRUCT_END() ...@@ -744,6 +744,18 @@ IPC_STRUCT_END()
IPC_MESSAGE_CONTROL1(ViewMsg_SetNextPageID, IPC_MESSAGE_CONTROL1(ViewMsg_SetNextPageID,
int32 /* next_page_id */) int32 /* next_page_id */)
// Sets the history length of page_ids for a RenderView to
// |length| entries, and moves the current page_id to the last
// entry if it is valid.
// The main use for this is prerendered pages, but Instant pages also use this.
// For example, assume that there are 3 entries in the history when a
// prerendered page is created. The new prerendered page will have a single
// entry history like [7]. When it is swapped in, we need to extend the history
// so it has a total length of 4 (3 for the previous history, 1 for the
// prerendered page), so it looks like [-1 -1 -1 7].
IPC_MESSAGE_ROUTED1(ViewMsg_SetHistoryLengthAndClear,
int /* length */)
// Sends System Colors corresponding to a set of CSS color keywords // Sends System Colors corresponding to a set of CSS color keywords
// down the pipe. // down the pipe.
// This message must be sent to the renderer immediately on launch // This message must be sent to the renderer immediately on launch
......
...@@ -704,6 +704,8 @@ bool RenderView::OnMessageReceived(const IPC::Message& message) { ...@@ -704,6 +704,8 @@ bool RenderView::OnMessageReceived(const IPC::Message& message) {
#endif #endif
IPC_MESSAGE_HANDLER(ViewMsg_UpdateRemoteAccessClientFirewallTraversal, IPC_MESSAGE_HANDLER(ViewMsg_UpdateRemoteAccessClientFirewallTraversal,
OnUpdateRemoteAccessClientFirewallTraversal) OnUpdateRemoteAccessClientFirewallTraversal)
IPC_MESSAGE_HANDLER(ViewMsg_SetHistoryLengthAndClear,
OnSetHistoryLengthAndClear)
// Have the super handle all other messages. // Have the super handle all other messages.
IPC_MESSAGE_UNHANDLED(handled = RenderWidget::OnMessageReceived(message)) IPC_MESSAGE_UNHANDLED(handled = RenderWidget::OnMessageReceived(message))
IPC_END_MESSAGE_MAP() IPC_END_MESSAGE_MAP()
...@@ -1018,6 +1020,32 @@ void RenderView::OnScrollFocusedEditableNodeIntoView() { ...@@ -1018,6 +1020,32 @@ void RenderView::OnScrollFocusedEditableNodeIntoView() {
} }
} }
void RenderView::OnSetHistoryLengthAndClear(int history_length) {
DCHECK(history_length >= 0);
// history_list_length_ may be 0 if this is called between
// a navigate and a commit of the provisional load. Otherwise,
// only add one entry, regardless of how long the current history is.
// TODO(cbentzel): Investigate what happens if a prerendered page
// navigates to several entries before it is swapped in. Cropping
// those may be a bad idea.
int new_history_list_length = history_length;
if (history_list_length_ > 0)
++new_history_list_length;
DCHECK(page_id_ == -1 ||
(history_list_offset_ >= 0 &&
page_id_ == history_page_ids_[history_list_offset_]));
// Generate the new list.
std::vector<int32> new_history_page_ids(new_history_list_length, -1);
if (page_id_ != -1)
new_history_page_ids[new_history_list_length - 1] = page_id_;
new_history_page_ids.swap(history_page_ids_);
history_list_offset_ = new_history_list_length - 1;
history_list_length_ = new_history_list_length;
}
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// Tell the embedding application that the URL of the active page has changed // Tell the embedding application that the URL of the active page has changed
......
...@@ -847,6 +847,7 @@ class RenderView : public RenderWidget, ...@@ -847,6 +847,7 @@ class RenderView : public RenderWidget,
void OnUpdateTargetURLAck(); void OnUpdateTargetURLAck();
void OnUpdateWebPreferences(const WebPreferences& prefs); void OnUpdateWebPreferences(const WebPreferences& prefs);
void OnUpdateRemoteAccessClientFirewallTraversal(const std::string& policy); void OnUpdateRemoteAccessClientFirewallTraversal(const std::string& policy);
void OnSetHistoryLengthAndClear(int history_length);
#if defined(OS_MACOSX) #if defined(OS_MACOSX)
void OnWindowFrameChanged(const gfx::Rect& window_frame, void OnWindowFrameChanged(const gfx::Rect& window_frame,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment