Give the main frame a RenderWidget.

Currently, RenderView is a subclass of RenderWidget, and the RenderWidget
portion is effectively treated as the  the widget for the main frame as
well. For a number of reasons, this is a problematic model:

- A remote frame doesn't need a widget; however, a RenderView with a remote
  main frame still has a vestigal RenderWidget.
- Code that needs to affect both RenderWidget / RenderView is awkwardly
  split between them, in both content and blink.
- RenderView itself is often seen as an easy entry point to perform
  page-level work in the renderer. With OOPI, this is no longer a valid
  assumption.

In order to incrementally de-widgetize RenderView, the main frame will
have also have a RenderWidget, to make it consistent with the local frame
roots for subframes, which already have a RenderWidget. However, instead of
giving main frames their own RenderWidget, the main frame re-uses the
RenderView as its RenderWidget.

The rationale for taking this approach is to minimize the breakage: today,
Chrome simply doesn't expect to have two "widgets" for a frame.
Instantiating a distinct RenderWidget for the main frame can confuse code
that iterates or counts the active widgets: an example of this is the
security check for injecting WebUI bindings.

In the future, when RenderViewHost has-a RenderWidgetHost (and similarly,
when RenderViewImpl has-a RenderWidget) instead of today's is-a relation,
then it be conceptually much more straightforward to transition completely
to the new model.

BUG=419087

Review URL: https://codereview.chromium.org/1303773002

Cr-Commit-Position: refs/heads/master@{#356176}
diff --git a/content/browser/frame_host/frame_tree_node.cc b/content/browser/frame_host/frame_tree_node.cc
index c44c19c..876be33 100644
--- a/content/browser/frame_host/frame_tree_node.cc
+++ b/content/browser/frame_host/frame_tree_node.cc
@@ -131,7 +131,6 @@
   // frames in the same SiteInstance as the current frame, and they can swap to
   // a different one if they navigate away.
   child->render_manager()->Init(
-      render_manager_.current_host()->GetSiteInstance()->GetBrowserContext(),
       render_manager_.current_host()->GetSiteInstance(),
       render_manager_.current_host()->GetRoutingID(), frame_routing_id,
       MSG_ROUTING_NONE);
diff --git a/content/browser/frame_host/frame_tree_unittest.cc b/content/browser/frame_host/frame_tree_unittest.cc
index b40628b..6804994 100644
--- a/content/browser/frame_host/frame_tree_unittest.cc
+++ b/content/browser/frame_host/frame_tree_unittest.cc
@@ -136,7 +136,7 @@
   // itself. Instead, leave them in "not live" state, which is indicated by the
   // * after the frame id, since this test cares about the shape, not the
   // frame liveliness.
-  EXPECT_EQ("1*: []", GetTreeState(frame_tree));
+  EXPECT_EQ("2*: []", GetTreeState(frame_tree));
 
   // Simulate attaching a series of frames to build the frame tree.
   frame_tree->AddFrame(root, process_id, 14, blink::WebTreeScopeType::Document,
@@ -156,10 +156,11 @@
                        blink::WebTreeScopeType::Document, std::string(),
                        blink::WebSandboxFlags::None);
 
-  EXPECT_EQ("1*: [14*: [244*: [], 245*: []], "
-                "15*: [255* 'no children node': []], "
-                "16*: []]",
-            GetTreeState(frame_tree));
+  EXPECT_EQ(
+      "2*: [14*: [244*: [], 245*: []], "
+      "15*: [255* 'no children node': []], "
+      "16*: []]",
+      GetTreeState(frame_tree));
 
   FrameTreeNode* child_16 = root->child_at(2);
   frame_tree->AddFrame(child_16, process_id, 264,
@@ -193,36 +194,40 @@
                        std::string(), blink::WebSandboxFlags::None);
 
   // Now that's it's fully built, verify the tree structure is as expected.
-  EXPECT_EQ("1*: [14*: [244*: [], 245*: []], "
-                "15*: [255* 'no children node': []], "
-                "16*: [264*: [], 265*: [], 266*: [], "
-                     "267* 'node with deep subtree': "
-                         "[365*: [455*: [555*: [655*: []]]]], 268*: []]]",
-            GetTreeState(frame_tree));
+  EXPECT_EQ(
+      "2*: [14*: [244*: [], 245*: []], "
+      "15*: [255* 'no children node': []], "
+      "16*: [264*: [], 265*: [], 266*: [], "
+      "267* 'node with deep subtree': "
+      "[365*: [455*: [555*: [655*: []]]]], 268*: []]]",
+      GetTreeState(frame_tree));
 
   FrameTreeNode* child_555 = child_267->child_at(0)->child_at(0)->child_at(0);
   frame_tree->RemoveFrame(child_555);
-  EXPECT_EQ("1*: [14*: [244*: [], 245*: []], "
-                "15*: [255* 'no children node': []], "
-                "16*: [264*: [], 265*: [], 266*: [], "
-                     "267* 'node with deep subtree': "
-                         "[365*: [455*: []]], 268*: []]]",
-            GetTreeState(frame_tree));
+  EXPECT_EQ(
+      "2*: [14*: [244*: [], 245*: []], "
+      "15*: [255* 'no children node': []], "
+      "16*: [264*: [], 265*: [], 266*: [], "
+      "267* 'node with deep subtree': "
+      "[365*: [455*: []]], 268*: []]]",
+      GetTreeState(frame_tree));
 
   frame_tree->RemoveFrame(child_16->child_at(1));
-  EXPECT_EQ("1*: [14*: [244*: [], 245*: []], "
-                "15*: [255* 'no children node': []], "
-                "16*: [264*: [], 266*: [], "
-                     "267* 'node with deep subtree': "
-                         "[365*: [455*: []]], 268*: []]]",
-            GetTreeState(frame_tree));
+  EXPECT_EQ(
+      "2*: [14*: [244*: [], 245*: []], "
+      "15*: [255* 'no children node': []], "
+      "16*: [264*: [], 266*: [], "
+      "267* 'node with deep subtree': "
+      "[365*: [455*: []]], 268*: []]]",
+      GetTreeState(frame_tree));
 
   frame_tree->RemoveFrame(root->child_at(1));
-  EXPECT_EQ("1*: [14*: [244*: [], 245*: []], "
-                "16*: [264*: [], 266*: [], "
-                     "267* 'node with deep subtree': "
-                         "[365*: [455*: []]], 268*: []]]",
-            GetTreeState(frame_tree));
+  EXPECT_EQ(
+      "2*: [14*: [244*: [], 245*: []], "
+      "16*: [264*: [], 266*: [], "
+      "267* 'node with deep subtree': "
+      "[365*: [455*: []]], 268*: []]]",
+      GetTreeState(frame_tree));
 }
 
 // Ensure frames can be found by frame_tree_node_id, routing ID, or name.
@@ -312,7 +317,7 @@
 TEST_F(FrameTreeTest, ObserverWalksTreeDuringFrameCreation) {
   TreeWalkingWebContentsLogger activity(contents());
   contents()->NavigateAndCommit(GURL("http://www.google.com"));
-  EXPECT_EQ("RenderFrameCreated(1) -> 1: []", activity.GetLog());
+  EXPECT_EQ("RenderFrameCreated(2) -> 2: []", activity.GetLog());
 
   FrameTree* frame_tree = contents()->GetFrameTree();
   FrameTreeNode* root = frame_tree->root();
@@ -322,20 +327,20 @@
                                       std::string(),
                                       blink::WebSandboxFlags::None);
   EXPECT_EQ(
-      "RenderFrameHostChanged(new)(14) -> 1: []\n"
-      "RenderFrameCreated(14) -> 1: [14: []]",
+      "RenderFrameHostChanged(new)(14) -> 2: []\n"
+      "RenderFrameCreated(14) -> 2: [14: []]",
       activity.GetLog());
   main_test_rfh()->OnCreateChildFrame(18, blink::WebTreeScopeType::Document,
                                       std::string(),
                                       blink::WebSandboxFlags::None);
   EXPECT_EQ(
-      "RenderFrameHostChanged(new)(18) -> 1: [14: []]\n"
-      "RenderFrameCreated(18) -> 1: [14: [], 18: []]",
+      "RenderFrameHostChanged(new)(18) -> 2: [14: []]\n"
+      "RenderFrameCreated(18) -> 2: [14: [], 18: []]",
       activity.GetLog());
   frame_tree->RemoveFrame(root->child_at(0));
-  EXPECT_EQ("RenderFrameDeleted(14) -> 1: [18: []]", activity.GetLog());
+  EXPECT_EQ("RenderFrameDeleted(14) -> 2: [18: []]", activity.GetLog());
   frame_tree->RemoveFrame(root->child_at(0));
