Home | History | Annotate | Download | only in renderer
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "content/renderer/render_frame_proxy.h"
      6 
      7 #include <map>
      8 
      9 #include "base/lazy_instance.h"
     10 #include "content/child/webmessageportchannel_impl.h"
     11 #include "content/common/frame_messages.h"
     12 #include "content/common/swapped_out_messages.h"
     13 #include "content/common/view_messages.h"
     14 #include "content/renderer/child_frame_compositing_helper.h"
     15 #include "content/renderer/render_frame_impl.h"
     16 #include "content/renderer/render_thread_impl.h"
     17 #include "content/renderer/render_view_impl.h"
     18 #include "third_party/WebKit/public/web/WebLocalFrame.h"
     19 #include "third_party/WebKit/public/web/WebView.h"
     20 
     21 namespace content {
     22 
     23 namespace {
     24 
     25 // Facilitates lookup of RenderFrameProxy by routing_id.
     26 typedef std::map<int, RenderFrameProxy*> RoutingIDProxyMap;
     27 static base::LazyInstance<RoutingIDProxyMap> g_routing_id_proxy_map =
     28     LAZY_INSTANCE_INITIALIZER;
     29 
     30 // Facilitates lookup of RenderFrameProxy by WebFrame.
     31 typedef std::map<blink::WebFrame*, RenderFrameProxy*> FrameMap;
     32 base::LazyInstance<FrameMap> g_frame_map = LAZY_INSTANCE_INITIALIZER;
     33 
     34 }  // namespace
     35 
     36 // static
     37 RenderFrameProxy* RenderFrameProxy::CreateProxyToReplaceFrame(
     38     RenderFrameImpl* frame_to_replace,
     39     int routing_id) {
     40   CHECK_NE(routing_id, MSG_ROUTING_NONE);
     41 
     42   scoped_ptr<RenderFrameProxy> proxy(
     43       new RenderFrameProxy(routing_id, frame_to_replace->GetRoutingID()));
     44 
     45   // When a RenderFrame is replaced by a RenderProxy, the WebRemoteFrame should
     46   // always come from WebRemoteFrame::create and a call to WebFrame::swap must
     47   // follow later.
     48   blink::WebRemoteFrame* web_frame = blink::WebRemoteFrame::create(proxy.get());
     49   proxy->Init(web_frame, frame_to_replace->render_view());
     50   return proxy.release();
     51 }
     52 
     53 RenderFrameProxy* RenderFrameProxy::CreateFrameProxy(
     54     int routing_id,
     55     int parent_routing_id,
     56     int render_view_routing_id) {
     57   scoped_ptr<RenderFrameProxy> proxy(
     58       new RenderFrameProxy(routing_id, MSG_ROUTING_NONE));
     59   RenderViewImpl* render_view = NULL;
     60   blink::WebRemoteFrame* web_frame = NULL;
     61   if (parent_routing_id == MSG_ROUTING_NONE) {
     62     // Create a top level frame.
     63     render_view = RenderViewImpl::FromRoutingID(render_view_routing_id);
     64     web_frame = blink::WebRemoteFrame::create(proxy.get());
     65     render_view->webview()->setMainFrame(web_frame);
     66   } else {
     67     // Create a frame under an existing parent. The parent is always expected
     68     // to be a RenderFrameProxy, because navigations initiated by local frames
     69     // should not wind up here.
     70     RenderFrameProxy* parent =
     71         RenderFrameProxy::FromRoutingID(parent_routing_id);
     72     web_frame = parent->web_frame()->createRemoteChild("", proxy.get());
     73     render_view = parent->render_view();
     74   }
     75 
     76   proxy->Init(web_frame, render_view);
     77 
     78   return proxy.release();
     79 }
     80 
     81 // static
     82 RenderFrameProxy* RenderFrameProxy::FromRoutingID(int32 routing_id) {
     83   RoutingIDProxyMap* proxies = g_routing_id_proxy_map.Pointer();
     84   RoutingIDProxyMap::iterator it = proxies->find(routing_id);
     85   return it == proxies->end() ? NULL : it->second;
     86 }
     87 
     88 // static
     89 RenderFrameProxy* RenderFrameProxy::FromWebFrame(blink::WebFrame* web_frame) {
     90   FrameMap::iterator iter = g_frame_map.Get().find(web_frame);
     91   if (iter != g_frame_map.Get().end()) {
     92     RenderFrameProxy* proxy = iter->second;
     93     DCHECK_EQ(web_frame, proxy->web_frame());
     94     return proxy;
     95   }
     96   return NULL;
     97 }
     98 
     99 RenderFrameProxy::RenderFrameProxy(int routing_id, int frame_routing_id)
    100     : routing_id_(routing_id),
    101       frame_routing_id_(frame_routing_id),
    102       web_frame_(NULL),
    103       render_view_(NULL) {
    104   std::pair<RoutingIDProxyMap::iterator, bool> result =
    105       g_routing_id_proxy_map.Get().insert(std::make_pair(routing_id_, this));
    106   CHECK(result.second) << "Inserting a duplicate item.";
    107   RenderThread::Get()->AddRoute(routing_id_, this);
    108 }
    109 
    110 RenderFrameProxy::~RenderFrameProxy() {
    111   render_view()->UnregisterRenderFrameProxy(this);
    112 
    113   FrameMap::iterator it = g_frame_map.Get().find(web_frame_);
    114   CHECK(it != g_frame_map.Get().end());
    115   CHECK_EQ(it->second, this);
    116   g_frame_map.Get().erase(it);
    117 
    118   RenderThread::Get()->RemoveRoute(routing_id_);
    119   g_routing_id_proxy_map.Get().erase(routing_id_);
    120 
    121   // TODO(nick): Call close unconditionally when web_frame() is always remote.
    122   if (web_frame()->isWebRemoteFrame())
    123     web_frame()->close();
    124 }
    125 
    126 void RenderFrameProxy::Init(blink::WebRemoteFrame* web_frame,
    127                             RenderViewImpl* render_view) {
    128   CHECK(web_frame);
    129   CHECK(render_view);
    130 
    131   web_frame_ = web_frame;
    132   render_view_ = render_view;
    133 
    134   // TODO(nick): Should all RenderFrameProxies remain observers of their views?
    135   render_view_->RegisterRenderFrameProxy(this);
    136 
    137   std::pair<FrameMap::iterator, bool> result =
    138       g_frame_map.Get().insert(std::make_pair(web_frame_, this));
    139   CHECK(result.second) << "Inserted a duplicate item.";
    140 }
    141 
    142 void RenderFrameProxy::DidCommitCompositorFrame() {
    143   if (compositing_helper_.get())
    144     compositing_helper_->DidCommitCompositorFrame();
    145 }
    146 
    147 bool RenderFrameProxy::OnMessageReceived(const IPC::Message& msg) {
    148   bool handled = true;
    149   IPC_BEGIN_MESSAGE_MAP(RenderFrameProxy, msg)
    150     IPC_MESSAGE_HANDLER(FrameMsg_DeleteProxy, OnDeleteProxy)
    151     IPC_MESSAGE_HANDLER(FrameMsg_ChildFrameProcessGone, OnChildFrameProcessGone)
    152     IPC_MESSAGE_HANDLER_GENERIC(FrameMsg_CompositorFrameSwapped,
    153                                 OnCompositorFrameSwapped(msg))
    154     IPC_MESSAGE_HANDLER(FrameMsg_DisownOpener, OnDisownOpener)
    155     IPC_MESSAGE_UNHANDLED(handled = false)
    156   IPC_END_MESSAGE_MAP()
    157 
    158   // If |handled| is true, |this| may have been deleted.
    159   if (handled)
    160     return true;
    161 
    162   RenderFrameImpl* render_frame =
    163       RenderFrameImpl::FromRoutingID(frame_routing_id_);
    164   return render_frame && render_frame->OnMessageReceived(msg);
    165 }
    166 
    167 bool RenderFrameProxy::Send(IPC::Message* message) {
    168   if (!SwappedOutMessages::CanSendWhileSwappedOut(message)) {
    169     delete message;
    170     return false;
    171   }
    172   message->set_routing_id(routing_id_);
    173   return RenderThread::Get()->Send(message);
    174 }
    175 
    176 void RenderFrameProxy::OnDeleteProxy() {
    177   RenderFrameImpl* render_frame =
    178       RenderFrameImpl::FromRoutingID(frame_routing_id_);
    179 
    180   if (render_frame)
    181     render_frame->set_render_frame_proxy(NULL);
    182 
    183   delete this;
    184 }
    185 
    186 void RenderFrameProxy::OnChildFrameProcessGone() {
    187   if (compositing_helper_.get())
    188     compositing_helper_->ChildFrameGone();
    189 }
    190 
    191 void RenderFrameProxy::OnCompositorFrameSwapped(const IPC::Message& message) {
    192   FrameMsg_CompositorFrameSwapped::Param param;
    193   if (!FrameMsg_CompositorFrameSwapped::Read(&message, &param))
    194     return;
    195 
    196   scoped_ptr<cc::CompositorFrame> frame(new cc::CompositorFrame);
    197   param.a.frame.AssignTo(frame.get());
    198 
    199   if (!compositing_helper_.get()) {
    200     compositing_helper_ =
    201         ChildFrameCompositingHelper::CreateForRenderFrameProxy(this);
    202     compositing_helper_->EnableCompositing(true);
    203   }
    204   compositing_helper_->OnCompositorFrameSwapped(frame.Pass(),
    205                                                 param.a.producing_route_id,
    206                                                 param.a.output_surface_id,
    207                                                 param.a.producing_host_id,
    208                                                 param.a.shared_memory_handle);
    209 }
    210 
    211 void RenderFrameProxy::OnDisownOpener() {
    212   // TODO(creis): We should only see this for main frames for now.  To support
    213   // disowning the opener on subframes, we will need to move WebContentsImpl's
    214   // opener_ to FrameTreeNode.
    215   CHECK(!web_frame_->parent());
    216 
    217   // When there is a RenderFrame for this proxy, tell it to disown its opener.
    218   // TODO(creis): Remove this when we only have WebRemoteFrames and make sure
    219   // they know they have an opener.
    220   RenderFrameImpl* render_frame =
    221       RenderFrameImpl::FromRoutingID(frame_routing_id_);
    222   if (render_frame) {
    223     if (render_frame->GetWebFrame()->opener())
    224       render_frame->GetWebFrame()->setOpener(NULL);
    225     return;
    226   }
    227 
    228   if (web_frame_->opener())
    229     web_frame_->setOpener(NULL);
    230 }
    231 
    232 void RenderFrameProxy::postMessageEvent(
    233     blink::WebLocalFrame* source_frame,
    234     blink::WebRemoteFrame* target_frame,
    235     blink::WebSecurityOrigin target_origin,
    236     blink::WebDOMMessageEvent event) {
    237   DCHECK(!web_frame_ || web_frame_ == target_frame);
    238 
    239   ViewMsg_PostMessage_Params params;
    240   params.is_data_raw_string = false;
    241   params.data = event.data().toString();
    242   params.source_origin = event.origin();
    243   if (!target_origin.isNull())
    244     params.target_origin = target_origin.toString();
    245 
    246   blink::WebMessagePortChannelArray channels = event.releaseChannels();
    247   if (!channels.isEmpty()) {
    248     std::vector<int> message_port_ids(channels.size());
    249      // Extract the port IDs from the channel array.
    250      for (size_t i = 0; i < channels.size(); ++i) {
    251        WebMessagePortChannelImpl* webchannel =
    252            static_cast<WebMessagePortChannelImpl*>(channels[i]);
    253        message_port_ids[i] = webchannel->message_port_id();
    254        webchannel->QueueMessages();
    255        DCHECK_NE(message_port_ids[i], MSG_ROUTING_NONE);
    256      }
    257      params.message_port_ids = message_port_ids;
    258   }
    259 
    260   // Include the routing ID for the source frame (if one exists), which the
    261   // browser process will translate into the routing ID for the equivalent
    262   // frame in the target process.
    263   params.source_routing_id = MSG_ROUTING_NONE;
    264   if (source_frame) {
    265     RenderViewImpl* source_view =
    266         RenderViewImpl::FromWebView(source_frame->view());
    267     if (source_view)
    268       params.source_routing_id = source_view->routing_id();
    269   }
    270 
    271   Send(new ViewHostMsg_RouteMessageEvent(render_view_->GetRoutingID(), params));
    272 }
    273 
    274 void RenderFrameProxy::initializeChildFrame(
    275     const blink::WebRect& frame_rect,
    276     float scale_factor) {
    277   Send(new FrameHostMsg_InitializeChildFrame(
    278       routing_id_, frame_rect, scale_factor));
    279 }
    280 
    281 }  // namespace
    282