Make it clear that WeakPtrFactory is the last data member
[chromium-blink-merge.git] / extensions / renderer / guest_view / guest_view_container.cc
blob8ef8054ae714ce18059109e5f2029960d9d28113
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.
5 #include "extensions/renderer/guest_view/guest_view_container.h"
7 #include "content/public/renderer/browser_plugin_delegate.h"
8 #include "content/public/renderer/render_frame.h"
9 #include "content/public/renderer/render_view.h"
10 #include "extensions/common/extension_messages.h"
11 #include "extensions/common/guest_view/guest_view_constants.h"
12 #include "third_party/WebKit/public/web/WebLocalFrame.h"
13 #include "third_party/WebKit/public/web/WebScopedMicrotaskSuppression.h"
14 #include "third_party/WebKit/public/web/WebView.h"
16 namespace {
17 typedef std::pair<int, int> GuestViewID;
18 typedef std::map<GuestViewID, extensions::GuestViewContainer*>
19 GuestViewContainerMap;
20 static base::LazyInstance<GuestViewContainerMap> g_guest_view_container_map =
21 LAZY_INSTANCE_INITIALIZER;
22 } // namespace
24 namespace extensions {
26 GuestViewContainer::GuestViewContainer(
27 content::RenderFrame* render_frame,
28 const std::string& mime_type)
29 : content::BrowserPluginDelegate(render_frame, mime_type),
30 content::RenderFrameObserver(render_frame),
31 mime_type_(mime_type),
32 element_instance_id_(guestview::kInstanceIDNone),
33 render_view_routing_id_(render_frame->GetRenderView()->GetRoutingID()),
34 attached_(false),
35 attach_pending_(false),
36 isolate_(NULL) {
39 GuestViewContainer::~GuestViewContainer() {
40 if (element_instance_id_ != guestview::kInstanceIDNone) {
41 g_guest_view_container_map.Get().erase(
42 GuestViewID(render_view_routing_id_, element_instance_id_));
46 GuestViewContainer* GuestViewContainer::FromID(int render_view_routing_id,
47 int element_instance_id) {
48 GuestViewContainerMap* guest_view_containers =
49 g_guest_view_container_map.Pointer();
50 GuestViewContainerMap::iterator it = guest_view_containers->find(
51 GuestViewID(render_view_routing_id, element_instance_id));
52 return it == guest_view_containers->end() ? NULL : it->second;
56 void GuestViewContainer::AttachGuest(int element_instance_id,
57 int guest_instance_id,
58 scoped_ptr<base::DictionaryValue> params,
59 v8::Handle<v8::Function> callback,
60 v8::Isolate* isolate) {
61 // GuestViewContainer supports reattachment (i.e. attached_ == true) but not
62 // while a current attach process is pending.
63 if (attach_pending_)
64 return;
66 // Step 1, send the attach params to chrome/.
67 render_frame()->Send(new ExtensionHostMsg_AttachGuest(render_view_routing_id_,
68 element_instance_id,
69 guest_instance_id,
70 *params));
72 // Step 2, attach plugin through content/.
73 render_frame()->AttachGuest(element_instance_id);
75 callback_.reset(callback);
76 isolate_ = isolate;
77 attach_pending_ = true;
80 void GuestViewContainer::SetElementInstanceID(int element_instance_id) {
81 GuestViewID guest_view_id(render_view_routing_id_, element_instance_id);
82 DCHECK_EQ(element_instance_id_, guestview::kInstanceIDNone);
83 DCHECK(g_guest_view_container_map.Get().find(guest_view_id) ==
84 g_guest_view_container_map.Get().end());
85 element_instance_id_ = element_instance_id;
86 g_guest_view_container_map.Get().insert(std::make_pair(guest_view_id, this));
89 void GuestViewContainer::DidFinishLoading() {
90 if (mime_type_.empty())
91 return;
93 DCHECK_NE(element_instance_id_, guestview::kInstanceIDNone);
94 render_frame()->Send(new ExtensionHostMsg_CreateMimeHandlerViewGuest(
95 routing_id(), html_string_, mime_type_, element_instance_id_));
98 void GuestViewContainer::DidReceiveData(const char* data, int data_length) {
99 std::string value(data, data_length);
100 html_string_ += value;
103 void GuestViewContainer::OnDestruct() {
104 // GuestViewContainer's lifetime is managed by BrowserPlugin so don't let
105 // RenderFrameObserver self-destruct here.
108 bool GuestViewContainer::OnMessageReceived(const IPC::Message& message) {
109 if (!ShouldHandleMessage(message))
110 return false;
112 DCHECK_NE(element_instance_id_, guestview::kInstanceIDNone);
113 int element_instance_id = guestview::kInstanceIDNone;
114 PickleIterator iter(message);
115 bool success = iter.ReadInt(&element_instance_id);
116 DCHECK(success);
117 if (element_instance_id != element_instance_id_)
118 return false;
120 bool handled = true;
121 IPC_BEGIN_MESSAGE_MAP(GuestViewContainer, message)
122 IPC_MESSAGE_HANDLER(ExtensionMsg_CreateMimeHandlerViewGuestACK,
123 OnCreateMimeHandlerViewGuestACK)
124 IPC_MESSAGE_HANDLER(ExtensionMsg_GuestAttached, OnGuestAttached)
125 IPC_MESSAGE_UNHANDLED(handled = false)
126 IPC_END_MESSAGE_MAP()
127 return handled;
130 void GuestViewContainer::OnCreateMimeHandlerViewGuestACK(
131 int element_instance_id) {
132 DCHECK_NE(element_instance_id_, guestview::kInstanceIDNone);
133 DCHECK_EQ(element_instance_id_, element_instance_id);
134 DCHECK(!mime_type_.empty());
135 render_frame()->AttachGuest(element_instance_id);
138 void GuestViewContainer::OnGuestAttached(int element_instance_id,
139 int guest_routing_id) {
140 attached_ = true;
141 attach_pending_ = false;
143 // If we don't have a callback then there's nothing more to do.
144 if (callback_.IsEmpty())
145 return;
147 content::RenderView* guest_proxy_render_view =
148 content::RenderView::FromRoutingID(guest_routing_id);
149 // TODO(fsamuel): Should we be reporting an error to JavaScript or DCHECKing?
150 if (!guest_proxy_render_view)
151 return;
153 v8::HandleScope handle_scope(isolate_);
154 v8::Handle<v8::Function> callback = callback_.NewHandle(isolate_);
155 v8::Handle<v8::Context> context = callback->CreationContext();
156 if (context.IsEmpty())
157 return;
159 blink::WebFrame* frame = guest_proxy_render_view->GetWebView()->mainFrame();
160 v8::Local<v8::Value> window = frame->mainWorldScriptContext()->Global();
162 const int argc = 1;
163 v8::Handle<v8::Value> argv[argc] = { window };
165 v8::Context::Scope context_scope(context);
166 blink::WebScopedMicrotaskSuppression suppression;
168 // Call the AttachGuest API's callback with the guest proxy as the first
169 // parameter.
170 callback->Call(context->Global(), argc, argv);
171 callback_.reset();
174 // static
175 bool GuestViewContainer::ShouldHandleMessage(const IPC::Message& message) {
176 switch (message.type()) {
177 case ExtensionMsg_CreateMimeHandlerViewGuestACK::ID:
178 case ExtensionMsg_GuestAttached::ID:
179 return true;
180 default:
181 break;
183 return false;
186 } // namespace extensions