-  EXPECT_EQ("RenderFrameDeleted(18) -> 1: []", activity.GetLog());
+  EXPECT_EQ("RenderFrameDeleted(18) -> 2: []", activity.GetLog());
 }
 
 // Make sure that WebContentsObservers see a consistent view of the tree after
@@ -343,30 +348,30 @@
 TEST_F(FrameTreeTest, ObserverWalksTreeAfterCrash) {
   TreeWalkingWebContentsLogger activity(contents());
   contents()->NavigateAndCommit(GURL("http://www.google.com"));
-  EXPECT_EQ("RenderFrameCreated(1) -> 1: []", activity.GetLog());
+  EXPECT_EQ("RenderFrameCreated(2) -> 2: []", activity.GetLog());
 
   main_test_rfh()->OnCreateChildFrame(22, blink::WebTreeScopeType::Document,
                                       std::string(),
                                       blink::WebSandboxFlags::None);
   EXPECT_EQ(
-      "RenderFrameHostChanged(new)(22) -> 1: []\n"
-      "RenderFrameCreated(22) -> 1: [22: []]",
+      "RenderFrameHostChanged(new)(22) -> 2: []\n"
+      "RenderFrameCreated(22) -> 2: [22: []]",
       activity.GetLog());
   main_test_rfh()->OnCreateChildFrame(23, blink::WebTreeScopeType::Document,
                                       std::string(),
                                       blink::WebSandboxFlags::None);
   EXPECT_EQ(
-      "RenderFrameHostChanged(new)(23) -> 1: [22: []]\n"
-      "RenderFrameCreated(23) -> 1: [22: [], 23: []]",
+      "RenderFrameHostChanged(new)(23) -> 2: [22: []]\n"
+      "RenderFrameCreated(23) -> 2: [22: [], 23: []]",
       activity.GetLog());
 
   // Crash the renderer
   main_test_rfh()->GetProcess()->SimulateCrash();
   EXPECT_EQ(
-      "RenderProcessGone -> 1*: [22*: [], 23*: []]\n"
-      "RenderFrameDeleted(23) -> 1*: [22*: [], 23*: []]\n"
-      "RenderFrameDeleted(22) -> 1*: [22*: [], 23*: []]\n"
-      "RenderFrameDeleted(1) -> 1*: []",
+      "RenderProcessGone -> 2*: [22*: [], 23*: []]\n"
+      "RenderFrameDeleted(23) -> 2*: [22*: [], 23*: []]\n"
+      "RenderFrameDeleted(22) -> 2*: [22*: [], 23*: []]\n"
+      "RenderFrameDeleted(2) -> 2*: []",
       activity.GetLog());
 }
 
@@ -378,13 +383,13 @@
   FrameTreeNode* root = frame_tree->root();
   int process_id = root->current_frame_host()->GetProcess()->GetID();
 
-  ASSERT_EQ("1: []", GetTreeState(frame_tree));
+  ASSERT_EQ("2: []", GetTreeState(frame_tree));
 
   // Simulate attaching a frame from mismatched process id.
   ASSERT_FALSE(frame_tree->AddFrame(
       root, process_id + 1, 1, blink::WebTreeScopeType::Document, std::string(),
       blink::WebSandboxFlags::None));
-  ASSERT_EQ("1: []", GetTreeState(frame_tree));
+  ASSERT_EQ("2: []", GetTreeState(frame_tree));
 }
 
 // Ensure that frames removed while a process has crashed are not preserved in
diff --git a/content/browser/frame_host/interstitial_page_impl.cc b/content/browser/frame_host/interstitial_page_impl.cc
index 810647124..c3e6fa1d 100644
--- a/content/browser/frame_host/interstitial_page_impl.cc
+++ b/content/browser/frame_host/interstitial_page_impl.cc
@@ -595,9 +595,12 @@
       new SessionStorageNamespaceImpl(dom_storage_context);
 
   // Use the RenderViewHost from our FrameTree.
+  // TODO(avi): The view routing ID can be restored to MSG_ROUTING_NONE once
+  // RenderViewHostImpl has-a RenderWidgetHostImpl. https://crbug.com/545684
+  int32_t widget_routing_id = site_instance->GetProcess()->GetNextRoutingID();
   frame_tree_.root()->render_manager()->Init(
-      browser_context, site_instance.get(), MSG_ROUTING_NONE, MSG_ROUTING_NONE,
-      MSG_ROUTING_NONE);
+      site_instance.get(), widget_routing_id, MSG_ROUTING_NONE,
+      widget_routing_id);
   return frame_tree_.root()->current_frame_host()->render_view_host();
 }
 
@@ -761,8 +764,9 @@
 
 void InterstitialPageImpl::CreateNewWindow(
     SiteInstance* source_site_instance,
-    int route_id,
-    int main_frame_route_id,
+    int32_t route_id,
+    int32_t main_frame_route_id,
+    int32_t main_frame_widget_route_id,
     const ViewHostMsg_CreateWindow_Params& params,
     SessionStorageNamespace* session_storage_namespace) {
   NOTREACHED() << "InterstitialPage does not support showing popups yet.";
diff --git a/content/browser/frame_host/interstitial_page_impl.h b/content/browser/frame_host/interstitial_page_impl.h
index 1dd685d..cd15e8d 100644
--- a/content/browser/frame_host/interstitial_page_impl.h
+++ b/content/browser/frame_host/interstitial_page_impl.h
@@ -122,8 +122,9 @@
   gfx::Rect GetRootWindowResizerRect() const override;
   void CreateNewWindow(
       SiteInstance* source_site_instance,
-      int route_id,
-      int main_frame_route_id,
+      int32_t route_id,
+      int32_t main_frame_route_id,
+      int32_t main_frame_widget_route_id,
       const ViewHostMsg_CreateWindow_Params& params,
       SessionStorageNamespace* session_storage_namespace) override;
   void CreateNewWidget(int32 render_process_id,
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index 7868121..06a15f8 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -214,9 +214,20 @@
       &RenderFrameHostImpl::OnSwappedOut, weak_ptr_factory_.GetWeakPtr())));
 
   if (widget_routing_id != MSG_ROUTING_NONE) {
-    render_widget_host_ = new RenderWidgetHostImpl(rwh_delegate, GetProcess(),
-                                                   widget_routing_id, hidden);
-    render_widget_host_->set_owned_by_render_frame_host(true);
+    // TODO(avi): Once RenderViewHostImpl has-a RenderWidgetHostImpl, the main
+    // render frame should probably start owning the RenderWidgetHostImpl,
+    // so this logic checking for an already existing RWHI should be removed.
+    // https://crbug.com/545684
+    render_widget_host_ =
+        RenderWidgetHostImpl::FromID(GetProcess()->GetID(), widget_routing_id);
+    if (!render_widget_host_) {
+      DCHECK(frame_tree_node->parent());
+      render_widget_host_ = new RenderWidgetHostImpl(rwh_delegate, GetProcess(),
+                                                     widget_routing_id, hidden);
+      render_widget_host_->set_owned_by_render_frame_host(true);
+    } else {
+      DCHECK(!render_widget_host_->owned_by_render_frame_host());
+    }
   }
 }
 
@@ -233,10 +244,6 @@
   if (IsRFHStateActive(rfh_state_))
     GetSiteInstance()->decrement_active_frame_count();
 
-  // Notify the FrameTree that this RFH is going away, allowing it to shut down
-  // the corresponding RenderViewHost if it is no longer needed.
-  frame_tree_->ReleaseRenderViewHostRef(render_view_host_);
-
   // NULL out the swapout timer; in crash dumps this member will be null only if
   // the dtor has run.
   swapout_event_monitor_timeout_.reset();
@@ -245,10 +252,15 @@
     iter.second.Run(false);
   }
 
