| Index: content/renderer/render_view_impl.cc
 | 
| diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
 | 
| index daf58486c6501a8c3c1c1b2194342698377f3a49..9db069b0cf2028268cccea3e8196a58cf129bb55 100644
 | 
| --- a/content/renderer/render_view_impl.cc
 | 
| +++ b/content/renderer/render_view_impl.cc
 | 
| @@ -13,6 +13,7 @@
 | 
|  #include "base/bind_helpers.h"
 | 
|  #include "base/command_line.h"
 | 
|  #include "base/compiler_specific.h"
 | 
| +#include "base/json/json_reader.h"
 | 
|  #include "base/json/json_writer.h"
 | 
|  #include "base/lazy_instance.h"
 | 
|  #include "base/message_loop_proxy.h"
 | 
| @@ -345,6 +346,13 @@ static RenderViewImpl* FromRoutingID(int32 routing_id) {
 | 
|        ChildThread::current()->ResolveRoute(routing_id));
 | 
|  }
 | 
|  
 | 
| +static WebKit::WebFrame* FindFrameByID(WebKit::WebFrame* root, int frame_id) {
 | 
| +  for (WebFrame* frame = root; frame; frame = frame->traverseNext(false))
 | 
| +    if (frame->identifier() == frame_id)
 | 
| +      return frame;
 | 
| +  return NULL;
 | 
| +}
 | 
| +
 | 
