Index: extensions/renderer/guest_view/guest_view_container.cc |
diff --git a/extensions/renderer/guest_view/guest_view_container.cc b/extensions/renderer/guest_view/guest_view_container.cc |
index 40051b103c17c11d8fc4aa180bdecc6448709a3c..8ef8054ae714ce18059109e5f2029960d9d28113 100644 |
--- a/extensions/renderer/guest_view/guest_view_container.cc |
+++ b/extensions/renderer/guest_view/guest_view_container.cc |
@@ -6,8 +6,20 @@ |
#include "content/public/renderer/browser_plugin_delegate.h" |
#include "content/public/renderer/render_frame.h" |
+#include "content/public/renderer/render_view.h" |
#include "extensions/common/extension_messages.h" |
#include "extensions/common/guest_view/guest_view_constants.h" |
+#include "third_party/WebKit/public/web/WebLocalFrame.h" |
+#include "third_party/WebKit/public/web/WebScopedMicrotaskSuppression.h" |
+#include "third_party/WebKit/public/web/WebView.h" |
+ |
+namespace { |
+typedef std::pair<int, int> GuestViewID; |
+typedef std::map<GuestViewID, extensions::GuestViewContainer*> |
+ GuestViewContainerMap; |
+static base::LazyInstance<GuestViewContainerMap> g_guest_view_container_map = |
+ LAZY_INSTANCE_INITIALIZER; |
+} // namespace |
namespace extensions { |
@@ -17,14 +29,61 @@ GuestViewContainer::GuestViewContainer( |
: content::BrowserPluginDelegate(render_frame, mime_type), |
content::RenderFrameObserver(render_frame), |
mime_type_(mime_type), |
- element_instance_id_(guestview::kInstanceIDNone) { |
+ element_instance_id_(guestview::kInstanceIDNone), |
+ render_view_routing_id_(render_frame->GetRenderView()->GetRoutingID()), |
+ attached_(false), |
+ attach_pending_(false), |
+ isolate_(NULL) { |
} |
GuestViewContainer::~GuestViewContainer() { |
+ if (element_instance_id_ != guestview::kInstanceIDNone) { |
+ g_guest_view_container_map.Get().erase( |
+ GuestViewID(render_view_routing_id_, element_instance_id_)); |
+ } |
+} |
+ |
+GuestViewContainer* GuestViewContainer::FromID(int render_view_routing_id, |
+ int element_instance_id) { |
+ GuestViewContainerMap* guest_view_containers = |
+ g_guest_view_container_map.Pointer(); |
+ GuestViewContainerMap::iterator it = guest_view_containers->find( |
+ GuestViewID(render_view_routing_id, element_instance_id)); |
+ return it == guest_view_containers->end() ? NULL : it->second; |
+} |
+ |
+ |
+void GuestViewContainer::AttachGuest(int element_instance_id, |
+ int guest_instance_id, |
+ scoped_ptr<base::DictionaryValue> params, |
+ v8::Handle<v8::Function> callback, |
+ v8::Isolate* isolate) { |
+ // GuestViewContainer supports reattachment (i.e. attached_ == true) but not |
+ // while a current attach process is pending. |
+ if (attach_pending_) |
+ return; |
+ |
+ // Step 1, send the attach params to chrome/. |
+ render_frame()->Send(new ExtensionHostMsg_AttachGuest(render_view_routing_id_, |
+ element_instance_id, |
+ guest_instance_id, |
+ *params)); |
+ |
+ // Step 2, attach plugin through content/. |
+ render_frame()->AttachGuest(element_instance_id); |
+ |
+ callback_.reset(callback); |
+ isolate_ = isolate; |
+ attach_pending_ = true; |
} |
void GuestViewContainer::SetElementInstanceID(int element_instance_id) { |
+ GuestViewID guest_view_id(render_view_routing_id_, element_instance_id); |
+ DCHECK_EQ(element_instance_id_, guestview::kInstanceIDNone); |
+ DCHECK(g_guest_view_container_map.Get().find(guest_view_id) == |
+ g_guest_view_container_map.Get().end()); |
element_instance_id_ = element_instance_id; |
+ g_guest_view_container_map.Get().insert(std::make_pair(guest_view_id, this)); |
} |
void GuestViewContainer::DidFinishLoading() { |
@@ -47,7 +106,7 @@ void GuestViewContainer::OnDestruct() { |
} |
bool GuestViewContainer::OnMessageReceived(const IPC::Message& message) { |
- if (message.type() != ExtensionMsg_CreateMimeHandlerViewGuestACK::ID) |
+ if (!ShouldHandleMessage(message)) |
return false; |
DCHECK_NE(element_instance_id_, guestview::kInstanceIDNone); |
@@ -62,6 +121,7 @@ bool GuestViewContainer::OnMessageReceived(const IPC::Message& message) { |
IPC_BEGIN_MESSAGE_MAP(GuestViewContainer, message) |
IPC_MESSAGE_HANDLER(ExtensionMsg_CreateMimeHandlerViewGuestACK, |
OnCreateMimeHandlerViewGuestACK) |
+ IPC_MESSAGE_HANDLER(ExtensionMsg_GuestAttached, OnGuestAttached) |
IPC_MESSAGE_UNHANDLED(handled = false) |
IPC_END_MESSAGE_MAP() |
return handled; |
@@ -75,4 +135,52 @@ void GuestViewContainer::OnCreateMimeHandlerViewGuestACK( |
render_frame()->AttachGuest(element_instance_id); |
} |
+void GuestViewContainer::OnGuestAttached(int element_instance_id, |
+ int guest_routing_id) { |
+ attached_ = true; |
+ attach_pending_ = false; |
+ |
+ // If we don't have a callback then there's nothing more to do. |
+ if (callback_.IsEmpty()) |
+ return; |
+ |
+ content::RenderView* guest_proxy_render_view = |
+ content::RenderView::FromRoutingID(guest_routing_id); |
+ // TODO(fsamuel): Should we be reporting an error to JavaScript or DCHECKing? |
+ if (!guest_proxy_render_view) |
+ return; |
+ |
+ v8::HandleScope handle_scope(isolate_); |
+ v8::Handle<v8::Function> callback = callback_.NewHandle(isolate_); |
+ v8::Handle<v8::Context> context = callback->CreationContext(); |
+ if (context.IsEmpty()) |
+ return; |
+ |
+ blink::WebFrame* frame = guest_proxy_render_view->GetWebView()->mainFrame(); |
+ v8::Local<v8::Value> window = frame->mainWorldScriptContext()->Global(); |
+ |
+ const int argc = 1; |
+ v8::Handle<v8::Value> argv[argc] = { window }; |
+ |
+ v8::Context::Scope context_scope(context); |
+ blink::WebScopedMicrotaskSuppression suppression; |
+ |
+ // Call the AttachGuest API's callback with the guest proxy as the first |
+ // parameter. |
+ callback->Call(context->Global(), argc, argv); |
+ callback_.reset(); |
+} |
+ |
+// static |
+bool GuestViewContainer::ShouldHandleMessage(const IPC::Message& message) { |
+ switch (message.type()) { |
+ case ExtensionMsg_CreateMimeHandlerViewGuestACK::ID: |
+ case ExtensionMsg_GuestAttached::ID: |
+ return true; |
+ default: |
+ break; |
+ } |
+ return false; |
+} |
+ |
} // namespace extensions |