11320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Copyright 2014 The Chromium Authors. All rights reserved.
21320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Use of this source code is governed by a BSD-style license that can be
31320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// found in the LICENSE file.
41320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
51320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "extensions/renderer/guest_view/guest_view_container.h"
61320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
71320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "content/public/renderer/browser_plugin_delegate.h"
81320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "content/public/renderer/render_frame.h"
91320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "content/public/renderer/render_view.h"
101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "extensions/common/extension_messages.h"
111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "extensions/common/guest_view/guest_view_constants.h"
121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "third_party/WebKit/public/web/WebLocalFrame.h"
131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "third_party/WebKit/public/web/WebScopedMicrotaskSuppression.h"
141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "third_party/WebKit/public/web/WebView.h"
151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccinamespace {
171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccitypedef std::pair<int, int> GuestViewID;
181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccitypedef std::map<GuestViewID, extensions::GuestViewContainer*>
191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    GuestViewContainerMap;
201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccistatic base::LazyInstance<GuestViewContainerMap> g_guest_view_container_map =
211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    LAZY_INSTANCE_INITIALIZER;
221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}  // namespace
231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccinamespace extensions {
251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciGuestViewContainer::GuestViewContainer(
271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    content::RenderFrame* render_frame,
281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const std::string& mime_type)
291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    : content::BrowserPluginDelegate(render_frame, mime_type),
301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      content::RenderFrameObserver(render_frame),
311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      mime_type_(mime_type),
321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      element_instance_id_(guestview::kInstanceIDNone),
331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      render_view_routing_id_(render_frame->GetRenderView()->GetRoutingID()),
341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      attached_(false),
351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      attach_pending_(false),
361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      isolate_(NULL) {
371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciGuestViewContainer::~GuestViewContainer() {
401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (element_instance_id_ != guestview::kInstanceIDNone) {
411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    g_guest_view_container_map.Get().erase(
421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        GuestViewID(render_view_routing_id_, element_instance_id_));
431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciGuestViewContainer* GuestViewContainer::FromID(int render_view_routing_id,
471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                               int element_instance_id) {
481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  GuestViewContainerMap* guest_view_containers =
491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      g_guest_view_container_map.Pointer();
501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  GuestViewContainerMap::iterator it = guest_view_containers->find(
511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      GuestViewID(render_view_routing_id, element_instance_id));
521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return it == guest_view_containers->end() ? NULL : it->second;
531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid GuestViewContainer::AttachGuest(int element_instance_id,
571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                     int guest_instance_id,
581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                     scoped_ptr<base::DictionaryValue> params,
591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                     v8::Handle<v8::Function> callback,
601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                     v8::Isolate* isolate) {
611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // GuestViewContainer supports reattachment (i.e. attached_ == true) but not
621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // while a current attach process is pending.
631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (attach_pending_)
641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return;
651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Step 1, send the attach params to chrome/.
671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  render_frame()->Send(new ExtensionHostMsg_AttachGuest(render_view_routing_id_,
681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                                        element_instance_id,
691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                                        guest_instance_id,
701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                                        *params));
711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Step 2, attach plugin through content/.
731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  render_frame()->AttachGuest(element_instance_id);
741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  callback_.reset(callback);
761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  isolate_ = isolate;
771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  attach_pending_ = true;
781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid GuestViewContainer::SetElementInstanceID(int element_instance_id) {
811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  GuestViewID guest_view_id(render_view_routing_id_, element_instance_id);
821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK_EQ(element_instance_id_, guestview::kInstanceIDNone);
831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK(g_guest_view_container_map.Get().find(guest_view_id) ==
841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            g_guest_view_container_map.Get().end());
851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  element_instance_id_ = element_instance_id;
861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  g_guest_view_container_map.Get().insert(std::make_pair(guest_view_id, this));
871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid GuestViewContainer::DidFinishLoading() {
901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (mime_type_.empty())
911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return;
921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK_NE(element_instance_id_, guestview::kInstanceIDNone);
941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  render_frame()->Send(new ExtensionHostMsg_CreateMimeHandlerViewGuest(
951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      routing_id(), html_string_, mime_type_, element_instance_id_));
961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid GuestViewContainer::DidReceiveData(const char* data, int data_length) {
991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  std::string value(data, data_length);
1001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  html_string_ += value;
1011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid GuestViewContainer::OnDestruct() {
1041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // GuestViewContainer's lifetime is managed by BrowserPlugin so don't let
1051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // RenderFrameObserver self-destruct here.
1061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccibool GuestViewContainer::OnMessageReceived(const IPC::Message& message) {
1091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!ShouldHandleMessage(message))
1101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return false;
1111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK_NE(element_instance_id_, guestview::kInstanceIDNone);
1131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  int element_instance_id = guestview::kInstanceIDNone;
1141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  PickleIterator iter(message);
1151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  bool success = iter.ReadInt(&element_instance_id);
1161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK(success);
1171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (element_instance_id != element_instance_id_)
1181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return false;
1191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  bool handled = true;
1211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  IPC_BEGIN_MESSAGE_MAP(GuestViewContainer, message)
1221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    IPC_MESSAGE_HANDLER(ExtensionMsg_CreateMimeHandlerViewGuestACK,
1231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                        OnCreateMimeHandlerViewGuestACK)
1241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    IPC_MESSAGE_HANDLER(ExtensionMsg_GuestAttached, OnGuestAttached)
1251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    IPC_MESSAGE_UNHANDLED(handled = false)
1261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  IPC_END_MESSAGE_MAP()
1271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return handled;
1281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid GuestViewContainer::OnCreateMimeHandlerViewGuestACK(
1311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    int element_instance_id) {
1321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK_NE(element_instance_id_, guestview::kInstanceIDNone);
1331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK_EQ(element_instance_id_, element_instance_id);
1341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK(!mime_type_.empty());
1351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  render_frame()->AttachGuest(element_instance_id);
1361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid GuestViewContainer::OnGuestAttached(int element_instance_id,
1391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                         int guest_routing_id) {
1401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  attached_ = true;
1411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  attach_pending_ = false;
1421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // If we don't have a callback then there's nothing more to do.
1441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (callback_.IsEmpty())
1451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return;
1461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  content::RenderView* guest_proxy_render_view =
1481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      content::RenderView::FromRoutingID(guest_routing_id);
1491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // TODO(fsamuel): Should we be reporting an error to JavaScript or DCHECKing?
1501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!guest_proxy_render_view)
1511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return;
1521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  v8::HandleScope handle_scope(isolate_);
1541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  v8::Handle<v8::Function> callback = callback_.NewHandle(isolate_);
1551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  v8::Handle<v8::Context> context = callback->CreationContext();
1561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (context.IsEmpty())
1571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return;
1581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  blink::WebFrame* frame = guest_proxy_render_view->GetWebView()->mainFrame();
1601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  v8::Local<v8::Value> window = frame->mainWorldScriptContext()->Global();
1611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  const int argc = 1;
1631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  v8::Handle<v8::Value> argv[argc] = { window };
1641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  v8::Context::Scope context_scope(context);
1661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  blink::WebScopedMicrotaskSuppression suppression;
1671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Call the AttachGuest API's callback with the guest proxy as the first
1691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // parameter.
1701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  callback->Call(context->Global(), argc, argv);
1711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  callback_.reset();
1721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// static
1751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccibool GuestViewContainer::ShouldHandleMessage(const IPC::Message& message) {
1761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  switch (message.type()) {
1771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    case ExtensionMsg_CreateMimeHandlerViewGuestACK::ID:
1781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    case ExtensionMsg_GuestAttached::ID:
1791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      return true;
1801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    default:
1811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      break;
1821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
1831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return false;
1841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}  // namespace extensions
187