Add per-user preferences support.
[chromium-blink-merge.git] / extensions / renderer / guest_view / extensions_guest_view_container.cc
blobfe9570c5e4184234c117c25946aeb1ec5fe960ca
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(
25 GuestViewContainer* container,
26 v8::Handle<v8::Function> callback,
27 v8::Isolate* isolate)
28 : container_(container), callback_(isolate, callback), isolate_(isolate) {
31 ExtensionsGuestViewContainer::Request::~Request() {
34 bool ExtensionsGuestViewContainer::Request::HasCallback() const {
35 return !callback_.IsEmpty();
38 v8::Handle<v8::Function>
39 ExtensionsGuestViewContainer::Request::GetCallback() const {
40 return v8::Local<v8::Function>::New(isolate_, callback_);
43 ExtensionsGuestViewContainer::AttachRequest::AttachRequest(
44 GuestViewContainer* container,
45 int guest_instance_id,
46 scoped_ptr<base::DictionaryValue> params,
47 v8::Handle<v8::Function> callback,
48 v8::Isolate* isolate)
49 : Request(container, callback, isolate),
50 guest_instance_id_(guest_instance_id),
51 params_(params.Pass()) {
54 ExtensionsGuestViewContainer::AttachRequest::~AttachRequest() {
57 void ExtensionsGuestViewContainer::AttachRequest::PerformRequest() {
58 if (!container()->render_frame())
59 return;
61 // Step 1, send the attach params to extensions/.
62 container()->render_frame()->Send(
63 new GuestViewHostMsg_AttachGuest(container()->element_instance_id(),
64 guest_instance_id_,
65 *params_));
67 // Step 2, attach plugin through content/.
68 container()->render_frame()->AttachGuest(container()->element_instance_id());
71 void ExtensionsGuestViewContainer::AttachRequest::HandleResponse(
72 const IPC::Message& message) {
73 GuestViewMsg_GuestAttached::Param param;
74 if (!GuestViewMsg_GuestAttached::Read(&message, &param))
75 return;
77 // If we don't have a callback then there's nothing more to do.
78 if (!HasCallback())
79 return;
81 content::RenderView* guest_proxy_render_view =
82 content::RenderView::FromRoutingID(get<1>(param));
83 // TODO(fsamuel): Should we be reporting an error to JavaScript or DCHECKing?
84 if (!guest_proxy_render_view)
85 return;
87 v8::HandleScope handle_scope(isolate());
88 v8::Handle<v8::Function> callback = GetCallback();
89 v8::Handle<v8::Context> context = callback->CreationContext();
90 if (context.IsEmpty())
91 return;
93 blink::WebFrame* frame = guest_proxy_render_view->GetWebView()->mainFrame();
94 v8::Local<v8::Value> window = frame->mainWorldScriptContext()->Global();
96 const int argc = 1;
97 v8::Handle<v8::Value> argv[argc] = { window };
99 v8::Context::Scope context_scope(context);
100 blink::WebScopedMicrotaskSuppression suppression;
102 // Call the AttachGuest API's callback with the guest proxy as the first
103 // parameter.
104 callback->Call(context->Global(), argc, argv);
107 ExtensionsGuestViewContainer::DetachRequest::DetachRequest(
108 GuestViewContainer* container,
109 v8::Handle<v8::Function> callback,
110 v8::Isolate* isolate)
111 : Request(container, callback, isolate) {
114 ExtensionsGuestViewContainer::DetachRequest::~DetachRequest() {
117 void ExtensionsGuestViewContainer::DetachRequest::PerformRequest() {
118 if (!container()->render_frame())
119 return;
121 container()->render_frame()->DetachGuest(container()->element_instance_id());
124 void ExtensionsGuestViewContainer::DetachRequest::HandleResponse(
125 const IPC::Message& message) {
126 // If we don't have a callback then there's nothing more to do.
127 if (!HasCallback())
128 return;
130 v8::HandleScope handle_scope(isolate());
131 v8::Handle<v8::Function> callback = GetCallback();
132 v8::Handle<v8::Context> context = callback->CreationContext();
133 if (context.IsEmpty())
134 return;
136 v8::Context::Scope context_scope(context);
137 blink::WebScopedMicrotaskSuppression suppression;
139 // Call the DetachGuest's callback.
140 callback->Call(context->Global(), 0 /* argc */, nullptr);
143 ExtensionsGuestViewContainer::ExtensionsGuestViewContainer(
144 content::RenderFrame* render_frame)
145 : GuestViewContainer(render_frame),
146 ready_(false),
147 destruction_isolate_(nullptr),
148 element_resize_isolate_(nullptr),
149 weak_ptr_factory_(this) {
152 ExtensionsGuestViewContainer::~ExtensionsGuestViewContainer() {
153 if (element_instance_id() != guestview::kInstanceIDNone) {
154 g_guest_view_container_map.Get().erase(element_instance_id());
157 // Call the destruction callback, if one is registered.
158 if (destruction_callback_.IsEmpty())
159 return;
160 v8::HandleScope handle_scope(destruction_isolate_);
161 v8::Handle<v8::Function> callback =
162 v8::Local<v8::Function>::New(destruction_isolate_, destruction_callback_);
163 v8::Handle<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);
173 ExtensionsGuestViewContainer* ExtensionsGuestViewContainer::FromID(
174 int element_instance_id) {
175 ExtensionsGuestViewContainerMap* guest_view_containers =
176 g_guest_view_container_map.Pointer();
177 auto it = guest_view_containers->find(element_instance_id);
178 return it == guest_view_containers->end() ? nullptr : it->second;
181 void ExtensionsGuestViewContainer::IssueRequest(linked_ptr<Request> request) {
182 EnqueueRequest(request);
183 PerformPendingRequest();
186 void ExtensionsGuestViewContainer::RegisterDestructionCallback(
187 v8::Handle<v8::Function> callback,
188 v8::Isolate* isolate) {
189 destruction_callback_.Reset(isolate, callback);
190 destruction_isolate_ = isolate;
193 void ExtensionsGuestViewContainer::RegisterElementResizeCallback(
194 v8::Handle<v8::Function> callback,
195 v8::Isolate* isolate) {
196 element_resize_callback_.Reset(isolate, callback);
197 element_resize_isolate_ = isolate;
200 void ExtensionsGuestViewContainer::DidResizeElement(const gfx::Size& old_size,
201 const gfx::Size& new_size) {
202 // Call the element resize callback, if one is registered.
203 if (element_resize_callback_.IsEmpty())
204 return;
206 base::MessageLoop::current()->PostTask(
207 FROM_HERE,
208 base::Bind(&ExtensionsGuestViewContainer::CallElementResizeCallback,
209 weak_ptr_factory_.GetWeakPtr(), old_size, new_size));
212 bool ExtensionsGuestViewContainer::OnMessageReceived(
213 const IPC::Message& message) {
214 OnHandleCallback(message);
215 return true;
218 void ExtensionsGuestViewContainer::SetElementInstanceID(
219 int element_instance_id) {
220 GuestViewContainer::SetElementInstanceID(element_instance_id);
222 DCHECK(g_guest_view_container_map.Get().find(element_instance_id) ==
223 g_guest_view_container_map.Get().end());
224 g_guest_view_container_map.Get().insert(
225 std::make_pair(element_instance_id, this));
228 void ExtensionsGuestViewContainer::Ready() {
229 ready_ = true;
230 CHECK(!pending_response_.get());
231 PerformPendingRequest();
234 void ExtensionsGuestViewContainer::OnHandleCallback(
235 const IPC::Message& message) {
236 // Handle the callback for the current request with a pending response.
237 HandlePendingResponseCallback(message);
238 // Perform the subsequent attach request if one exists.
239 PerformPendingRequest();
242 void ExtensionsGuestViewContainer::CallElementResizeCallback(
243 const gfx::Size& old_size,
244 const gfx::Size& new_size) {
245 v8::HandleScope handle_scope(element_resize_isolate_);
246 v8::Handle<v8::Function> callback = v8::Local<v8::Function>::New(
247 element_resize_isolate_, element_resize_callback_);
248 v8::Handle<v8::Context> context = callback->CreationContext();
249 if (context.IsEmpty())
250 return;
252 const int argc = 4;
253 v8::Handle<v8::Value> argv[argc] = {
254 v8::Integer::New(element_resize_isolate_, old_size.width()),
255 v8::Integer::New(element_resize_isolate_, old_size.height()),
256 v8::Integer::New(element_resize_isolate_, new_size.width()),
257 v8::Integer::New(element_resize_isolate_, new_size.height())};
259 v8::Context::Scope context_scope(context);
260 blink::WebScopedMicrotaskSuppression suppression;
262 callback->Call(context->Global(), argc, argv);
265 void ExtensionsGuestViewContainer::EnqueueRequest(linked_ptr<Request> request) {
266 pending_requests_.push_back(request);
269 void ExtensionsGuestViewContainer::PerformPendingRequest() {
270 if (!ready_ || pending_requests_.empty() || pending_response_.get())
271 return;
273 linked_ptr<Request> pending_request = pending_requests_.front();
274 pending_requests_.pop_front();
275 pending_request->PerformRequest();
276 pending_response_ = pending_request;
279 void ExtensionsGuestViewContainer::HandlePendingResponseCallback(
280 const IPC::Message& message) {
281 CHECK(pending_response_.get());
282 linked_ptr<Request> pending_response(pending_response_.release());
283 pending_response->HandleResponse(message);
286 } // namespace extensions