-  if (render_widget_host_) {
+  if (render_widget_host_ &&
+      render_widget_host_->owned_by_render_frame_host()) {
     // Shutdown causes the RenderWidgetHost to delete itself.
     render_widget_host_->Shutdown();
   }
+
+  // Notify the FrameTree that this RFH is going away, allowing it to shut down
+  // the corresponding RenderViewHost if it is no longer needed.
+  frame_tree_->ReleaseRenderViewHostRef(render_view_host_);
 }
 
 int RenderFrameHostImpl::GetRoutingID() {
@@ -652,7 +664,10 @@
 
   // The RenderWidgetHost takes ownership of its view. It is tied to the
   // lifetime of the current RenderProcessHost for this RenderFrameHost.
-  if (render_widget_host_) {
+  // TODO(avi): This will need to change to initialize a
+  // RenderWidgetHostViewAura for the main frame once RenderViewHostImpl has-a
+  // RenderWidgetHostImpl. https://crbug.com/545684
+  if (parent_routing_id != MSG_ROUTING_NONE && render_widget_host_) {
     RenderWidgetHostView* rwhv =
         new RenderWidgetHostViewChildFrame(render_widget_host_);
     rwhv->Hide();
@@ -954,15 +969,7 @@
 }
 
 RenderWidgetHostImpl* RenderFrameHostImpl::GetRenderWidgetHost() {
-  if (render_widget_host_)
-    return render_widget_host_;
-
-  // TODO(kenrb): Remove this fallback and have the top-level frame have a
-  // widget host just like all the other frames.
-  if (!GetParent())
-    return render_view_host_->GetWidget();
-
-  return nullptr;
+  return render_widget_host_;
 }
 
 RenderWidgetHostView* RenderFrameHostImpl::GetView() {
@@ -973,7 +980,8 @@
     frame = static_cast<RenderFrameHostImpl*>(frame->GetParent());
   }
 
-  return render_view_host_->GetWidget()->GetView();
+  NOTREACHED();
+  return nullptr;
 }
 
 int RenderFrameHostImpl::GetEnabledBindings() {
diff --git a/content/browser/frame_host/render_frame_host_manager.cc b/content/browser/frame_host/render_frame_host_manager.cc
index 059e2b9..b38cc536 100644
--- a/content/browser/frame_host/render_frame_host_manager.cc
+++ b/content/browser/frame_host/render_frame_host_manager.cc
@@ -253,17 +253,16 @@
   SetRenderFrameHost(scoped_ptr<RenderFrameHostImpl>());
 }
 
-void RenderFrameHostManager::Init(BrowserContext* browser_context,
-                                  SiteInstance* site_instance,
+void RenderFrameHostManager::Init(SiteInstance* site_instance,
                                   int32 view_routing_id,
                                   int32 frame_routing_id,
                                   int32 widget_routing_id) {
-  // Create a RenderViewHost and RenderFrameHost, once we have an instance.  It
-  // is important to immediately give this SiteInstance to a RenderViewHost so
-  // that the SiteInstance is ref counted.
-  if (!site_instance)
-    site_instance = SiteInstance::Create(browser_context);
-
+  DCHECK(site_instance);
+  // TODO(avi): While RenderViewHostImpl is-a RenderWidgetHostImpl, this must
+  // hold true to avoid having two RenderWidgetHosts for the top-level frame.
+  // https://crbug.com/545684
+  DCHECK_IMPLIES(frame_tree_node_->IsMainFrame(),
+                 view_routing_id == widget_routing_id);
   int flags = delegate_->IsHidden() ? CREATE_RF_HIDDEN : 0;
   SetRenderFrameHost(CreateRenderFrameHost(site_instance, view_routing_id,
                                            frame_routing_id, widget_routing_id,
@@ -1711,6 +1710,20 @@
   if (frame_tree_node_->IsMainFrame()) {
     render_view_host = frame_tree->CreateRenderViewHost(
         site_instance, view_routing_id, frame_routing_id, swapped_out, hidden);
+    // TODO(avi): It's a bit bizarre that this logic lives here instead of in
+    // CreateRenderFrame(). It turns out that FrameTree::CreateRenderViewHost
+    // doesn't /always/ create a new RenderViewHost. It first tries to find an
+    // already existing one to reuse by a SiteInstance lookup. If it finds one,
+    // then the supplied routing IDs are completely ignored.
+    // CreateRenderFrame() could do this lookup too, but it seems redundant to
+    // do this lookup in two places. This is a good yak shave to clean up, or,
+    // if just ignored, should be an easy cleanup once RenderViewHostImpl has-a
+    // RenderWidgetHostImpl. https://crbug.com/545684
+    if (view_routing_id == MSG_ROUTING_NONE) {
+      widget_routing_id = render_view_host->GetRoutingID();
+    } else {
+      DCHECK_EQ(view_routing_id, render_view_host->GetRoutingID());
+    }
   } else {
     render_view_host = frame_tree->GetRenderViewHost(site_instance);
     CHECK(render_view_host);
diff --git a/content/browser/frame_host/render_frame_host_manager.h b/content/browser/frame_host/render_frame_host_manager.h
index 3cf8ea5..e490e88 100644
--- a/content/browser/frame_host/render_frame_host_manager.h
+++ b/content/browser/frame_host/render_frame_host_manager.h
@@ -201,8 +201,7 @@
   ~RenderFrameHostManager();
 
   // For arguments, see WebContentsImpl constructor.
-  void Init(BrowserContext* browser_context,
-            SiteInstance* site_instance,
+  void Init(SiteInstance* site_instance,
             int32 view_routing_id,
             int32 frame_routing_id,
             int32 widget_routing_id);
diff --git a/content/browser/renderer_host/render_message_filter.cc b/content/browser/renderer_host/render_message_filter.cc
index 91e81fa5..8861e37 100644
--- a/content/browser/renderer_host/render_message_filter.cc
+++ b/content/browser/renderer_host/render_message_filter.cc
@@ -235,9 +235,7 @@
 
 void RenderMessageFilter::OnCreateWindow(
     const ViewHostMsg_CreateWindow_Params& params,
-    int* route_id,
-    int* main_frame_route_id,
-    int64* cloned_session_storage_namespace_id) {
+    ViewHostMsg_CreateWindow_Reply* reply) {
   bool no_javascript_access;
 
   bool can_create_window =
@@ -259,9 +257,10 @@
           &no_javascript_access);
 
   if (!can_create_window) {
-    *route_id = MSG_ROUTING_NONE;
-    *main_frame_route_id = MSG_ROUTING_NONE;
-    *cloned_session_storage_namespace_id = 0;
+    reply->route_id = MSG_ROUTING_NONE;
+    reply->main_frame_route_id = MSG_ROUTING_NONE;
+    reply->main_frame_widget_route_id = MSG_ROUTING_NONE;
+    reply->cloned_session_storage_namespace_id = 0;
     return;
   }
 
@@ -269,14 +268,12 @@
   scoped_refptr<SessionStorageNamespaceImpl> cloned_namespace =
       new SessionStorageNamespaceImpl(dom_storage_context_.get(),
                                       params.session_storage_namespace_id);
-  *cloned_session_storage_namespace_id = cloned_namespace->id();
+  reply->cloned_session_storage_namespace_id = cloned_namespace->id();
 
-  render_widget_helper_->CreateNewWindow(params,
-                                         no_javascript_access,
-                                         PeerHandle(),
-                                         route_id,
-                                         main_frame_route_id,
-                                         cloned_namespace.get());
+  render_widget_helper_->CreateNewWindow(
+      params, no_javascript_access, PeerHandle(), &reply->route_id,
+      &reply->main_frame_route_id, &reply->main_frame_widget_route_id,
+      cloned_namespace.get());
 }
 
 void RenderMessageFilter::OnCreateWidget(int opener_id,
diff --git a/content/browser/renderer_host/render_message_filter.h b/content/browser/renderer_host/render_message_filter.h
index 4889e32..2fdf7f6 100644
--- a/content/browser/renderer_host/render_message_filter.h
+++ b/content/browser/renderer_host/render_message_filter.h
@@ -43,6 +43,7 @@
 class GURL;
 struct FontDescriptor;
 struct ViewHostMsg_CreateWindow_Params;
+struct ViewHostMsg_CreateWindow_Reply;
 
 namespace blink {
 struct WebScreenInfo;
@@ -118,9 +119,7 @@
 
   void OnGetProcessMemorySizes(size_t* private_bytes, size_t* shared_bytes);
   void OnCreateWindow(const ViewHostMsg_CreateWindow_Params& params,
-                      int* route_id,
-                      int* main_frame_route_id,
-                      int64* cloned_session_storage_namespace_id);
+                      ViewHostMsg_CreateWindow_Reply* reply);
   void OnCreateWidget(int opener_id,
                       blink::WebPopupType popup_type,
                       int* route_id);
diff --git a/content/browser/renderer_host/render_view_host_delegate.h b/content/browser/renderer_host/render_view_host_delegate.h
index 8805892..37bb5421 100644
--- a/content/browser/renderer_host/render_view_host_delegate.h
+++ b/content/browser/renderer_host/render_view_host_delegate.h
@@ -213,8 +213,9 @@
   // new window.
   virtual void CreateNewWindow(
       SiteInstance* source_site_instance,
-      int route_id,
-      int main_frame_route_id,
+      int32_t route_id,
+      int32_t main_frame_route_id,
+      int32_t main_frame_widget_route_id,
       const ViewHostMsg_CreateWindow_Params& params,
       SessionStorageNamespace* session_storage_namespace) {}
 
diff --git a/content/browser/renderer_host/render_view_host_impl.cc b/content/browser/renderer_host/render_view_host_impl.cc
index 328f40b..877062c6 100644
--- a/content/browser/renderer_host/render_view_host_impl.cc
+++ b/content/browser/renderer_host/render_view_host_impl.cc
@@ -315,6 +315,13 @@
   params.web_preferences = GetWebkitPreferences();
   params.view_id = GetRoutingID();
   params.main_frame_routing_id = main_frame_routing_id_;
+  if (main_frame_routing_id_ != MSG_ROUTING_NONE) {
+    RenderFrameHostImpl* main_rfh = RenderFrameHostImpl::FromID(
+        GetProcess()->GetID(), main_frame_routing_id_);
+    DCHECK(main_rfh);
+    RenderWidgetHostImpl* main_rwh = main_rfh->GetRenderWidgetHost();
+    params.main_frame_widget_routing_id = main_rwh->GetRoutingID();
+  }
   params.session_storage_namespace_id =
       delegate_->GetSessionStorageNamespace(instance_.get())->id();
   // Ensure the RenderView sets its opener correctly.
@@ -1009,8 +1016,9 @@
 }
 
 void RenderViewHostImpl::CreateNewWindow(
-    int route_id,
-    int main_frame_route_id,
+    int32_t route_id,
+    int32_t main_frame_route_id,
+    int32_t main_frame_widget_route_id,
     const ViewHostMsg_CreateWindow_Params& params,
     SessionStorageNamespace* session_storage_namespace) {
   ViewHostMsg_CreateWindow_Params validated_params(params);
@@ -1019,7 +1027,8 @@
   GetProcess()->FilterURL(true, &validated_params.opener_security_origin);
 
   delegate_->CreateNewWindow(GetSiteInstance(), route_id, main_frame_route_id,
-                             validated_params, session_storage_namespace);
+                             main_frame_widget_route_id, validated_params,
+                             session_storage_namespace);
 }
 
 void RenderViewHostImpl::CreateNewWidget(int32 route_id,
diff --git a/content/browser/renderer_host/render_view_host_impl.h b/content/browser/renderer_host/render_view_host_impl.h
index 5889857..83211f1b 100644
--- a/content/browser/renderer_host/render_view_host_impl.h
+++ b/content/browser/renderer_host/render_view_host_impl.h
@@ -291,11 +291,11 @@
   gfx::Rect GetRootWindowResizerRect() const override;
 
   // Creates a new RenderView with the given route id.
-  void CreateNewWindow(
-      int route_id,
-      int main_frame_route_id,
-      const ViewHostMsg_CreateWindow_Params& params,
-      SessionStorageNamespace* session_storage_namespace);
+  void CreateNewWindow(int32_t route_id,
+                       int32_t main_frame_route_id,
+                       int32_t main_frame_widget_route_id,
+                       const ViewHostMsg_CreateWindow_Params& params,
+                       SessionStorageNamespace* session_storage_namespace);
 
   // Creates a new RenderWidget with the given route id.  |popup_type| indicates
   // if this widget is a popup and what kind of popup it is (select, autofill).
diff --git a/content/browser/renderer_host/render_widget_helper.cc b/content/browser/renderer_host/render_widget_helper.cc
index 0aad52a6d..72b2d55 100644
--- a/content/browser/renderer_host/render_widget_helper.cc
+++ b/content/browser/renderer_host/render_widget_helper.cc
@@ -102,8 +102,9 @@
     const ViewHostMsg_CreateWindow_Params& params,
     bool no_javascript_access,
     base::ProcessHandle render_process,
-    int* route_id,
-    int* main_frame_route_id,
+    int32_t* route_id,
+    int32_t* main_frame_route_id,
+    int32_t* main_frame_widget_route_id,
     SessionStorageNamespace* session_storage_namespace) {
   if (params.opener_suppressed || no_javascript_access) {
     // If the opener is supppressed or script access is disallowed, we should
@@ -113,9 +114,14 @@
     // in OnCreateWindowOnUI, using the params provided here.
     *route_id = MSG_ROUTING_NONE;
     *main_frame_route_id = MSG_ROUTING_NONE;
+    *main_frame_widget_route_id = MSG_ROUTING_NONE;
   } else {
     *route_id = GetNextRoutingID();
     *main_frame_route_id = GetNextRoutingID();
+    // TODO(avi): When RenderViewHostImpl has-a RenderWidgetHostImpl, this
+    // should be updated to give the widget a distinct routing ID.
+    // https://crbug.com/545684
+    *main_frame_widget_route_id = *route_id;
     // Block resource requests until the view is created, since the HWND might
     // be needed if a response ends up creating a plugin.
     resource_dispatcher_host_->BlockRequestsForRoute(
@@ -126,21 +132,23 @@
 
   BrowserThread::PostTask(
       BrowserThread::UI, FROM_HERE,
-      base::Bind(&RenderWidgetHelper::OnCreateWindowOnUI,
-                 this, params, *route_id, *main_frame_route_id,
+      base::Bind(&RenderWidgetHelper::OnCreateWindowOnUI, this, params,
+                 *route_id, *main_frame_route_id, *main_frame_widget_route_id,
                  make_scoped_refptr(session_storage_namespace)));
 }
 
 void RenderWidgetHelper::OnCreateWindowOnUI(
     const ViewHostMsg_CreateWindow_Params& params,
-    int route_id,
-    int main_frame_route_id,
+    int32_t route_id,
+    int32_t main_frame_route_id,
+    int32_t main_frame_widget_route_id,
     SessionStorageNamespace* session_storage_namespace) {
   RenderViewHostImpl* host =
       RenderViewHostImpl::FromID(render_process_id_, params.opener_id);
   if (host)
-    host->CreateNewWindow(route_id, main_frame_route_id, params,
-        session_storage_namespace);
+    host->CreateNewWindow(route_id, main_frame_route_id,
+                          main_frame_widget_route_id, params,
+                          session_storage_namespace);
 }
 
 void RenderWidgetHelper::OnResumeRequestsForView(int route_id) {
diff --git a/content/browser/renderer_host/render_widget_helper.h b/content/browser/renderer_host/render_widget_helper.h
index 18576a41..881dd50 100644
--- a/content/browser/renderer_host/render_widget_helper.h
+++ b/content/browser/renderer_host/render_widget_helper.h
@@ -99,13 +99,13 @@
 
   // IO THREAD ONLY -----------------------------------------------------------
 
-  void CreateNewWindow(
-      const ViewHostMsg_CreateWindow_Params& params,
-      bool no_javascript_access,
-      base::ProcessHandle render_process,
-      int* route_id,
-      int* main_frame_route_id,
-      SessionStorageNamespace* session_storage_namespace);
+  void CreateNewWindow(const ViewHostMsg_CreateWindow_Params& params,
+                       bool no_javascript_access,
+                       base::ProcessHandle render_process,
+                       int32_t* route_id,
+                       int32_t* main_frame_route_id,
+                       int32_t* main_frame_widget_route_id,
+                       SessionStorageNamespace* session_storage_namespace);
   void CreateNewWidget(int opener_id,
                        blink::WebPopupType popup_type,
                        int* route_id);
@@ -119,11 +119,11 @@
   ~RenderWidgetHelper();
 
   // Called on the UI thread to finish creating a window.
-  void OnCreateWindowOnUI(
-      const ViewHostMsg_CreateWindow_Params& params,
-      int route_id,
-      int main_frame_route_id,
-      SessionStorageNamespace* session_storage_namespace);
+  void OnCreateWindowOnUI(const ViewHostMsg_CreateWindow_Params& params,
+                          int32_t route_id,
+                          int32_t main_frame_route_id,
+                          int32_t main_frame_widget_route_id,
+                          SessionStorageNamespace* session_storage_namespace);
 
   // Called on the IO thread after a window was created on the UI thread.
   void OnResumeRequestsForView(int route_id);
diff --git a/content/browser/renderer_host/render_widget_host_impl.h b/content/browser/renderer_host/render_widget_host_impl.h
index bd6bc76..240eec1 100644
--- a/content/browser/renderer_host/render_widget_host_impl.h
+++ b/content/browser/renderer_host/render_widget_host_impl.h
@@ -187,6 +187,9 @@
   void set_owned_by_render_frame_host(bool owned_by_rfh) {
     owned_by_render_frame_host_ = owned_by_rfh;
   }
+  bool owned_by_render_frame_host() const {
+    return owned_by_render_frame_host_;
+  }
 
   // Tells the renderer to die and then calls Destroy().
   virtual void Shutdown();
diff --git a/content/browser/security_exploit_browsertest.cc b/content/browser/security_exploit_browsertest.cc
index 2c5acc4..1358af2 100644
--- a/content/browser/security_exploit_browsertest.cc
+++ b/content/browser/security_exploit_browsertest.cc
@@ -196,7 +196,7 @@
 // process.
 IN_PROC_BROWSER_TEST_F(SecurityExploitBrowserTest,
                        AttemptDuplicateRenderViewHost) {
-  int duplicate_routing_id = MSG_ROUTING_NONE;
+  int32_t duplicate_routing_id = MSG_ROUTING_NONE;
   RenderViewHostImpl* pending_rvh =
       PrepareToDuplicateHosts(shell(), &duplicate_routing_id);
   EXPECT_NE(MSG_ROUTING_NONE, duplicate_routing_id);
@@ -213,10 +213,12 @@
   scoped_refptr<SessionStorageNamespaceImpl> session_storage(
       new SessionStorageNamespaceImpl(dom_storage_context));
   // Cause a deliberate collision in routing ids.
-  int main_frame_routing_id = duplicate_routing_id + 1;
-  pending_rvh->CreateNewWindow(duplicate_routing_id,
-                               main_frame_routing_id,
-                               params,
+  int32_t main_frame_routing_id = duplicate_routing_id + 1;
+  // TODO(avi): This should be made unique from the view routing ID once
+  // RenderViewHostImpl has-a RenderWidgetHostImpl. https://crbug.com/545684
+  int32_t main_frame_widget_routing_id = duplicate_routing_id;
+  pending_rvh->CreateNewWindow(duplicate_routing_id, main_frame_routing_id,
+                               main_frame_widget_routing_id, params,
                                session_storage.get());
 
   // If the above operation doesn't cause a crash, the test has succeeded!
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 6b1407b7..5dce2b39 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -1343,14 +1343,33 @@
   // it should be hidden.
   should_normally_be_visible_ = !params.initially_hidden;
 
-  // Either both routing ids can be given, or neither can be.
+  // The routing ids must either all be set or all be unset.
   DCHECK((params.routing_id == MSG_ROUTING_NONE &&
-              params.main_frame_routing_id == MSG_ROUTING_NONE) ||
+          params.main_frame_routing_id == MSG_ROUTING_NONE &&
+          params.main_frame_widget_routing_id == MSG_ROUTING_NONE) ||
          (params.routing_id != MSG_ROUTING_NONE &&
-              params.main_frame_routing_id != MSG_ROUTING_NONE));
-  GetRenderManager()->Init(params.browser_context, params.site_instance,
-                           params.routing_id, params.main_frame_routing_id,
-                           MSG_ROUTING_NONE);
+          params.main_frame_routing_id != MSG_ROUTING_NONE &&
+          params.main_frame_widget_routing_id != MSG_ROUTING_NONE));
+
+  scoped_refptr<SiteInstance> site_instance = params.site_instance;
+  if (!site_instance)
+    site_instance = SiteInstance::Create(params.browser_context);
+
+  // A main RenderFrameHost always has a RenderWidgetHost, since it is always a
+  // local root by definition.
+  // TODO(avi): Once RenderViewHostImpl has-a RenderWidgetHostImpl, it will no
+  // longer be necessary to eagerly grab a routing ID for the view.
+  // https://crbug.com/545684
+  int32_t view_routing_id = params.routing_id;
+  int32_t main_frame_widget_routing_id = params.main_frame_widget_routing_id;
+  if (main_frame_widget_routing_id == MSG_ROUTING_NONE) {
+    view_routing_id = main_frame_widget_routing_id =
+        site_instance->GetProcess()->GetNextRoutingID();
+  }
+
+  GetRenderManager()->Init(site_instance.get(), view_routing_id,
+                           params.main_frame_routing_id,
+                           main_frame_widget_routing_id);
   frame_tree_.root()->SetFrameName(params.main_frame_name);
 
   WebContentsViewDelegate* delegate =
@@ -1661,8 +1680,9 @@
 
 void WebContentsImpl::CreateNewWindow(
     SiteInstance* source_site_instance,
-    int route_id,
-    int main_frame_route_id,
+    int32_t route_id,
+    int32_t main_frame_route_id,
+    int32_t main_frame_widget_route_id,
     const ViewHostMsg_CreateWindow_Params& params,
     SessionStorageNamespace* session_storage_namespace) {
   // We usually create the new window in the same BrowsingInstance (group of
@@ -1721,14 +1741,10 @@
   CHECK(session_storage_namespace_impl->IsFromContext(dom_storage_context));
 
   if (delegate_ &&
-      !delegate_->ShouldCreateWebContents(this,
-                                          route_id,
-                                          main_frame_route_id,
-                                          params.window_container_type,
-                                          params.frame_name,
-                                          params.target_url,
-                                          partition_id,
-                                          session_storage_namespace)) {
+      !delegate_->ShouldCreateWebContents(
+          this, route_id, main_frame_route_id, main_frame_widget_route_id,
+          params.window_container_type, params.frame_name, params.target_url,
+          partition_id, session_storage_namespace)) {
     if (route_id != MSG_ROUTING_NONE &&
         !RenderViewHost::FromID(render_process_id, route_id)) {
       // If the embedder didn't create a WebContents for this route, we need to
@@ -1738,6 +1754,8 @@
     GetRenderViewHost()->GetProcess()->ResumeRequestsForView(route_id);
     GetRenderViewHost()->GetProcess()->ResumeRequestsForView(
         main_frame_route_id);
+    GetRenderViewHost()->GetProcess()->ResumeRequestsForView(
+        main_frame_widget_route_id);
     return;
   }
 
@@ -1746,6 +1764,7 @@
   CreateParams create_params(GetBrowserContext(), site_instance.get());
   create_params.routing_id = route_id;
   create_params.main_frame_routing_id = main_frame_route_id;
+  create_params.main_frame_widget_routing_id = main_frame_widget_route_id;
   create_params.main_frame_name = params.frame_name;
   create_params.opener_render_process_id = render_process_id;
   create_params.opener_render_frame_id = params.opener_render_frame_id;
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index 35da9b59..d9d9d20 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -491,8 +491,9 @@
   void LostMouseLock() override;
   void CreateNewWindow(
       SiteInstance* source_site_instance,
-      int route_id,
-      int main_frame_route_id,
+      int32_t route_id,
+      int32_t main_frame_route_id,
+      int32_t main_frame_widget_route_id,
       const ViewHostMsg_CreateWindow_Params& params,
       SessionStorageNamespace* session_storage_namespace) override;
   void CreateNewWidget(int32 render_process_id,
diff --git a/content/common/view_messages.h b/content/common/view_messages.h
index cec3302..748c676 100644
--- a/content/common/view_messages.h
+++ b/content/common/view_messages.h
@@ -341,6 +341,21 @@
   IPC_STRUCT_MEMBER(std::vector<base::string16>, additional_features)
 IPC_STRUCT_END()
 
+IPC_STRUCT_BEGIN(ViewHostMsg_CreateWindow_Reply)
+  // The ID of the view to be created. If the ID is MSG_ROUTING_NONE, then the
+  // view couldn't be created.
+  IPC_STRUCT_MEMBER(int32_t, route_id, MSG_ROUTING_NONE)
+
+  // The ID of the main frame hosted in the view.
+  IPC_STRUCT_MEMBER(int32_t, main_frame_route_id, MSG_ROUTING_NONE)
+
+  // The ID of the widget for the main frame.
+  IPC_STRUCT_MEMBER(int32_t, main_frame_widget_route_id, MSG_ROUTING_NONE)
+
+  // TODO(dcheng): No clue. This is kind of duplicated from ViewMsg_New_Params.
+  IPC_STRUCT_MEMBER(int64, cloned_session_storage_namespace_id)
+IPC_STRUCT_END()
+
 IPC_STRUCT_BEGIN(ViewHostMsg_CreateWorker_Params)
   // URL for the worker script.
   IPC_STRUCT_MEMBER(GURL, url)
@@ -480,17 +495,20 @@
   IPC_STRUCT_MEMBER(content::WebPreferences, web_preferences)
 
   // The ID of the view to be created.
-  IPC_STRUCT_MEMBER(int32, view_id)
+  IPC_STRUCT_MEMBER(int32_t, view_id, MSG_ROUTING_NONE)
 
   // The ID of the main frame hosted in the view.
-  IPC_STRUCT_MEMBER(int32, main_frame_routing_id)
+  IPC_STRUCT_MEMBER(int32_t, main_frame_routing_id, MSG_ROUTING_NONE)
+
+  // The ID of the widget for the main frame.
+  IPC_STRUCT_MEMBER(int32_t, main_frame_widget_routing_id, MSG_ROUTING_NONE)
 
   // The session storage namespace ID this view should use.
   IPC_STRUCT_MEMBER(int64, session_storage_namespace_id)
 
   // The route ID of the opener RenderFrame or RenderFrameProxy, if we need to
   // set one (MSG_ROUTING_NONE otherwise).
-  IPC_STRUCT_MEMBER(int, opener_frame_route_id)
+  IPC_STRUCT_MEMBER(int, opener_frame_route_id, MSG_ROUTING_NONE)
 
   // Whether the RenderView should initially be swapped out.
   IPC_STRUCT_MEMBER(bool, swapped_out)
@@ -503,7 +521,7 @@
 
   // The ID of the proxy object for the main frame in this view. It is only
   // used if |swapped_out| is true.
-  IPC_STRUCT_MEMBER(int32, proxy_routing_id)
+  IPC_STRUCT_MEMBER(int32_t, proxy_routing_id, MSG_ROUTING_NONE)
 
   // Whether the RenderView should initially be hidden.
   IPC_STRUCT_MEMBER(bool, hidden)
@@ -967,12 +985,11 @@
                     bool /* enabled */)
 
 // Sent by the renderer when it is creating a new window.  The browser creates a
-// tab for it.  If route_id is MSG_ROUTING_NONE, the view couldn't be created.
-IPC_SYNC_MESSAGE_CONTROL1_3(ViewHostMsg_CreateWindow,
+// tab for it.  If |reply.route_id| is MSG_ROUTING_NONE, the view couldn't be
+// created.
+IPC_SYNC_MESSAGE_CONTROL1_1(ViewHostMsg_CreateWindow,
                             ViewHostMsg_CreateWindow_Params,
-                            int /* route_id */,
-                            int /* main_frame_route_id */,
-                            int64 /* cloned_session_storage_namespace_id */)
+                            ViewHostMsg_CreateWindow_Reply)
 
 // Similar to ViewHostMsg_CreateWindow, except used for sub-widgets, like
 // <select> dropdowns.  This message is sent to the WebContentsImpl that
diff --git a/content/public/browser/web_contents.cc b/content/public/browser/web_contents.cc
index 887f242f..1b6d8a68 100644
--- a/content/public/browser/web_contents.cc
+++ b/content/public/browser/web_contents.cc
@@ -10,21 +10,10 @@
 namespace content {
 
 WebContents::CreateParams::CreateParams(BrowserContext* context)
-    : browser_context(context),
-      site_instance(nullptr),
-      opener_render_process_id(content::ChildProcessHost::kInvalidUniqueID),
-      opener_render_frame_id(MSG_ROUTING_NONE),
-      opener_suppressed(false),
-      created_with_opener(false),
-      routing_id(MSG_ROUTING_NONE),
-      main_frame_routing_id(MSG_ROUTING_NONE),
-      initially_hidden(false),
-      guest_delegate(nullptr),
-      context(nullptr),
-      renderer_initiated_creation(false) {}
+    : CreateParams(context, nullptr) {}
 
-WebContents::CreateParams::CreateParams(
-    BrowserContext* context, SiteInstance* site)
+WebContents::CreateParams::CreateParams(BrowserContext* context,
+                                        SiteInstance* site)
     : browser_context(context),
       site_instance(site),
       opener_render_process_id(content::ChildProcessHost::kInvalidUniqueID),
@@ -33,6 +22,7 @@
       created_with_opener(false),
       routing_id(MSG_ROUTING_NONE),
       main_frame_routing_id(MSG_ROUTING_NONE),
+      main_frame_widget_routing_id(MSG_ROUTING_NONE),
       initially_hidden(false),
       guest_delegate(nullptr),
       context(nullptr),
diff --git a/content/public/browser/web_contents.h b/content/public/browser/web_contents.h
index 795bec5..46918e5 100644
--- a/content/public/browser/web_contents.h
+++ b/content/public/browser/web_contents.h
@@ -113,11 +113,13 @@
     // (e.g., for blocked popups).
     bool created_with_opener;
 
-    // The routing ids of the RenderView and of the main RenderFrame. Either
-    // both must be provided, or both must be MSG_ROUTING_NONE to have the
-    // WebContents make the assignment.
-    int routing_id;
-    int main_frame_routing_id;
+    // The routing ids of the RenderView, main RenderFrame, and the widget for
+    // the main RenderFrame. Either all routing IDs must be provided or all must
+    // be MSG_ROUTING_NONE to have WebContents make the assignment. If provided,
+    // these routing IDs are associated with |site_instance->GetProcess()|.
+    int32_t routing_id;
+    int32_t main_frame_routing_id;
+    int32_t main_frame_widget_routing_id;
 
     // The name of the top-level frame of the new window. It is non-empty
     // when creating a named window (e.g. <a target="foo"> or
diff --git a/content/public/browser/web_contents_delegate.cc b/content/public/browser/web_contents_delegate.cc
index 3d18cee..b39436d 100644
--- a/content/public/browser/web_contents_delegate.cc
+++ b/content/public/browser/web_contents_delegate.cc
@@ -132,8 +132,9 @@
 
 bool WebContentsDelegate::ShouldCreateWebContents(
     WebContents* web_contents,
-    int route_id,
-    int main_frame_route_id,
+    int32_t route_id,
+    int32_t main_frame_route_id,
+    int32_t main_frame_widget_route_id,
     WindowContainerType window_container_type,
     const std::string& frame_name,
     const GURL& target_url,
diff --git a/content/public/browser/web_contents_delegate.h b/content/public/browser/web_contents_delegate.h
index eb5f480..40a49049a 100644
--- a/content/public/browser/web_contents_delegate.h
+++ b/content/public/browser/web_contents_delegate.h
@@ -289,8 +289,9 @@
   // be destroyed.
   virtual bool ShouldCreateWebContents(
       WebContents* web_contents,
-      int route_id,
-      int main_frame_route_id,
+      int32_t route_id,
+      int32_t main_frame_route_id,
+      int32_t main_frame_widget_route_id,
       WindowContainerType window_container_type,
       const std::string& frame_name,
       const GURL& target_url,
diff --git a/content/public/test/mock_render_thread.cc b/content/public/test/mock_render_thread.cc
index a3edec4..687d7b8 100644
--- a/content/public/test/mock_render_thread.cc
+++ b/content/public/test/mock_render_thread.cc
@@ -23,8 +23,8 @@
       opener_id_(0),
       new_window_routing_id_(0),
       new_window_main_frame_routing_id_(0),
-      new_frame_routing_id_(0) {
-}
+      new_window_main_frame_widget_routing_id_(0),
+      new_frame_routing_id_(0) {}
 
 MockRenderThread::~MockRenderThread() {
   while (!filters_.empty()) {
@@ -208,12 +208,11 @@
 // The View expects to be returned a valid route_id different from its own.
 void MockRenderThread::OnCreateWindow(
     const ViewHostMsg_CreateWindow_Params& params,
-    int* route_id,
-    int* main_frame_route_id,
-    int64* cloned_session_storage_namespace_id) {
-  *route_id = new_window_routing_id_;
-  *main_frame_route_id = new_window_main_frame_routing_id_;
-  *cloned_session_storage_namespace_id = 0;
+    ViewHostMsg_CreateWindow_Reply* reply) {
+  reply->route_id = new_window_routing_id_;
+  reply->main_frame_route_id = new_window_main_frame_routing_id_;
+  reply->main_frame_widget_route_id = new_window_main_frame_widget_routing_id_;
+  reply->cloned_session_storage_namespace_id = 0;
 }
 
 // The Frame expects to be returned a valid route_id different from its own.
diff --git a/content/public/test/mock_render_thread.h b/content/public/test/mock_render_thread.h
index 945dc673..17d44831 100644
--- a/content/public/test/mock_render_thread.h
+++ b/content/public/test/mock_render_thread.h
@@ -15,6 +15,7 @@
 #include "third_party/WebKit/public/web/WebPopupType.h"
 
 struct ViewHostMsg_CreateWindow_Params;
+struct ViewHostMsg_CreateWindow_Reply;
 
 namespace IPC {
 class MessageFilter;
@@ -93,6 +94,10 @@
     new_window_routing_id_ = id;
   }
 
+  void set_new_window_main_frame_widget_routing_id(int32_t id) {
+    new_window_main_frame_widget_routing_id_ = id;
+  }
+
   void set_new_frame_routing_id(int32 id) {
     new_frame_routing_id_ = id;
   }
@@ -117,14 +122,11 @@
                       blink::WebPopupType popup_type,
                       int* route_id);
 
-  // The View expects to be returned a valid route_id different from its own.
-  // We do not keep track of the newly created widget in MockRenderThread,
+  // The View expects to be returned a valid |reply.route_id| different from its
+  // own. We do not keep track of the newly created widget in MockRenderThread,
   // so it must be cleaned up on its own.
-  void OnCreateWindow(
-    const ViewHostMsg_CreateWindow_Params& params,
-    int* route_id,
-    int* main_frame_route_id,
-    int64* cloned_session_storage_namespace_id);
+  void OnCreateWindow(const ViewHostMsg_CreateWindow_Params& params,
+                      ViewHostMsg_CreateWindow_Reply* reply);
 
   // The Frame expects to be returned a valid route_id different from its own.
   void OnCreateChildFrame(int new_frame_routing_id,
@@ -149,6 +151,7 @@
   // Routing id that will be assigned to a CreateWindow Widget.
   int32 new_window_routing_id_;
   int32 new_window_main_frame_routing_id_;
+  int32_t new_window_main_frame_widget_routing_id_;
   int32 new_frame_routing_id_;
 
   // The last known good deserializer for sync messages.
diff --git a/content/public/test/render_view_test.cc b/content/public/test/render_view_test.cc
index 39ccf86f..7810e3a7 100644
--- a/content/public/test/render_view_test.cc
+++ b/content/public/test/render_view_test.cc
@@ -61,8 +61,13 @@
 
 const int32 kRouteId = 5;
 const int32 kMainFrameRouteId = 6;
+// TODO(avi): Widget routing IDs should be distinct from the view routing IDs,
+// once RenderWidgetHost is distilled from RenderViewHostImpl.
+// https://crbug.com/545684
+const int32_t kMainFrameWidgetRouteId = 5;
 const int32 kNewWindowRouteId = 7;
 const int32 kNewFrameRouteId = 10;
+const int32_t kNewFrameWidgetRouteId = 7;
 
 // Converts |ascii_character| into |key_code| and returns true on success.
 // Handles only the characters needed by tests.
@@ -205,6 +210,8 @@
     render_thread_.reset(new MockRenderThread());
   render_thread_->set_routing_id(kRouteId);
   render_thread_->set_new_window_routing_id(kNewWindowRouteId);
+  render_thread_->set_new_window_main_frame_widget_routing_id(
+      kNewFrameWidgetRouteId);
   render_thread_->set_new_frame_routing_id(kNewFrameRouteId);
 
 #if defined(OS_MACOSX)
@@ -242,6 +249,7 @@
   view_params.web_preferences = WebPreferences();
   view_params.view_id = kRouteId;
   view_params.main_frame_routing_id = kMainFrameRouteId;
+  view_params.main_frame_widget_routing_id = kMainFrameWidgetRouteId;
   view_params.session_storage_namespace_id = kInvalidSessionStorageNamespaceId;
   view_params.swapped_out = false;
   view_params.replicated_frame_state = FrameReplicationState();
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 8fff086bd9..76ae73c 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -570,14 +570,31 @@
 }
 
 // static
-RenderFrameImpl* RenderFrameImpl::CreateMainFrame(RenderViewImpl* render_view,
-                                                  int32 routing_id) {
+RenderFrameImpl* RenderFrameImpl::CreateMainFrame(
+    RenderViewImpl* render_view,
+    int32_t routing_id,
+    int32_t widget_routing_id,
+    bool hidden,
+    const blink::WebScreenInfo& screen_info,
+    CompositorDependencies* compositor_deps) {
+  // A main frame RenderFrame must have a RenderWidget.
+  DCHECK_NE(MSG_ROUTING_NONE, widget_routing_id);
+
   RenderFrameImpl* render_frame =
       RenderFrameImpl::Create(render_view, routing_id);
   WebLocalFrame* web_frame =
       WebLocalFrame::create(blink::WebTreeScopeType::Document, render_frame);
   render_frame->SetWebFrame(web_frame);
   render_view->webview()->setMainFrame(web_frame);
+  render_frame->render_widget_ = RenderWidget::CreateForFrame(
+      widget_routing_id, hidden, screen_info, compositor_deps, web_frame);
+  // TODO(kenrb): Observing shouldn't be necessary when we sort out
+  // WasShown and WasHidden, separating page-level visibility from
+  // frame-level visibility.
+  // TODO(avi): This DCHECK is to track cleanup for https://crbug.com/545684
+  DCHECK_EQ(render_view, render_frame->render_widget_)
+      << "Main frame is no longer reusing the RenderView as its widget! "
+      << "Does the RenderFrame need to register itself with the RenderWidget?";
   return render_frame;
 }
 
@@ -633,14 +650,20 @@
   web_frame->setOpener(opener);
 
   if (widget_params.routing_id != MSG_ROUTING_NONE) {
-    CHECK(SiteIsolationPolicy::AreCrossProcessFramesPossible());
+    CHECK_IMPLIES(web_frame->parent(),
+                  SiteIsolationPolicy::AreCrossProcessFramesPossible());
     render_frame->render_widget_ = RenderWidget::CreateForFrame(
         widget_params.routing_id, widget_params.hidden,
         render_frame->render_view_->screen_info(), compositor_deps, web_frame);
-    // TODO(kenrb): Observing shouldn't be necessary when we sort out
-    // WasShown and WasHidden, separating page-level visibility from
-    // frame-level visibility.
-    render_frame->render_widget_->RegisterRenderFrame(render_frame);
+    // TODO(avi): The main frame re-uses the RenderViewImpl as its widget, so
+    // avoid double-registering the frame as an observer.
+    // https://crbug.com/545684
+    if (web_frame->parent()) {
+      // TODO(kenrb): Observing shouldn't be necessary when we sort out
+      // WasShown and WasHidden, separating page-level visibility from
+      // frame-level visibility.
+      render_frame->render_widget_->RegisterRenderFrame(render_frame);
+    }
   }
 
   render_frame->Initialize();
@@ -3987,7 +4010,11 @@
   // TODO(kenrb): Need to figure out how to do this better. Should
   // VisibilityState remain a page-level concept or move to frames?
   // The semantics of 'Show' might have to change here.
-  if (render_widget_) {
+  // TODO(avi): This DCHECK is to track cleanup for https://crbug.com/545684
+  DCHECK_IMPLIES(IsMainFrame(), render_widget_.get() == render_view_.get())
+      << "The main render frame is no longer reusing the RenderView as its "
+      << "RenderWidget!";
+  if (render_widget_ && render_view_.get() != render_widget_.get()) {
     static_cast<blink::WebFrameWidget*>(render_widget_->webwidget())->
         setVisibilityState(blink::WebPageVisibilityStateVisible, false);
   }
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h
index b5bbaa5..945c61d 100644
--- a/content/renderer/render_frame_impl.h
+++ b/content/renderer/render_frame_impl.h
@@ -68,6 +68,7 @@
 struct WebCompositionUnderline;
 struct WebContextMenuData;
 struct WebCursorInfo;
+struct WebScreenInfo;
 }
 
 namespace gfx {
@@ -137,8 +138,13 @@
       NON_EXPORTED_BASE(public blink::WebPageSerializerClient) {
  public:
   // Creates a new RenderFrame as the main frame of |render_view|.
-  static RenderFrameImpl* CreateMainFrame(RenderViewImpl* render_view,
-                                          int32 routing_id);
+  static RenderFrameImpl* CreateMainFrame(
+      RenderViewImpl* render_view,
+      int32_t routing_id,
+      int32_t widget_routing_id,
+      bool hidden,
+      const blink::WebScreenInfo& screen_info,
+      CompositorDependencies* compositor_deps);
 
   // Creates a new RenderFrame with |routing_id|.  If |proxy_routing_id| is
   // MSG_ROUTING_NONE, it creates the Blink WebLocalFrame and inserts it into
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index 489aef6..584854c 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -644,6 +644,7 @@
       has_focus_(false),
       has_scrolled_focused_editable_node_into_rect_(false),
       main_render_frame_(nullptr),
+      frame_widget_(nullptr),
       speech_recognition_dispatcher_(NULL),
       mouse_lock_dispatcher_(NULL),
 #if defined(OS_ANDROID)
@@ -690,8 +691,9 @@
     stats_collection_observer_.reset(new StatsCollectionObserver(this));
 
   if (params.main_frame_routing_id != MSG_ROUTING_NONE) {
-    main_render_frame_ =
-        RenderFrameImpl::CreateMainFrame(this, params.main_frame_routing_id);
+    main_render_frame_ = RenderFrameImpl::CreateMainFrame(
+        this, params.main_frame_routing_id, params.main_frame_widget_routing_id,
+        params.hidden, screen_info(), compositor_deps_);
   }
 
   if (params.proxy_routing_id != MSG_ROUTING_NONE) {
@@ -822,6 +824,8 @@
 }
 
 RenderViewImpl::~RenderViewImpl() {
+  DCHECK(!frame_widget_);
+
   for (BitmapMap::iterator it = disambiguation_bitmaps_.begin();
        it != disambiguation_bitmaps_.end();
        ++it)
@@ -1575,14 +1579,9 @@
   for (size_t i = 0; i < features.additionalFeatures.size(); ++i)
     params.additional_features.push_back(features.additionalFeatures[i]);
 
-  int32 routing_id = MSG_ROUTING_NONE;
-  int32 main_frame_routing_id = MSG_ROUTING_NONE;
-  int64 cloned_session_storage_namespace_id = 0;
-
-  RenderThread::Get()->Send(
-      new ViewHostMsg_CreateWindow(params, &routing_id, &main_frame_routing_id,
-                                   &cloned_session_storage_namespace_id));
-  if (routing_id == MSG_ROUTING_NONE)
+  ViewHostMsg_CreateWindow_Reply reply;
+  RenderThread::Get()->Send(new ViewHostMsg_CreateWindow(params, &reply));
+  if (reply.route_id == MSG_ROUTING_NONE)
     return NULL;
 
   WebUserGestureIndicator::consumeUserGesture();
@@ -1610,14 +1609,14 @@
   view_params.window_was_created_with_opener = true;
   view_params.renderer_preferences = renderer_preferences_;
   view_params.web_preferences = webkit_preferences_;
-  view_params.view_id = routing_id;
-  view_params.main_frame_routing_id = main_frame_routing_id;
+  view_params.view_id = reply.route_id;
+  view_params.main_frame_routing_id = reply.main_frame_route_id;
+  view_params.main_frame_widget_routing_id = reply.main_frame_widget_route_id;
   view_params.session_storage_namespace_id =
-      cloned_session_storage_namespace_id;
+      reply.cloned_session_storage_namespace_id;
   view_params.swapped_out = false;
   // WebCore will take care of setting the correct name.
   view_params.replicated_frame_state = FrameReplicationState();
-  view_params.proxy_routing_id = MSG_ROUTING_NONE;
   view_params.hidden = (params.disposition == NEW_BACKGROUND_TAB);
   view_params.never_visible = never_visible;
   view_params.next_page_id = 1;
@@ -1696,6 +1695,12 @@
   }
 }
 
+void RenderViewImpl::AttachWebFrameWidget(blink::WebWidget* frame_widget) {
+  // The previous WebFrameWidget must already be detached by CloseForFrame().
+  DCHECK(!frame_widget_);
+  frame_widget_ = frame_widget;
+}
+
 void RenderViewImpl::SetZoomLevel(double zoom_level) {
   webview()->setZoomLevel(zoom_level);
   FOR_EACH_OBSERVER(RenderViewObserver, observers_, OnZoomLevelChanged());
@@ -2946,6 +2951,12 @@
 }
 #endif  // OS_MACOSX
 
+void RenderViewImpl::CloseForFrame() {
+  DCHECK(frame_widget_);
+  frame_widget_->close();
+  frame_widget_ = nullptr;
+}
+
 void RenderViewImpl::Close() {
   // We need to grab a pointer to the doomed WebView before we destroy it.
   WebView* doomed = webview();
diff --git a/content/renderer/render_view_impl.h b/content/renderer/render_view_impl.h
index 7f7dca4..591cd6b4 100644
--- a/content/renderer/render_view_impl.h
+++ b/content/renderer/render_view_impl.h
@@ -48,6 +48,7 @@
 #include "third_party/WebKit/public/web/WebConsoleMessage.h"
 #include "third_party/WebKit/public/web/WebDataSource.h"
 #include "third_party/WebKit/public/web/WebElement.h"
+#include "third_party/WebKit/public/web/WebFrameWidget.h"
 #include "third_party/WebKit/public/web/WebHistoryItem.h"
 #include "third_party/WebKit/public/web/WebIconURL.h"
 #include "third_party/WebKit/public/web/WebInputEvent.h"
@@ -239,6 +240,8 @@
   // FocusController.
   void SetFocus(bool enable);
 
+  void AttachWebFrameWidget(blink::WebWidget* frame_widget);
+
   // Plugin-related functions --------------------------------------------------
 
 #if defined(ENABLE_PLUGINS)
@@ -449,6 +452,7 @@
 
  protected:
   // RenderWidget overrides:
+  void CloseForFrame() override;
   void Close() override;
   void OnResize(const ViewMsg_Resize_Params& params) override;
   void DidInitiatePaint() override;
@@ -901,6 +905,10 @@
 
   RenderFrameImpl* main_render_frame_;
 
+  // Note: RenderViewImpl is pulling double duty: it's the RenderWidget for the
+  // "view", but it's also the RenderWidget for the main frame.
+  blink::WebWidget* frame_widget_;
+
   // The next group of objects all implement RenderViewObserver, so are deleted
   // along with the RenderView automatically.  This is why we just store
   // weak references.
diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc
index 2ece707..44b971f 100644
--- a/content/renderer/render_widget.cc
+++ b/content/renderer/render_widget.cc
@@ -50,6 +50,7 @@
 #include "content/renderer/render_frame_proxy.h"
 #include "content/renderer/render_process.h"
 #include "content/renderer/render_thread_impl.h"
+#include "content/renderer/render_view_impl.h"
 #include "content/renderer/renderer_blink_platform_impl.h"
 #include "content/renderer/resizing_mode_selector.h"
 #include "ipc/ipc_sync_message.h"
@@ -571,6 +572,14 @@
     CompositorDependencies* compositor_deps,
     blink::WebLocalFrame* frame) {
   CHECK_NE(routing_id, MSG_ROUTING_NONE);
+  // TODO(avi): Before RenderViewImpl has-a RenderWidget, the browser passes the
+  // same routing ID for both the view routing ID and the main frame widget
+  // routing ID. https://crbug.com/545684
+  RenderViewImpl* view = RenderViewImpl::FromRoutingID(routing_id);
+  if (view) {
+    view->AttachWebFrameWidget(RenderWidget::CreateWebFrameWidget(view, frame));
+    return view;
+  }
   scoped_refptr<RenderWidget> widget(
       new RenderWidget(compositor_deps, blink::WebPopupTypeNone, screen_info,
                        false, hidden, false));
@@ -590,6 +599,11 @@
 blink::WebWidget* RenderWidget::CreateWebFrameWidget(
     RenderWidget* render_widget,
     blink::WebLocalFrame* frame) {
+  if (!frame->parent()) {
+    // TODO(dcheng): The main frame widget currently has a special case.
+    // Eliminate this once WebView is no longer a WebWidget.
+    return blink::WebFrameWidget::create(render_widget, frame->view(), frame);
+  }
   return blink::WebFrameWidget::create(render_widget, frame);
 }
 
diff --git a/content/renderer/render_widget.h b/content/renderer/render_widget.h
index bb917e53..804ec98 100644
--- a/content/renderer/render_widget.h
+++ b/content/renderer/render_widget.h
@@ -122,7 +122,9 @@
                                       blink::WebLocalFrame* frame);
 
   // Closes a RenderWidget that was created by |CreateForFrame|.
-  void CloseForFrame();
+  // TODO(avi): De-virtualize this once RenderViewImpl has-a RenderWidget.
+  // https://crbug.com/545684
+  virtual void CloseForFrame();
 
   int32 routing_id() const { return routing_id_; }
   CompositorDependencies* compositor_deps() const { return compositor_deps_; }
diff --git a/content/test/test_web_contents.cc b/content/test/test_web_contents.cc
index b8d0092b..e69d806f 100644
--- a/content/test/test_web_contents.cc
+++ b/content/test/test_web_contents.cc
@@ -301,11 +301,11 @@
 
 void TestWebContents::CreateNewWindow(
     SiteInstance* source_site_instance,
-    int route_id,
-    int main_frame_route_id,
+    int32_t route_id,
+    int32_t main_frame_route_id,
+    int32_t main_frame_widget_route_id,
     const ViewHostMsg_CreateWindow_Params& params,
-    SessionStorageNamespace* session_storage_namespace) {
-}
+    SessionStorageNamespace* session_storage_namespace) {}
 
 void TestWebContents::CreateNewWidget(int32 render_process_id,
                                       int32 route_id,
diff --git a/content/test/test_web_contents.h b/content/test/test_web_contents.h
index 62910198..f46d0f9 100644
--- a/content/test/test_web_contents.h
+++ b/content/test/test_web_contents.h
@@ -117,8 +117,9 @@
   // WebContentsImpl overrides
   void CreateNewWindow(
       SiteInstance* source_site_instance,
-      int route_id,
-      int main_frame_route_id,
+      int32_t route_id,
+      int32_t main_frame_route_id,
+      int32_t main_frame_widget_route_id,
       const ViewHostMsg_CreateWindow_Params& params,
       SessionStorageNamespace* session_storage_namespace) override;
   void CreateNewWidget(int32 render_process_id,