Supervised user import: Listen for profile creation/deletion
[chromium-blink-merge.git] / extensions / renderer / guest_view / extensions_guest_view_container.cc
blobf45303051b1958cbaee97e5f03a77144abbf9462
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/extensions_guest_view_container.h"
7 #include "content/public/renderer/render_frame.h"
8 #include "content/public/renderer/render_view.h"
9 #include "extensions/common/guest_view/guest_view_constants.h"
10 #include "extensions/common/guest_view/guest_view_messages.h"
11 #include "third_party/WebKit/public/web/WebLocalFrame.h"
12 #include "third_party/WebKit/public/web/WebScopedMicrotaskSuppression.h"
13 #include "third_party/WebKit/public/web/WebView.h"
15 namespace {
16 typedef std::map<int, extensions::ExtensionsGuestViewContainer*>
17 ExtensionsGuestViewContainerMap;
18 static base::LazyInstance<ExtensionsGuestViewContainerMap>
19 g_guest_view_container_map = LAZY_INSTANCE_INITIALIZER;
20 } // namespace
22 namespace extensions {
24 ExtensionsGuestViewContainer::Request::Request(GuestViewContainer* container,
25 v8::Local<v8::Function> callback,
26 v8::Isolate* isolate)
27 : container_(container), callback_(isolate, callback), isolate_(isolate) {
30 ExtensionsGuestViewContainer::Request::~Request() {
33 bool ExtensionsGuestViewContainer::Request::HasCallback() const {
34 return !callback_.IsEmpty();
37 v8::Local<v8::Function> ExtensionsGuestViewContainer::Request::GetCallback()
38 const {
39 return v8::Local<v8::Function>::New(isolate_, callback_);
42 void ExtensionsGuestViewContainer::Request::ExecuteCallbackIfAvailable(
43 int argc,
44 scoped_ptr<v8::Local<v8::Value>[]> argv) {
45 if (!HasCallback())
46 return;
48 v8::HandleScope handle_scope(isolate());
49 v8::Local<v8::Function> callback = GetCallback();
50 v8::Local<v8::Context> context = callback->CreationContext();
51 if (context.IsEmpty())
52 return;
54 v8::Context::Scope context_scope(context);
55 blink::WebScopedMicrotaskSuppression suppression;
57 // Call the AttachGuest API's callback with the guest proxy as the first
58 // parameter.
59 callback->Call(context->Global(), argc, argv.get());
62 ExtensionsGuestViewContainer::AttachRequest::AttachRequest(
63 GuestViewContainer* container,
64 int guest_instance_id,
65 scoped_ptr<base::DictionaryValue> params,
66 v8::Local<v8::Function> callback,
67 v8::Isolate* isolate)
68 : Request(container, callback, isolate),
69 guest_instance_id_(guest_instance_id),
70 params_(params.Pass()) {
73 ExtensionsGuestViewContainer::AttachRequest::~AttachRequest() {
76 void ExtensionsGuestViewContainer::AttachRequest::PerformRequest() {
77 if (!container()->render_frame())
78 return;
80 // Step 1, send the attach params to extensions/.
81 container()->render_frame()->Send(
82 new GuestViewHostMsg_AttachGuest(container()->element_instance_id(),
83 guest_instance_id_,
84 *params_));
86 // Step 2, attach plugin through content/.
87 container()->render_frame()->AttachGuest(container()->element_instance_id());
90 void ExtensionsGuestViewContainer::AttachRequest::HandleResponse(
91 const IPC::Message& message) {
92 GuestViewMsg_GuestAttached::Param param;
93 if (!GuestViewMsg_GuestAttached::Read(&message, &param))
94 return;
96 content::RenderView* guest_proxy_render_view =
97 content::RenderView::FromRoutingID(get<1>(param));
98 // TODO(fsamuel): Should we be reporting an error to JavaScript or DCHECKing?
99 if (!guest_proxy_render_view)
100 return;
102 v8::HandleScope handle_scope(isolate());
103 blink::WebFrame* frame = guest_proxy_render_view->GetWebView()->mainFrame();
104 v8::Local<v8::Value> window = frame->mainWorldScriptContext()->Global();
106 const int argc = 1;
107 scoped_ptr<v8::Local<v8::Value>[]> argv(new v8::Local<v8::Value>[argc]);
108 argv[0] = window;
110 ExecuteCallbackIfAvailable(argc, argv.Pass());
113 ExtensionsGuestViewContainer::DetachRequest::DetachRequest(
114 GuestViewContainer* container,
115 v8::Local<v8::Function> callback,
116 v8::Isolate* isolate)
117 : Request(container, callback, isolate) {
120 ExtensionsGuestViewContainer::DetachRequest::~DetachRequest() {
123 void ExtensionsGuestViewContainer::DetachRequest::PerformRequest() {
124 if (!container()->render_frame())
125 return;
127 container()->render_frame()->DetachGuest(container()->element_instance_id());
130 void ExtensionsGuestViewContainer::DetachRequest::HandleResponse(
131 const IPC::Message& message) {
132 ExecuteCallbackIfAvailable(0 /* argc */, nullptr);
135 ExtensionsGuestViewContainer::ExtensionsGuestViewContainer(
136 content::RenderFrame* render_frame)
137 : GuestViewContainer(render_frame),
138 ready_(false),
139 destruction_isolate_(nullptr),
140 element_resize_isolate_(nullptr),
141 weak_ptr_factory_(this) {
144 ExtensionsGuestViewContainer::~ExtensionsGuestViewContainer() {
145 if (element_instance_id() != guestview::kInstanceIDNone)
146 g_guest_view_container_map.Get().erase(element_instance_id());
148 if (pending_response_.get())
149 pending_response_->ExecuteCallbackIfAvailable(0 /* argc */, nullptr);
151 while (pending_requests_.size() > 0) {
152 linked_ptr<Request> pending_request = pending_requests_.front();
153 pending_requests_.pop_front();
154 // Call the JavaScript callbacks with no arguments which implies an error.
155 pending_request->ExecuteCallbackIfAvailable(0 /* argc */, nullptr);
158 // Call the destruction callback, if one is registered.
159 if (!destruction_callback_.IsEmpty()) {
160 v8::HandleScope handle_scope(destruction_isolate_);
161 v8::Local<v8::Function> callback = v8::Local<v8::Function>::New(
162 destruction_isolate_, destruction_callback_);
163 v8::Local<v8::Context> context = callback->CreationContext();
164 if (context.IsEmpty())
165 return;
167 v8::Context::Scope context_scope(context);
168 blink::WebScopedMicrotaskSuppression suppression;
170 callback->Call(context->Global(), 0 /* argc */, nullptr);
174 ExtensionsGuestViewContainer* ExtensionsGuestViewContainer::FromID(
175 int element_instance_id) {
176 ExtensionsGuestViewContainerMap* guest_view_containers =
177 g_guest_view_container_map.Pointer();
178 auto it = guest_view_containers->find(element_instance_id);
179 return it == guest_view_containers->end() ? nullptr : it->second;
182 void ExtensionsGuestViewContainer::IssueRequest(linked_ptr<Request> request) {
183 EnqueueRequest(request);
184 PerformPendingRequest();
187 void ExtensionsGuestViewContainer::RegisterDestructionCallback(
188 v8::Local<v8::Function> callback,
189 v8::Isolate* isolate) {
190 destruction_callback_.Reset(isolate, callback);
191 destruction_isolate_ = isolate;
194 void ExtensionsGuestViewContainer::RegisterElementResizeCallback(
195 v8::Local<v8::Function> callback,
196 v8::Isolate* isolate) {
197 element_resize_callback_.Reset(isolate, callback);
198 element_resize_isolate_ = isolate;
201 void ExtensionsGuestViewContainer::DidResizeElement(const gfx::Size& old_size,
202 const gfx::Size& new_size) {
203 // Call the element resize callback, if one is registered.
204 if (element_resize_callback_.IsEmpty())
205 return;
207 base::MessageLoop::current()->PostTask(
208 FROM_HERE,
209 base::Bind(&ExtensionsGuestViewContainer::CallElementResizeCallback,
210 weak_ptr_factory_.GetWeakPtr(), old_size, new_size));
213 bool ExtensionsGuestViewContainer::OnMessageReceived(
214 const IPC::Message& message) {
215 OnHandleCallback(message);
216 return true;
219 void ExtensionsGuestViewContainer::SetElementInstanceID(
220 int element_instance_id) {
221 GuestViewContainer::SetElementInstanceID(element_instance_id);
223 DCHECK(g_guest_view_container_map.Get().find(element_instance_id) ==
224 g_guest_view_container_map.Get().end());
225 g_guest_view_container_map.Get().insert(
226 std::make_pair(element_instance_id, this));
229 void ExtensionsGuestViewContainer::Ready() {
230 ready_ = true;
231 CHECK(!pending_response_.get());
232 PerformPendingRequest();
235 void ExtensionsGuestViewContainer::OnHandleCallback(
236 const IPC::Message& message) {
237 // Handle the callback for the current request with a pending response.
238 HandlePendingResponseCallback(message);
239 // Perform the subsequent attach request if one exists.
240 PerformPendingRequest();
243 void ExtensionsGuestViewContainer::CallElementResizeCallback(
244 const gfx::Size& old_size,
245 const gfx::Size& new_size) {
246 v8::HandleScope handle_scope(element_resize_isolate_);
247 v8::Local<v8::Function> callback = v8::Local<v8::Function>::New(
248 element_resize_isolate_, element_resize_callback_);
249 v8::Local<v8::Context> context = callback->CreationContext();
250 if (context.IsEmpty())
251 return;
253 const int argc = 4;
254 v8::Local<v8::Value> argv[argc] = {
255 v8::Integer::New(element_resize_isolate_, old_size.width()),
256 v8::Integer::New(element_resize_isolate_, old_size.height()),
257 v8::Integer::New(element_resize_isolate_, new_size.width()),
258 v8::Integer::New(element_resize_isolate_, new_size.height())};
260 v8::Context::Scope context_scope(context);
261 blink::WebScopedMicrotaskSuppression suppression;
263 callback->Call(context->Global(), argc, argv);
266 void ExtensionsGuestViewContainer::EnqueueRequest(linked_ptr<Request> request) {
267 pending_requests_.push_back(request);
270 void ExtensionsGuestViewContainer::PerformPendingRequest() {
271 if (!ready_ || pending_requests_.empty() || pending_response_.get())
272 return;
274 linked_ptr<Request> pending_request = pending_requests_.front();
275 pending_requests_.pop_front();
276 pending_request->PerformRequest();
277 pending_response_ = pending_request;
280 void ExtensionsGuestViewContainer::HandlePendingResponseCallback(
281 const IPC::Message& message) {
282 CHECK(pending_response_.get());
283 linked_ptr<Request> pending_response(pending_response_.release());
284 pending_response->HandleResponse(message);
287 } // namespace extensions