diff options
author | nasko@chromium.org <nasko@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-05-09 02:05:12 +0000 |
---|---|---|
committer | nasko@chromium.org <nasko@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-05-09 02:05:12 +0000 |
commit | 50904457aacc2c53df5bc47465b9abd53fed1c3d (patch) | |
tree | 708cc6a8bd29937010cb6eac2469a9357e6501b7 /content | |
parent | 193b09392c0a87d682a4fff09399fd5e20acd7fb (diff) | |
download | chromium_src-50904457aacc2c53df5bc47465b9abd53fed1c3d.zip chromium_src-50904457aacc2c53df5bc47465b9abd53fed1c3d.tar.gz chromium_src-50904457aacc2c53df5bc47465b9abd53fed1c3d.tar.bz2 |
Create a frame tree in WebContents on the browser side.
This is a small delta from the original patch at https://codereview.chromium.org/14374002/.
BUG=235879
Review URL: https://chromiumcodereview.appspot.com/14580004
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@199087 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content')
-rw-r--r-- | content/browser/renderer_host/frame_tree_node.cc | 40 | ||||
-rw-r--r-- | content/browser/renderer_host/frame_tree_node.h | 61 | ||||
-rw-r--r-- | content/browser/renderer_host/render_view_host_impl.cc | 14 | ||||
-rw-r--r-- | content/browser/renderer_host/render_view_host_impl.h | 9 | ||||
-rw-r--r-- | content/browser/renderer_host/test_render_view_host.cc | 11 | ||||
-rw-r--r-- | content/browser/web_contents/web_contents_impl.cc | 69 | ||||
-rw-r--r-- | content/browser/web_contents/web_contents_impl.h | 16 | ||||
-rw-r--r-- | content/browser/web_contents/web_contents_impl_browsertest.cc | 39 | ||||
-rw-r--r-- | content/browser/web_contents/web_contents_impl_unittest.cc | 79 | ||||
-rw-r--r-- | content/common/view_messages.h | 13 | ||||
-rw-r--r-- | content/content_browser.gypi | 2 | ||||
-rw-r--r-- | content/renderer/render_view_impl.cc | 9 | ||||
-rw-r--r-- | content/test/data/frame_tree/2-4.html | 2 |
13 files changed, 355 insertions, 9 deletions
diff --git a/content/browser/renderer_host/frame_tree_node.cc b/content/browser/renderer_host/frame_tree_node.cc new file mode 100644 index 0000000..3486a2d --- /dev/null +++ b/content/browser/renderer_host/frame_tree_node.cc @@ -0,0 +1,40 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/renderer_host/frame_tree_node.h" + +#include <queue> + +#include "base/stl_util.h" + +namespace content { + +FrameTreeNode::FrameTreeNode(int64 frame_id, const std::string& name) + : frame_id_(frame_id), + frame_name_(name) { +} + +FrameTreeNode::~FrameTreeNode() { + STLDeleteContainerPointers(children_.begin(), children_.end()); +} + +void FrameTreeNode::AddChild(FrameTreeNode* child) { + children_.push_back(child); +} + +void FrameTreeNode::RemoveChild(int64 child_id) { + std::vector<FrameTreeNode*>::iterator iter; + + for (iter = children_.begin(); iter != children_.end(); ++iter) { + if ((*iter)->frame_id() == child_id) + break; + } + + if (iter != children_.end()) { + delete *iter; + children_.erase(iter); + } +} + +} // namespace content diff --git a/content/browser/renderer_host/frame_tree_node.h b/content/browser/renderer_host/frame_tree_node.h new file mode 100644 index 0000000..e35f409 --- /dev/null +++ b/content/browser/renderer_host/frame_tree_node.h @@ -0,0 +1,61 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_BROWSER_RENDERER_HOST_FRAME_TREE_NODE_H_ +#define CONTENT_BROWSER_RENDERER_HOST_FRAME_TREE_NODE_H_ + +#include <string> +#include <vector> + +#include "base/basictypes.h" +#include "content/common/content_export.h" + +namespace content { + +// Any page that contains iframes has a tree structure of the frames in the +// renderer process. We are mirroring this tree in the browser process. This +// class represents a node in this tree and is a wrapper for all objects that +// are frame-specific (as opposed to page-specific). +class CONTENT_EXPORT FrameTreeNode { + public: + FrameTreeNode(int64 frame_id, const std::string& name); + ~FrameTreeNode(); + + // This method takes ownership of the child pointer. + void AddChild(FrameTreeNode* child); + void RemoveChild(int64 child_id); + + int64 frame_id() const { + return frame_id_; + } + + const std::string& frame_name() const { + return frame_name_; + } + + size_t child_count() const { + return children_.size(); + } + + FrameTreeNode* child_at(size_t index) const { + return children_[index]; + } + + private: + // The unique identifier for the frame in the page. + int64 frame_id_; + + // The assigned name of the frame. This name can be empty, unlike the unique + // name generated internally in the DOM tree. + std::string frame_name_; + + // The immediate children of this specific frame. + std::vector<FrameTreeNode*> children_; + + DISALLOW_COPY_AND_ASSIGN(FrameTreeNode); +}; + +} // namespace content + +#endif // CONTENT_BROWSER_RENDERER_HOST_FRAME_TREE_NODE_H_ diff --git a/content/browser/renderer_host/render_view_host_impl.cc b/content/browser/renderer_host/render_view_host_impl.cc index d3363f5..322cf35 100644 --- a/content/browser/renderer_host/render_view_host_impl.cc +++ b/content/browser/renderer_host/render_view_host_impl.cc @@ -171,6 +171,7 @@ RenderViewHostImpl::RenderViewHostImpl( suspended_nav_params_(NULL), is_swapped_out_(swapped_out), is_subframe_(false), + main_frame_id_(-1), run_modal_reply_msg_(NULL), run_modal_opener_id_(MSG_ROUTING_NONE), is_waiting_for_beforeunload_ack_(false), @@ -1116,6 +1117,7 @@ void RenderViewHostImpl::OnRenderViewGone(int status, int exit_code) { // Reset state. ClearPowerSaveBlockers(); + main_frame_id_ = -1; // Our base class RenderWidgetHost needs to reset some stuff. RendererExited(render_view_termination_status_, exit_code); @@ -1186,6 +1188,18 @@ void RenderViewHostImpl::OnNavigate(const IPC::Message& msg) { if (is_waiting_for_unload_ack_) return; + // Cache the main frame id, so we can use it for creating the frame tree + // root node when needed. + if (PageTransitionIsMainFrame(validated_params.transition)) { + if (main_frame_id_ == -1) { + main_frame_id_ = validated_params.frame_id; + } else { + // TODO(nasko): We plan to remove the usage of frame_id in navigation + // and move to routing ids. This is in place to ensure that a + // renderer is not misbehaving and sending us incorrect data. + DCHECK_EQ(main_frame_id_, validated_params.frame_id); + } + } RenderProcessHost* process = GetProcess(); // If the --site-per-process flag is passed, then the renderer process is diff --git a/content/browser/renderer_host/render_view_host_impl.h b/content/browser/renderer_host/render_view_host_impl.h index a03ba43..516af7e7 100644 --- a/content/browser/renderer_host/render_view_host_impl.h +++ b/content/browser/renderer_host/render_view_host_impl.h @@ -395,6 +395,10 @@ class CONTENT_EXPORT RenderViewHostImpl is_subframe_ = is_subframe; } + int64 main_frame_id() const { + return main_frame_id_; + } + // Set the opener to null in the renderer process. void DisownOpener(); @@ -607,6 +611,11 @@ class CONTENT_EXPORT RenderViewHostImpl // different process from its parent page. bool is_subframe_; + // The frame id of the main (top level) frame. This value is set on the + // initial navigation of a RenderView and reset when the RenderView is + // terminated (in RenderViewGone). + int64 main_frame_id_; + // If we were asked to RunModal, then this will hold the reply_msg that we // must return to the renderer to unblock it. IPC::Message* run_modal_reply_msg_; diff --git a/content/browser/renderer_host/test_render_view_host.cc b/content/browser/renderer_host/test_render_view_host.cc index 6f5310f..a84f4dc 100644 --- a/content/browser/renderer_host/test_render_view_host.cc +++ b/content/browser/renderer_host/test_render_view_host.cc @@ -35,6 +35,9 @@ SessionStorageNamespaceImpl* CreateSessionStorageNamespace( return new SessionStorageNamespaceImpl( static_cast<DOMStorageContextImpl*>(dom_storage_context)); } + +const int64 kFrameId = 13UL; + } // namespace @@ -248,6 +251,8 @@ TestRenderViewHost::TestRenderViewHost( // deleted in the destructor below, because // TestRenderWidgetHostView::Destroy() doesn't |delete this|. SetView(new TestRenderWidgetHostView(this)); + + main_frame_id_ = kFrameId; } TestRenderViewHost::~TestRenderViewHost() { @@ -287,7 +292,7 @@ void TestRenderViewHost::SendNavigateWithTransition( void TestRenderViewHost::SendNavigateWithOriginalRequestURL( int page_id, const GURL& url, const GURL& original_request_url) { - OnDidStartProvisionalLoadForFrame(0, -1, true, url); + OnDidStartProvisionalLoadForFrame(kFrameId, -1, true, url); SendNavigateWithParameters(page_id, url, PAGE_TRANSITION_LINK, original_request_url, 200, 0); } @@ -301,7 +306,7 @@ void TestRenderViewHost::SendNavigateWithFile( void TestRenderViewHost::SendNavigateWithTransitionAndResponseCode( int page_id, const GURL& url, PageTransition transition, int response_code) { - OnDidStartProvisionalLoadForFrame(0, -1, true, url); + OnDidStartProvisionalLoadForFrame(kFrameId, -1, true, url); SendNavigateWithParameters(page_id, url, transition, url, response_code, 0); } @@ -311,7 +316,7 @@ void TestRenderViewHost::SendNavigateWithParameters( const base::FilePath* file_path_for_history_item) { ViewHostMsg_FrameNavigate_Params params; params.page_id = page_id; - params.frame_id = 0; + params.frame_id = kFrameId; params.url = url; params.referrer = Referrer(); params.transition = transition; diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc index 43ec8e5..66cd29e 100644 --- a/content/browser/web_contents/web_contents_impl.cc +++ b/content/browser/web_contents/web_contents_impl.cc @@ -692,6 +692,7 @@ bool WebContentsImpl::OnMessageReceived(RenderViewHost* render_view_host, IPC_MESSAGE_HANDLER(ViewHostMsg_OpenDateTimeDialog, OnOpenDateTimeDialog) #endif + IPC_MESSAGE_HANDLER(ViewHostMsg_FrameAttached, OnFrameAttached) IPC_MESSAGE_HANDLER(ViewHostMsg_FrameDetached, OnFrameDetached) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP_EX() @@ -2425,9 +2426,45 @@ void WebContentsImpl::OnUpdateFaviconURL( DidUpdateFaviconURL(page_id, candidates)); } -void WebContentsImpl::OnFrameDetached(int64 frame_id) { +FrameTreeNode* WebContentsImpl::FindFrameTreeNodeByID(int64 frame_id) { + FrameTreeNode* node = NULL; + std::queue<FrameTreeNode*> queue; + queue.push(frame_tree_root_.get()); + + while (!queue.empty()) { + node = queue.front(); + queue.pop(); + if (node->frame_id() == frame_id) + return node; + + for (size_t i = 0; i < node->child_count(); ++i) + queue.push(node->child_at(i)); + } + + return NULL; +} + +void WebContentsImpl::OnFrameAttached( + int64 parent_frame_id, + int64 frame_id, + const std::string& frame_name) { + FrameTreeNode* parent = FindFrameTreeNodeByID(parent_frame_id); + if (!parent) + return; + + FrameTreeNode* node = new FrameTreeNode(frame_id, frame_name); + parent->AddChild(node); +} + +void WebContentsImpl::OnFrameDetached(int64 parent_frame_id, int64 frame_id) { FOR_EACH_OBSERVER(WebContentsObserver, observers_, FrameDetached(message_source_, frame_id)); + + FrameTreeNode* parent = FindFrameTreeNodeByID(parent_frame_id); + if (!parent) + return; + + parent->RemoveChild(frame_id); } void WebContentsImpl::DidChangeVisibleSSLState() { @@ -2720,6 +2757,14 @@ void WebContentsImpl::RenderViewDeleted(RenderViewHost* rvh) { void WebContentsImpl::DidNavigate( RenderViewHost* rvh, const ViewHostMsg_FrameNavigate_Params& params) { + // If we don't have a frame tree root yet, this is the first navigation in + // using the current RenderViewHost, so we need to create it with the proper + // frame id. + if (!frame_tree_root_.get()) { + DCHECK(PageTransitionIsMainFrame(params.transition)); + frame_tree_root_.reset(new FrameTreeNode(params.frame_id, std::string())); + } + if (PageTransitionIsMainFrame(params.transition)) { // When overscroll navigation gesture is enabled, a screenshot of the page // in its current state is taken so that it can be used during the @@ -2733,6 +2778,10 @@ void WebContentsImpl::DidNavigate( render_manager_.DidNavigateMainFrame(rvh); } + // We expect to have a valid frame tree root node at all times when + // navigating. + DCHECK(frame_tree_root_.get()); + // Update the site of the SiteInstance if it doesn't have one yet, unless // this is for about:blank. In that case, the SiteInstance can still be // considered unused until a navigation to a real page. @@ -3306,6 +3355,24 @@ void WebContentsImpl::NotifySwappedFromRenderManager(RenderViewHost* rvh) { view_->SetOverscrollControllerEnabled(delegate_->CanOverscrollContent()); view_->RenderViewSwappedIn(render_manager_.current_host()); + + FrameTreeNode* root = NULL; + RenderViewHostImpl* new_rvh = static_cast<RenderViewHostImpl*>( + render_manager_.current_host()); + + // We are doing a cross-site navigation and swapping processes. Since frame + // ids are unique to a process, we need to recreate the frame tree with the + // proper main frame id. + // Note that it is possible for this method to be called before the new RVH + // has committed a navigation (if RenderViewHostManager short-circuits the + // CommitPending call because the current RVH is dead). In that case, we + // haven't heard a valid frame id to use to initialize the root node, so clear + // out the root node and the first subsequent navigation message will set it + // correctly. + if (new_rvh->main_frame_id() != -1) + root = new FrameTreeNode(new_rvh->main_frame_id(), std::string()); + + frame_tree_root_.reset(root); } int WebContentsImpl::CreateOpenerRenderViewsForRenderManager( diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h index 39cf2ae..a7a408b 100644 --- a/content/browser/web_contents/web_contents_impl.h +++ b/content/browser/web_contents/web_contents_impl.h @@ -14,6 +14,7 @@ #include "base/memory/scoped_ptr.h" #include "base/observer_list.h" #include "base/process.h" +#include "content/browser/renderer_host/frame_tree_node.h" #include "content/browser/renderer_host/render_view_host_delegate.h" #include "content/browser/renderer_host/render_widget_host_delegate.h" #include "content/browser/web_contents/navigation_controller_impl.h" @@ -184,6 +185,10 @@ class CONTENT_EXPORT WebContentsImpl void DragSourceMovedTo(int client_x, int client_y, int screen_x, int screen_y); + FrameTreeNode* GetFrameTreeRootForTesting() { + return frame_tree_root_.get(); + } + // WebContents ------------------------------------------------------ virtual WebContentsDelegate* GetDelegate() OVERRIDE; virtual void SetDelegate(WebContentsDelegate* delegate) OVERRIDE; @@ -488,6 +493,7 @@ class CONTENT_EXPORT WebContentsImpl FRIEND_TEST_ALL_PREFIXES(WebContentsImplTest, CrossSiteCantPreemptAfterUnload); FRIEND_TEST_ALL_PREFIXES(WebContentsImplTest, PendingContents); + FRIEND_TEST_ALL_PREFIXES(WebContentsImplTest, FrameTreeShape); FRIEND_TEST_ALL_PREFIXES(FormStructureBrowserTest, HTMLFiles); FRIEND_TEST_ALL_PREFIXES(NavigationControllerTest, HistoryNavigate); FRIEND_TEST_ALL_PREFIXES(RenderViewHostManagerTest, PageDoesBackAndReload); @@ -588,7 +594,10 @@ class CONTENT_EXPORT WebContentsImpl const std::vector<SkBitmap>& bitmaps); void OnUpdateFaviconURL(int32 page_id, const std::vector<FaviconURL>& candidates); - void OnFrameDetached(int64 frame_id); + void OnFrameAttached(int64 parent_frame_id, + int64 frame_id, + const std::string& frame_name); + void OnFrameDetached(int64 parent_frame_id, int64 frame_id); // Changes the IsLoading state and notifies delegate as needed // |details| is used to provide details on the load that just finished @@ -697,6 +706,8 @@ class CONTENT_EXPORT WebContentsImpl RenderViewHostImpl* GetRenderViewHostImpl(); + FrameTreeNode* FindFrameTreeNodeByID(int64 frame_id); + // Removes browser plugin embedder if there is one. void RemoveBrowserPluginEmbedder(); @@ -800,6 +811,9 @@ class CONTENT_EXPORT WebContentsImpl // True if this is a secure page which displayed insecure content. bool displayed_insecure_content_; + // The frame tree structure of the current page. + scoped_ptr<FrameTreeNode> frame_tree_root_; + // Data for misc internal state ---------------------------------------------- // When > 0, the WebContents is currently being captured (e.g., for diff --git a/content/browser/web_contents/web_contents_impl_browsertest.cc b/content/browser/web_contents/web_contents_impl_browsertest.cc index cfc5e08..66e0857 100644 --- a/content/browser/web_contents/web_contents_impl_browsertest.cc +++ b/content/browser/web_contents/web_contents_impl_browsertest.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "base/values.h" +#include "content/browser/renderer_host/render_view_host_impl.h" #include "content/browser/web_contents/web_contents_impl.h" #include "content/public/browser/load_notification_details.h" #include "content/public/browser/navigation_controller.h" @@ -121,4 +122,42 @@ IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest, load_observer.controller_); } +// Test that the browser receives the proper frame attach/detach messages from +// the renderer and builds proper frame tree. +IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest, FrameTree) { + ASSERT_TRUE(test_server()->Start()); + + NavigateToURL(shell(), test_server()->GetURL("files/frame_tree/top.html")); + + WebContentsImpl* wc = static_cast<WebContentsImpl*>(shell()->web_contents()); + RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>( + wc->GetRenderViewHost()); + FrameTreeNode* root = wc->GetFrameTreeRootForTesting(); + + // Check that the root node is properly created with the frame id of the + // initial navigation. + EXPECT_EQ(3UL, root->child_count()); + EXPECT_EQ(std::string(), root->frame_name()); + EXPECT_EQ(rvh->main_frame_id(), root->frame_id()); + + EXPECT_EQ(2UL, root->child_at(0)->child_count()); + EXPECT_STREQ("1-1-name", root->child_at(0)->frame_name().c_str()); + + // Verify the deepest node exists and has the right name. + EXPECT_EQ(2UL, root->child_at(2)->child_count()); + EXPECT_EQ(1UL, root->child_at(2)->child_at(1)->child_count()); + EXPECT_EQ(0UL, root->child_at(2)->child_at(1)->child_at(0)->child_count()); + EXPECT_STREQ("3-1-id", + root->child_at(2)->child_at(1)->child_at(0)->frame_name().c_str()); + + // Navigate to about:blank, which should leave only the root node of the frame + // tree in the browser process. + NavigateToURL(shell(), test_server()->GetURL("files/title1.html")); + + root = wc->GetFrameTreeRootForTesting(); + EXPECT_EQ(0UL, root->child_count()); + EXPECT_EQ(std::string(), root->frame_name()); + EXPECT_EQ(rvh->main_frame_id(), root->frame_id()); +} + } // namespace content diff --git a/content/browser/web_contents/web_contents_impl_unittest.cc b/content/browser/web_contents/web_contents_impl_unittest.cc index cb702a4..6d79088 100644 --- a/content/browser/web_contents/web_contents_impl_unittest.cc +++ b/content/browser/web_contents/web_contents_impl_unittest.cc @@ -4,6 +4,7 @@ #include "base/logging.h" #include "base/utf_string_conversions.h" +#include "content/browser/renderer_host/frame_tree_node.h" #include "content/browser/renderer_host/render_view_host_impl.h" #include "content/browser/renderer_host/test_render_view_host.h" #include "content/browser/site_instance_impl.h" @@ -2050,4 +2051,82 @@ TEST_F(WebContentsImplTest, PendingContents) { EXPECT_EQ(NULL, contents()->GetCreatedWindow(route_id)); } +// This test asserts the shape of the frame tree is correct, based on incoming +// frame attached/detached messages. +TEST_F(WebContentsImplTest, FrameTreeShape) { + std::string no_children_node("no children node"); + std::string deep_subtree("node with deep subtree"); + + // The initial navigation will create a frame_tree_root_ node with the top + // level frame id. Simulate that by just creating it here. + contents()->frame_tree_root_.reset( + new FrameTreeNode(5, std::string("top-level"))); + + // Let's send a series of messages for frame attached and build the + // frame tree. + contents()->OnFrameAttached(5, 14, std::string()); + contents()->OnFrameAttached(5, 15, std::string()); + contents()->OnFrameAttached(5, 16, std::string()); + + contents()->OnFrameAttached(14, 244, std::string()); + contents()->OnFrameAttached(14, 245, std::string()); + + contents()->OnFrameAttached(15, 255, no_children_node); + + contents()->OnFrameAttached(16, 264, std::string()); + contents()->OnFrameAttached(16, 265, std::string()); + contents()->OnFrameAttached(16, 266, std::string()); + contents()->OnFrameAttached(16, 267, deep_subtree); + contents()->OnFrameAttached(16, 268, std::string()); + + contents()->OnFrameAttached(267, 365, std::string()); + contents()->OnFrameAttached(365, 455, std::string()); + contents()->OnFrameAttached(455, 555, std::string()); + contents()->OnFrameAttached(555, 655, std::string()); + + // Now, verify the tree structure is as expected. + FrameTreeNode* root = contents()->frame_tree_root_.get(); + EXPECT_EQ(5, root->frame_id()); + EXPECT_EQ(3UL, root->child_count()); + + EXPECT_EQ(2UL, root->child_at(0)->child_count()); + EXPECT_EQ(0UL, root->child_at(0)->child_at(0)->child_count()); + EXPECT_EQ(0UL, root->child_at(0)->child_at(1)->child_count()); + + EXPECT_EQ(1UL, root->child_at(1)->child_count()); + EXPECT_EQ(0UL, root->child_at(1)->child_at(0)->child_count()); + EXPECT_STREQ(no_children_node.c_str(), + root->child_at(1)->child_at(0)->frame_name().c_str()); + + EXPECT_EQ(5UL, root->child_at(2)->child_count()); + EXPECT_EQ(0UL, root->child_at(2)->child_at(0)->child_count()); + EXPECT_EQ(0UL, root->child_at(2)->child_at(1)->child_count()); + EXPECT_EQ(0UL, root->child_at(2)->child_at(2)->child_count()); + EXPECT_EQ(1UL, root->child_at(2)->child_at(3)->child_count()); + EXPECT_STREQ(deep_subtree.c_str(), + root->child_at(2)->child_at(3)->frame_name().c_str()); + EXPECT_EQ(0UL, root->child_at(2)->child_at(4)->child_count()); + + FrameTreeNode* deep_tree = root->child_at(2)->child_at(3)->child_at(0); + EXPECT_EQ(365, deep_tree->frame_id()); + EXPECT_EQ(1UL, deep_tree->child_count()); + EXPECT_EQ(455, deep_tree->child_at(0)->frame_id()); + EXPECT_EQ(1UL, deep_tree->child_at(0)->child_count()); + EXPECT_EQ(555, deep_tree->child_at(0)->child_at(0)->frame_id()); + EXPECT_EQ(1UL, deep_tree->child_at(0)->child_at(0)->child_count()); + EXPECT_EQ(655, deep_tree->child_at(0)->child_at(0)->child_at(0)->frame_id()); + EXPECT_EQ(0UL, + deep_tree->child_at(0)->child_at(0)->child_at(0)->child_count()); + + // Test removing of nodes. + contents()->OnFrameDetached(555, 655); + EXPECT_EQ(0UL, deep_tree->child_at(0)->child_at(0)->child_count()); + + contents()->OnFrameDetached(16, 265); + EXPECT_EQ(4UL, root->child_at(2)->child_count()); + + contents()->OnFrameDetached(5, 15); + EXPECT_EQ(2UL, root->child_count()); +} + } // namespace content diff --git a/content/common/view_messages.h b/content/common/view_messages.h index 2f3756e..0a5cc0b 100644 --- a/content/common/view_messages.h +++ b/content/common/view_messages.h @@ -2172,8 +2172,17 @@ IPC_MESSAGE_CONTROL3(ViewHostMsg_DidLose3DContext, content::ThreeDAPIType /* context_type */, int /* arb_robustness_status_code */) -// Notifies the browser that the frame with the given id was detached. -IPC_MESSAGE_ROUTED1(ViewHostMsg_FrameDetached, +// This message is sent when a frame is added to the DOM. +IPC_MESSAGE_ROUTED3(ViewHostMsg_FrameAttached, + int64 /* parent_frame_id*/, + int64 /* frame_id */, + std::string /* frame_name */) + +// Notifies the browser that the frame with the given id was detached. The +// |parent_frame_id| is -1 for the top level frame, otherwise the id of the +// immediate parent of the detached frame. +IPC_MESSAGE_ROUTED2(ViewHostMsg_FrameDetached, + int64 /* parent_frame_id */, int64 /* frame_id */) // Notifies the browser that document has parsed the body. This is used by the diff --git a/content/content_browser.gypi b/content/content_browser.gypi index 37b5aee..fc2071b 100644 --- a/content/content_browser.gypi +++ b/content/content_browser.gypi @@ -682,6 +682,8 @@ 'browser/renderer_host/dip_util.h', 'browser/renderer_host/file_utilities_message_filter.cc', 'browser/renderer_host/file_utilities_message_filter.h', + 'browser/renderer_host/frame_tree_node.cc', + 'browser/renderer_host/frame_tree_node.h', 'browser/renderer_host/gamepad_browser_message_filter.cc', 'browser/renderer_host/gamepad_browser_message_filter.h', 'browser/renderer_host/gesture_event_filter.cc', diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc index 56ff217..a24e962 100644 --- a/content/renderer/render_view_impl.cc +++ b/content/renderer/render_view_impl.cc @@ -2776,6 +2776,8 @@ WebCookieJar* RenderViewImpl::cookieJar(WebFrame* frame) { } void RenderViewImpl::didCreateFrame(WebFrame* parent, WebFrame* child) { + Send(new ViewHostMsg_FrameAttached(routing_id_, parent->identifier(), + child->identifier(), UTF16ToUTF8(child->assignedName()))); } void RenderViewImpl::didDisownOpener(WebKit::WebFrame* frame) { @@ -2791,7 +2793,12 @@ void RenderViewImpl::didDisownOpener(WebKit::WebFrame* frame) { } void RenderViewImpl::frameDetached(WebFrame* frame) { - Send(new ViewHostMsg_FrameDetached(routing_id_, frame->identifier())); + int64 parent_frame_id = -1; + if (frame->parent()) + parent_frame_id = frame->parent()->identifier(); + + Send(new ViewHostMsg_FrameDetached(routing_id_, parent_frame_id, + frame->identifier())); FOR_EACH_OBSERVER(RenderViewObserver, observers_, FrameDetached(frame)); } diff --git a/content/test/data/frame_tree/2-4.html b/content/test/data/frame_tree/2-4.html index 3bdea4b..3767f39 100644 --- a/content/test/data/frame_tree/2-4.html +++ b/content/test/data/frame_tree/2-4.html @@ -6,7 +6,7 @@ Frame 2-4. <br> -<iframe src="3-1.html"></iframe> +<iframe id='3-1-id' src="3-1.html"></iframe> </body> </html> |