|  static void GetRedirectChain(WebDataSource* ds, std::vector<GURL>* result) {
 | 
|    WebVector<WebURL> urls;
 | 
|    ds->redirectChain(urls);
 | 
| @@ -449,6 +457,35 @@ static bool IsNonLocalTopLevelNavigation(const GURL& url,
 | 
|    return false;
 | 
|  }
 | 
|  
 | 
| +// The frame tree for a renderer is serialized to JSON, so it can be sent to
 | 
| +// the browser process. Each node in the tree is a DictionaryValue with three
 | 
| +// properties:
 | 
| +// * id - the frame identifier in this renderer
 | 
| +// * name - the name of the frame, if one has been assigned
 | 
| +// * subtree - a list of DictionaryValue objects for each frame that is
 | 
| +//     direct child of the current frame. This property can be omitted if
 | 
| +//     there are no direct child frames, so less data is transferred.
 | 
| +static void ConstructFrameTree(WebKit::WebFrame* frame,
 | 
| +                      WebKit::WebFrame* exclude_subtree,
 | 
| +                      base::DictionaryValue* dict) {
 | 
| +  dict->SetString("name", UTF16ToUTF8(frame->assignedName()).c_str());
 | 
| +  dict->SetInteger("id", frame->identifier());
 | 
| +
 | 
| +  WebFrame* child = frame->firstChild();
 | 
| +  ListValue* children = new ListValue();
 | 
| +  for (; child; child = child->nextSibling()) {
 | 
| +    if (child == exclude_subtree)
 | 
| +      continue;
 | 
| +
 | 
| +    base::DictionaryValue* d = new base::DictionaryValue();
 | 
| +    ConstructFrameTree(child, exclude_subtree, d);
 | 
| +    children->Append(d);
 | 
| +  }
 | 
| +  if (children->GetSize() > 0) {
 | 
| +    dict->Set("subtree", children);
 | 
| +  }
 | 
| +}
 | 
| +
 | 
|  ///////////////////////////////////////////////////////////////////////////////
 | 
|  
 | 
|  struct RenderViewImpl::PendingFileChooser {
 | 
| @@ -558,6 +595,10 @@ RenderViewImpl::RenderViewImpl(
 | 
|        guest_to_embedder_channel_(guest_to_embedder_channel),
 | 
|        guest_pp_instance_(0),
 | 
|        guest_uninitialized_context_(NULL),
 | 
| +      updating_frame_tree_(false),
 | 
| +      pending_frame_tree_update_(false),
 | 
| +      remote_process_id_(0),
 | 
| +      remote_routing_id_(0),
 | 
|        ALLOW_THIS_IN_INITIALIZER_LIST(pepper_delegate_(this)) {
 | 
|    set_throttle_input_events(renderer_prefs.throttle_input_events);
 | 
|    routing_id_ = routing_id;
 | 
| @@ -652,7 +693,6 @@ RenderViewImpl::RenderViewImpl(
 | 
|  
 | 
|    // If we have an opener_id but we weren't created by a renderer, then
 | 
|    // it's the browser asking us to set our opener to another RenderView.
 | 
| -  // TODO(creis): This doesn't yet handle openers that are subframes.
 | 
|    if (opener_id != MSG_ROUTING_NONE && !is_renderer_created) {
 | 
|      RenderViewImpl* opener_view = FromRoutingID(opener_id);
 | 
|      if (opener_view)
 | 
| @@ -662,7 +702,7 @@ RenderViewImpl::RenderViewImpl(
 | 
|    // If we are initially swapped out, navigate to kSwappedOutURL.
 | 
|    // This ensures we are in a unique origin that others cannot script.
 | 
|    if (is_swapped_out_)
 | 
| -    NavigateToSwappedOutURL();
 | 
| +    NavigateToSwappedOutURL(webview()->mainFrame(), NULL);
 | 
|  }
 | 
|  
 | 
|  RenderViewImpl::~RenderViewImpl() {
 | 
| @@ -965,6 +1005,7 @@ bool RenderViewImpl::OnMessageReceived(const IPC::Message& message) {
 | 
|      IPC_MESSAGE_HANDLER(ViewMsg_EnableViewSourceMode, OnEnableViewSourceMode)
 | 
|      IPC_MESSAGE_HANDLER(JavaBridgeMsg_Init, OnJavaBridgeInit)
 | 
|      IPC_MESSAGE_HANDLER(ViewMsg_SetAccessibilityMode, OnSetAccessibilityMode)
 | 
| +    IPC_MESSAGE_HANDLER(ViewMsg_FrameTree, OnFrameTree)
 | 
|  
 | 
|      // Have the super handle all other messages.
 | 
|      IPC_MESSAGE_UNHANDLED(handled = RenderWidget::OnMessageReceived(message))
 | 
| @@ -1868,6 +1909,11 @@ void RenderViewImpl::didStopLoading() {
 | 
|    if (load_progress_tracker_ != NULL)
 | 
|      load_progress_tracker_->DidStopLoading();
 | 
|  
 | 
| +  if (pending_frame_tree_update_) {
 | 
| +    pending_frame_tree_update_ = false;
 | 
| +    SendUpdatedFrameTree(webview()->mainFrame(), false);
 | 
| +  }
 | 
| +
 | 
|    FOR_EACH_OBSERVER(RenderViewObserver, observers_, DidStopLoading());
 | 
|  }
 | 
|  
 | 
| @@ -2452,7 +2498,24 @@ WebCookieJar* RenderViewImpl::cookieJar(WebFrame* frame) {
 | 
|    return &cookie_jar_;
 | 
|  }
 | 
|  
 | 
| +void RenderViewImpl::didCreateFrame(WebFrame* parent, WebFrame* child) {
 | 
| +  if (is_loading_) {
 | 
| +    pending_frame_tree_update_ = true;
 | 
| +    return;
 | 
| +  }
 | 
| +  if (!updating_frame_tree_) {
 | 
| +    SendUpdatedFrameTree(child, false);
 | 
| +  }
 | 
| +}
 | 
| +
 | 
|  void RenderViewImpl::frameDetached(WebFrame* frame) {
 | 
| +  if (is_loading_) {
 | 
| +    pending_frame_tree_update_ = true;
 | 
| +    return;
 | 
| +  }
 | 
| +  if (!updating_frame_tree_) {
 | 
| +    SendUpdatedFrameTree(frame, true);
 | 
| +  }
 | 
|    FOR_EACH_OBSERVER(RenderViewObserver, observers_, FrameDetached(frame));
 | 
|  }
 | 
|  
 | 
| @@ -3605,6 +3668,24 @@ WebGraphicsContext3D* RenderViewImpl::CreateGraphicsContext3D(
 | 
|    }
 | 
|  }
 | 
|  
 | 
| +// The browser process needs to know the shape of the tree, as well as the names
 | 
| +// and ids of all frames. This allows it to properly route JavaScript messages
 | 
| +// across processes and frames.
 | 
| +// This function sends a those updates to the browser and updates the RVH
 | 
| +// corresponding to this object. It must be called on any events that modify
 | 
| +// the tree structure or the names of any frames.
 | 
| +void RenderViewImpl::SendUpdatedFrameTree(
 | 
| +    WebKit::WebFrame* frame, bool exclude_subtree) {
 | 
| +  std::string json;
 | 
| +  WebFrame* f = frame->top();
 | 
| +  base::DictionaryValue tree;
 | 
| +
 | 
| +  ConstructFrameTree(f, exclude_subtree ? frame : NULL, &tree);
 | 
| +  base::JSONWriter::Write(&tree, &json);
 | 
| +
 | 
| +  Send(new ViewHostMsg_FrameTree(routing_id_, json));
 | 
| +}
 | 
| +
 | 
|  void RenderViewImpl::EnsureMediaStreamImpl() {
 | 
|    if (!RenderThreadImpl::current())  // Will be NULL during unit tests.
 | 
|      return;
 | 
| @@ -3820,7 +3901,8 @@ void RenderViewImpl::dispatchIntent(
 | 
|  }
 | 
|  
 | 
|  bool RenderViewImpl::willCheckAndDispatchMessageEvent(
 | 
| -    WebKit::WebFrame* source,
 | 
| +    WebKit::WebFrame* sourceFrame,
 | 
| +    WebKit::WebFrame* targetFrame,
 | 
|      WebKit::WebSecurityOrigin target_origin,
 | 
|      WebKit::WebDOMMessageEvent event) {
 | 
|    if (!is_swapped_out_)
 | 
| @@ -3835,11 +3917,24 @@ bool RenderViewImpl::willCheckAndDispatchMessageEvent(
 | 
|    // Include the routing ID for the source frame, which the browser process
 | 
|    // will translate into the routing ID for the equivalent frame in the target
 | 
|    // process.
 | 
| -  // TODO(creis): Support source subframes.
 | 
|    params.source_routing_id = MSG_ROUTING_NONE;
 | 
| -  RenderViewImpl* source_view = FromWebView(source->view());
 | 
| +  RenderViewImpl* source_view = FromWebView(sourceFrame->view());
 | 
|    if (source_view)
 | 
|      params.source_routing_id = source_view->routing_id();
 | 
| +  params.source_frame_id = sourceFrame->identifier();
 | 
| +
 | 
| +  // Include the process, route, and frame IDs of the target frame. This allows
 | 
| +  // the browser to detect races between this message being sent and the target
 | 
| +  // frame no longer being valid.
 | 
| +  params.remote_process_id = remote_process_id_;
 | 
| +  params.remote_routing_id = remote_routing_id_;
 | 
| +
 | 
| +  std::map<int,int>::iterator it = frames_map_.find(targetFrame->identifier());
 | 
| +  if (it != frames_map_.end()) {
 | 
| +    params.remote_frame_id = it->second;
 | 
| +  } else {
 | 
| +    params.remote_frame_id = 0;
 | 
| +  }
 | 
|  
 | 
|    Send(new ViewHostMsg_RouteMessageEvent(routing_id_, params));
 | 
|    return true;
 | 
| @@ -4569,16 +4664,19 @@ void RenderViewImpl::OnScriptEvalRequest(const string16& frame_xpath,
 | 
|  
 | 
|  void RenderViewImpl::OnPostMessageEvent(
 | 
|      const ViewMsg_PostMessage_Params& params) {
 | 
| -  // TODO(creis): Support sending to subframes.
 | 
| -  WebFrame* frame = webview()->mainFrame();
 | 
| +  // Find the frame, which is a target of this message. The source tags the
 | 
| +  // message with |remote_frame_id|, so use it to locate the frame.
 | 
| +  WebFrame* frame = FindFrameByID(webview()->mainFrame(),
 | 
| +                                  params.remote_frame_id);
 | 
| +  if (!frame)
 | 
| +    return;
 | 
|  
 | 
|    // Find the source frame if it exists.
 | 
| -  // TODO(creis): Support source subframes.
 | 
|    WebFrame* source_frame = NULL;
 | 
|    if (params.source_routing_id != MSG_ROUTING_NONE) {
 | 
|      RenderViewImpl* source_view = FromRoutingID(params.source_routing_id);
 | 
|      if (source_view)
 | 
| -      source_frame = source_view->webview()->mainFrame();
 | 
| +      source_frame = source_view->GetFrameByRemoteID(params.source_frame_id);
 | 
|    }
 | 
|  
 | 
|    // Create an event with the message.  The final parameter to initMessageEvent
 | 
| @@ -4927,7 +5025,7 @@ void RenderViewImpl::OnSwapOut(const ViewMsg_SwapOut_Params& params) {
 | 
|      // run a second time, thanks to a check in FrameLoader::stopLoading.
 | 
|      // TODO(creis): Need to add a better way to do this that avoids running the
 | 
|      // beforeunload handler. For now, we just run it a second time silently.
 | 
| -    NavigateToSwappedOutURL();
 | 
| +    NavigateToSwappedOutURL(webview()->mainFrame(), NULL);
 | 
|  
 | 
|      // Let WebKit know that this view is hidden so it can drop resources and
 | 
|      // stop compositing.
 | 
| @@ -4938,14 +5036,46 @@ void RenderViewImpl::OnSwapOut(const ViewMsg_SwapOut_Params& params) {
 | 
|    Send(new ViewHostMsg_SwapOut_ACK(routing_id_, params));
 | 
|  }
 | 
|  
 | 
| -void RenderViewImpl::NavigateToSwappedOutURL() {
 | 
| +void RenderViewImpl::NavigateToSwappedOutURL(
 | 
| +    WebKit::WebFrame* frame,
 | 
| +    base::DictionaryValue* frame_tree) {
 | 
|    // We use loadRequest instead of loadHTMLString because the former commits
 | 
|    // synchronously.  Otherwise a new navigation can interrupt the navigation
 | 
|    // to content::kSwappedOutURL. If that happens to be to the page we had been
 | 
|    // showing, then WebKit will never send a commit and we'll be left spinning.
 | 
|    GURL swappedOutURL(content::kSwappedOutURL);
 | 
|    WebURLRequest request(swappedOutURL);
 | 
| -  webview()->mainFrame()->loadRequest(request);
 | 
| +  frame->loadRequest(request);
 | 
| +
 | 
| +  // If a frame tree is specified, recursively recreate it using the data
 | 
| +  // in the current DictionaryValue.
 | 
| +  if (frame_tree == NULL)
 | 
| +    return;
 | 
| +
 | 
| +  string16 name;
 | 
| +  if (frame_tree->GetString("name", &name) && name != string16())
 | 
| +    frame->setName(name);
 | 
| +
 | 
| +  int remote_id;
 | 
| +  if (frame_tree->GetInteger("id", &remote_id))
 | 
| +    frames_map_.insert(std::pair<int, int>(frame->identifier(), remote_id));
 | 
| +
 | 
| +  ListValue* children;
 | 
| +  if (!frame_tree->GetList("subtree", &children))
 | 
| +    return;
 | 
| +
 | 
| +  base::DictionaryValue* child;
 | 
| +  for (size_t i = 0; i < children->GetSize(); ++i) {
 | 
| +    if (!children->GetDictionary(i, &child))
 | 
| +      continue;
 | 
| +    WebElement element = frame->document().createElement("iframe");
 | 
| +    if (frame->document().body().appendChild(element)) {
 | 
| +      WebFrame* subframe = WebFrame::fromFrameOwnerElement(element);
 | 
| +      if (subframe) {
 | 
| +        NavigateToSwappedOutURL(subframe, child);
 | 
| +      }
 | 
| +    }
 | 
| +  }
 | 
|  }
 | 
|  
 | 
|  void RenderViewImpl::OnClosePage() {
 | 
| @@ -5805,3 +5935,36 @@ void RenderViewImpl::OnJavaBridgeInit() {
 | 
|    java_bridge_dispatcher_ = new JavaBridgeDispatcher(this);
 | 
|  #endif
 | 
|  }
 | 
| +
 | 
| +void RenderViewImpl::OnFrameTree(
 | 
| +    int process_id,
 | 
| +    int route_id,
 | 
| +    const std::string& frame_tree) {
 | 
| +  base::DictionaryValue* frames = NULL;
 | 
| +  scoped_ptr<base::Value> tree(base::JSONReader::Read(frame_tree));
 | 
| +  if (tree.get() != NULL && tree->IsType(base::Value::TYPE_DICTIONARY))
 | 
| +    tree->GetAsDictionary(&frames);
 | 
| +
 | 
| +  updating_frame_tree_ = true;
 | 
| +  frames_map_.clear();
 | 
| +
 | 
| +  remote_process_id_ = process_id;
 | 
| +  remote_routing_id_ = route_id;
 | 
| +  NavigateToSwappedOutURL(webview()->mainFrame(), frames);
 | 
| +
 | 
| +  updating_frame_tree_ = false;
 | 
| +}
 | 
| +
 | 
| +WebKit::WebFrame* RenderViewImpl::GetFrameByRemoteID(int remote_frame_id) {
 | 
| +  WebKit::WebFrame* frame = NULL;
 | 
| +
 | 
| +  std::map<int, int>::iterator it = frames_map_.find(remote_frame_id);
 | 
| +  if (it == frames_map_.end())
 | 
| +    return NULL;
 | 
| +
 | 
| +  for (WebFrame* f = webview()->mainFrame(); f; f = f->traverseNext(false))
 | 
| +    if (f->identifier() == it->second)
 | 
| +      frame = f;
 | 
| +
 | 
| +  return frame;
 | 
| +}
 | 
| 
 |