Add a WebContents API for initializing the renderer without navigating
I added prepare_renderer flag in WebContents::CreateParams.
So now we can create WebContents with renderer process and RenderFrame
without navigation to about:blank or something like that.
It is need to avoid hack with navigation and to save resources.
BUG=521729
[email protected], [email protected]
Review-Url: https://codereview.chromium.org/1970253002
Cr-Commit-Position: refs/heads/master@{#395413}
diff --git a/chrome/browser/ui/browser_navigator_browsertest.cc b/chrome/browser/ui/browser_navigator_browsertest.cc
index 429519a..93c12211 100644
--- a/chrome/browser/ui/browser_navigator_browsertest.cc
+++ b/chrome/browser/ui/browser_navigator_browsertest.cc
@@ -30,7 +30,10 @@
#include "components/prefs/pref_service.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_types.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/render_process_host.h"
#include "content/public/browser/web_contents.h"
+#include "content/public/test/browser_test_utils.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
using content::WebContents;
@@ -126,8 +129,9 @@
return browser;
}
-WebContents* BrowserNavigatorTest::CreateWebContents() {
+WebContents* BrowserNavigatorTest::CreateWebContents(bool initialize_renderer) {
content::WebContents::CreateParams create_params(browser()->profile());
+ create_params.initialize_renderer = initialize_renderer;
content::WebContents* base_web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
if (base_web_contents) {
@@ -700,10 +704,10 @@
IN_PROC_BROWSER_TEST_F(BrowserNavigatorTest, TargetContents_ForegroundTab) {
chrome::NavigateParams params(MakeNavigateParams());
params.disposition = NEW_FOREGROUND_TAB;
- params.target_contents = CreateWebContents();
+ params.target_contents = CreateWebContents(false);
chrome::Navigate(¶ms);
- // Navigate() should have opened the contents in a new foreground in the
+ // Navigate() should have opened the contents in a new foreground tab in the
// current Browser.
EXPECT_EQ(browser(), params.browser);
EXPECT_EQ(browser()->tab_strip_model()->GetActiveWebContents(),
@@ -719,7 +723,7 @@
IN_PROC_BROWSER_TEST_F(BrowserNavigatorTest, DISABLED_TargetContents_Popup) {
chrome::NavigateParams params(MakeNavigateParams());
params.disposition = NEW_POPUP;
- params.target_contents = CreateWebContents();
+ params.target_contents = CreateWebContents(false);
params.window_bounds = gfx::Rect(10, 10, 500, 500);
chrome::Navigate(¶ms);
@@ -753,6 +757,46 @@
}
#endif
+// This test checks that we can create WebContents with renderer process and
+// RenderFrame without navigating it.
+IN_PROC_BROWSER_TEST_F(BrowserNavigatorTest,
+ CreateWebContentsWithRendererProcess) {
+ chrome::NavigateParams params(MakeNavigateParams());
+ params.disposition = NEW_FOREGROUND_TAB;
+ params.target_contents = CreateWebContents(true);
+ ASSERT_TRUE(params.target_contents);
+
+ // There is no navigation (to about:blank or something like that).
+ EXPECT_FALSE(params.target_contents->IsLoading());
+
+ ASSERT_TRUE(params.target_contents->GetMainFrame());
+ EXPECT_TRUE(params.target_contents->GetMainFrame()->IsRenderFrameLive());
+ EXPECT_TRUE(
+ params.target_contents->GetController().IsInitialBlankNavigation());
+ int renderer_id = params.target_contents->GetRenderProcessHost()->GetID();
+
+ // We should have one window, with one tab of WebContents differ from
+ // params.target_contents.
+ EXPECT_EQ(1u, chrome::GetTotalBrowserCount());
+ EXPECT_EQ(1, browser()->tab_strip_model()->count());
+ EXPECT_NE(browser()->tab_strip_model()->GetActiveWebContents(),
+ params.target_contents);
+
+ chrome::Navigate(¶ms);
+
+ // Navigate() should have opened the contents in a new foreground tab in the
+ // current Browser, without changing the renderer process of target_contents.
+ EXPECT_EQ(browser(), params.browser);
+ EXPECT_EQ(browser()->tab_strip_model()->GetActiveWebContents(),
+ params.target_contents);
+ EXPECT_EQ(renderer_id,
+ params.target_contents->GetRenderProcessHost()->GetID());
+
+ // We should have one window, with two tabs.
+ EXPECT_EQ(1u, chrome::GetTotalBrowserCount());
+ EXPECT_EQ(2, browser()->tab_strip_model()->count());
+}
+
// This tests adding a tab at a specific index.
IN_PROC_BROWSER_TEST_F(BrowserNavigatorTest, Tabstrip_InsertAtIndex) {
// This is not meant to be a comprehensive test of whether or not the tab
diff --git a/chrome/browser/ui/browser_navigator_browsertest.h b/chrome/browser/ui/browser_navigator_browsertest.h
index eb089862..4d5a998 100644
--- a/chrome/browser/ui/browser_navigator_browsertest.h
+++ b/chrome/browser/ui/browser_navigator_browsertest.h
@@ -36,7 +36,7 @@
Browser* CreateEmptyBrowserForType(Browser::Type type, Profile* profile);
Browser* CreateEmptyBrowserForApp(Profile* profile);
- content::WebContents* CreateWebContents();
+ content::WebContents* CreateWebContents(bool initialize_renderer);
void RunSuppressTest(WindowOpenDisposition disposition);
void RunUseNonIncognitoWindowTest(const GURL& url);
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 33f0093..13947aab1 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -1584,6 +1584,13 @@
GetRenderManager()->current_frame_host()->SetRenderFrameCreated(true);
}
+ // Create the renderer process in advance if requested.
+ if (params.initialize_renderer) {
+ if (!GetRenderManager()->current_frame_host()->IsRenderFrameLive()) {
+ GetRenderManager()->InitRenderView(GetRenderViewHost(), nullptr);
+ }
+ }
+
// Ensure that observers are notified of the creation of this WebContents's
// main RenderFrameHost. It must be done here for main frames, since the
// NotifySwappedFromRenderManager expects view_ to already be created and that
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index ef56b7d..6eedb76 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -757,7 +757,7 @@
const gfx::RectF& active_rect);
#endif
-private:
+ private:
friend class WebContentsObserver;
friend class WebContents; // To implement factory methods.
diff --git a/content/browser/web_contents/web_contents_impl_browsertest.cc b/content/browser/web_contents/web_contents_impl_browsertest.cc
index 55e00c56..b6593d3f 100644
--- a/content/browser/web_contents/web_contents_impl_browsertest.cc
+++ b/content/browser/web_contents/web_contents_impl_browsertest.cc
@@ -1011,4 +1011,83 @@
wc->SetJavaScriptDialogManagerForTesting(nullptr);
}
+IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
+ CreateWebContentsWithRendererProcess) {
+ GURL url("http://c.com/title3.html");
+ ASSERT_TRUE(embedded_test_server()->Start());
+ WebContents* base_web_contents = shell()->web_contents();
+ ASSERT_TRUE(base_web_contents);
+
+ WebContents::CreateParams create_params(
+ base_web_contents->GetBrowserContext());
+ create_params.initialize_renderer = true;
+ create_params.initial_size =
+ base_web_contents->GetContainerBounds().size();
+ std::unique_ptr<WebContents> web_contents(WebContents::Create(create_params));
+ ASSERT_TRUE(web_contents);
+
+ // There is no navigation (to about:blank or something like that).
+ EXPECT_FALSE(web_contents->IsLoading());
+
+ ASSERT_TRUE(web_contents->GetMainFrame());
+ EXPECT_TRUE(web_contents->GetMainFrame()->IsRenderFrameLive());
+ EXPECT_TRUE(web_contents->GetController().IsInitialBlankNavigation());
+ int renderer_id = web_contents->GetRenderProcessHost()->GetID();
+
+ TestNavigationObserver same_tab_observer(web_contents.get(), 1);
+ NavigationController::LoadURLParams params(url);
+ params.transition_type = ui::PageTransitionFromInt(
+ ui::PAGE_TRANSITION_TYPED | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR);
+ web_contents->GetController().LoadURLWithParams(params);
+ same_tab_observer.Wait();
+
+ // Check that pre-warmed process is used.
+ EXPECT_EQ(renderer_id, web_contents->GetRenderProcessHost()->GetID());
+ EXPECT_EQ(1, web_contents->GetController().GetEntryCount());
+ NavigationEntry* entry =
+ web_contents->GetController().GetLastCommittedEntry();
+ ASSERT_TRUE(entry);
+ EXPECT_EQ(url, entry->GetURL());
+}
+
+IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
+ NavigatingToWebUIDoesNotUsePreWarmedProcess) {
+ GURL web_ui_url(std::string(kChromeUIScheme) + "://" +
+ std::string(kChromeUIGpuHost));
+ ASSERT_TRUE(embedded_test_server()->Start());
+ WebContents* base_web_contents = shell()->web_contents();
+ ASSERT_TRUE(base_web_contents);
+
+ WebContents::CreateParams create_params(
+ base_web_contents->GetBrowserContext());
+ create_params.initialize_renderer = true;
+ create_params.initial_size =
+ base_web_contents->GetContainerBounds().size();
+ std::unique_ptr<WebContents> web_contents(WebContents::Create(create_params));
+ ASSERT_TRUE(web_contents);
+
+ // There is no navigation (to about:blank or something like that).
+ EXPECT_FALSE(web_contents->IsLoading());
+
+ ASSERT_TRUE(web_contents->GetMainFrame());
+ EXPECT_TRUE(web_contents->GetMainFrame()->IsRenderFrameLive());
+ EXPECT_TRUE(web_contents->GetController().IsInitialBlankNavigation());
+ int renderer_id = web_contents->GetRenderProcessHost()->GetID();
+
+ TestNavigationObserver same_tab_observer(web_contents.get(), 1);
+ NavigationController::LoadURLParams params(web_ui_url);
+ params.transition_type = ui::PageTransitionFromInt(
+ ui::PAGE_TRANSITION_TYPED | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR);
+ web_contents->GetController().LoadURLWithParams(params);
+ same_tab_observer.Wait();
+
+ // Check that pre-warmed process isn't used.
+ EXPECT_NE(renderer_id, web_contents->GetRenderProcessHost()->GetID());
+ EXPECT_EQ(1, web_contents->GetController().GetEntryCount());
+ NavigationEntry* entry =
+ web_contents->GetController().GetLastCommittedEntry();
+ ASSERT_TRUE(entry);
+ EXPECT_EQ(web_ui_url, entry->GetURL());
+}
+
} // namespace content
diff --git a/content/public/browser/web_contents.cc b/content/public/browser/web_contents.cc
index 69190cf..fa0afb5 100644
--- a/content/public/browser/web_contents.cc
+++ b/content/public/browser/web_contents.cc
@@ -28,7 +28,9 @@
initially_hidden(false),
guest_delegate(nullptr),
context(nullptr),
- renderer_initiated_creation(false) {}
+ renderer_initiated_creation(false),
+ initialize_renderer(false) {
+}
WebContents::CreateParams::CreateParams(const CreateParams& other) = default;
diff --git a/content/public/browser/web_contents.h b/content/public/browser/web_contents.h
index 6aa00e6..90b647e 100644
--- a/content/public/browser/web_contents.h
+++ b/content/public/browser/web_contents.h
@@ -149,6 +149,14 @@
// RenderFrame, have already been created on the renderer side, and
// WebContents construction should take this into account.
bool renderer_initiated_creation;
+
+ // True if the WebContents should create its renderer process and main
+ // RenderFrame before the first navigation. This is useful to reduce
+ // the latency of the first navigation in cases where it might
+ // not happen right away.
+ // Note that the pre-created renderer process may not be used if the first
+ // navigation requires a dedicated or privileged process, such as a WebUI.
+ bool initialize_renderer;
};
// Creates a new WebContents.