Reland the ULONG -> SIZE_T change from 317177
[chromium-blink-merge.git] / extensions / renderer / guest_view / extensions_guest_view_container.cc
blob5936ee8ec916cf40e2a8498d03d14eb30e727cec
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),
29 callback_(callback),
30 isolate_(isolate) {
33 ExtensionsGuestViewContainer::Request::~Request() {
36 bool ExtensionsGuestViewContainer::Request::HasCallback() const {
37 return !callback_.IsEmpty();
40 v8::Handle<v8::Function>
41 ExtensionsGuestViewContainer::Request::GetCallback() const {
42 return callback_.NewHandle(isolate_);
45 ExtensionsGuestViewContainer::AttachRequest::AttachRequest(
46 GuestViewContainer* container,
47 int guest_instance_id,
48 scoped_ptr<base::DictionaryValue> params,
49 v8::Handle<v8::Function> callback,
50 v8::Isolate* isolate)
51 : Request(container, callback, isolate),
52 guest_instance_id_(guest_instance_id),
53 params_(params.Pass()) {
56 ExtensionsGuestViewContainer::AttachRequest::~AttachRequest() {
59 void ExtensionsGuestViewContainer::AttachRequest::PerformRequest() {
60 if (!container()->render_frame())
61 return;
63 // Step 1, send the attach params to extensions/.
64 container()->render_frame()->Send(
65 new GuestViewHostMsg_AttachGuest(container()->element_instance_id(),
66 guest_instance_id_,
67 *params_));
69 // Step 2, attach plugin through content/.
70 container()->render_frame()->AttachGuest(container()->element_instance_id());
73 void ExtensionsGuestViewContainer::AttachRequest::HandleResponse(
74 const IPC::Message& message) {
75 GuestViewMsg_GuestAttached::Param param;
76 if (!GuestViewMsg_GuestAttached::Read(&message, &param))
77 return;
79 // If we don't have a callback then there's nothing more to do.
80 if (!HasCallback())
81 return;
83 content::RenderView* guest_proxy_render_view =
84 content::RenderView::FromRoutingID(get<1>(param));
85 // TODO(fsamuel): Should we be reporting an error to JavaScript or DCHECKing?
86 if (!guest_proxy_render_view)
87 return;
89 v8::HandleScope handle_scope(isolate());
90 v8::Handle<v8::Function> callback = GetCallback();
91 v8::Handle<v8::Context> context = callback->CreationContext();
92 if (context.IsEmpty())
93 return;
95 blink::WebFrame* frame = guest_proxy_render_view->GetWebView()->mainFrame();
96 v8::Local<v8::Value> window = frame->mainWorldScriptContext()->Global();
98 const int argc = 1;
99 v8::Handle<v8::Value> argv[argc] = { window };
101 v8::Context::Scope context_scope(context);
102 blink::WebScopedMicrotaskSuppression suppression;
104 // Call the AttachGuest API's callback with the guest proxy as the first
105 // parameter.
106 callback->Call(context->Global(), argc, argv);
109 ExtensionsGuestViewContainer::DetachRequest::DetachRequest(
110 GuestViewContainer* container,
111 v8::Handle<v8::Function> callback,
112 v8::Isolate* isolate)
113 : Request(container, callback, isolate) {
116 ExtensionsGuestViewContainer::DetachRequest::~DetachRequest() {
119 void ExtensionsGuestViewContainer::DetachRequest::PerformRequest() {
120 if (!container()->render_frame())
121 return;
123 container()->render_frame()->DetachGuest(container()->element_instance_id());
126 void ExtensionsGuestViewContainer::DetachRequest::HandleResponse(
127 const IPC::Message& message) {
128 // If we don't have a callback then there's nothing more to do.
129 if (!HasCallback())
130 return;
132 v8::HandleScope handle_scope(isolate());
133 v8::Handle<v8::Function> callback = GetCallback();
134 v8::Handle<v8::Context> context = callback->CreationContext();
135 if (context.IsEmpty())
136 return;
138 v8::Context::Scope context_scope(context);
139 blink::WebScopedMicrotaskSuppression suppression;
141 // Call the DetachGuest's callback.
142 callback->Call(context->Global(), 0 /* argc */, nullptr);
145 ExtensionsGuestViewContainer::ExtensionsGuestViewContainer(
146 content::RenderFrame* render_frame)
147 : GuestViewContainer(render_frame),
148 ready_(false),
149 destruction_isolate_(nullptr),
150 element_resize_isolate_(nullptr),
151 weak_ptr_factory_(this) {
154 ExtensionsGuestViewContainer::~ExtensionsGuestViewContainer() {
155 if (element_instance_id() != guestview::kInstanceIDNone) {
156 g_guest_view_container_map.Get().erase(element_instance_id());
159 // Call the destruction callback, if one is registered.
160 if (destruction_callback_.IsEmpty())
161 return;
162 v8::HandleScope handle_scope(destruction_isolate_);
163 v8::Handle<v8::Function> callback =
164 destruction_callback_.NewHandle(destruction_isolate_);
165 v8::Handle<v8::Context> context = callback->CreationContext();
166 if (context.IsEmpty())
167 return;
169 v8::Context::Scope context_scope(context);
170 blink::WebScopedMicrotaskSuppression suppression;
172 callback->Call(context->Global(), 0 /* argc */, nullptr);
175 ExtensionsGuestViewContainer* ExtensionsGuestViewContainer::FromID(
176 int element_instance_id) {
177 ExtensionsGuestViewContainerMap* guest_view_containers =
178 g_guest_view_container_map.Pointer();
179 auto it = guest_view_containers->find(element_instance_id);
180 return it == guest_view_containers->end() ? nullptr : it->second;
183 void ExtensionsGuestViewContainer::IssueRequest(linked_ptr<Request> request) {
184 EnqueueRequest(request);
185 PerformPendingRequest();
188 void ExtensionsGuestViewContainer::RegisterDestructionCallback(
189 v8::Handle<v8::Function> callback,
190 v8::Isolate* isolate) {
191 destruction_callback_.reset(callback);
192 destruction_isolate_ = isolate;
195 void ExtensionsGuestViewContainer::RegisterElementResizeCallback(
196 v8::Handle<v8::Function> callback,
197 v8::Isolate* isolate) {
198 element_resize_callback_.reset(callback);
199 element_resize_isolate_ = isolate;
202 void ExtensionsGuestViewContainer::DidResizeElement(const gfx::Size& old_size,
203 const gfx::Size& new_size) {
204 // Call the element resize callback, if one is registered.
205 if (element_resize_callback_.IsEmpty())
206 return;
208 base::MessageLoop::current()->PostTask(
209 FROM_HERE,
210 base::Bind(&ExtensionsGuestViewContainer::CallElementResizeCallback,
211 weak_ptr_factory_.GetWeakPtr(), old_size, new_size));
214 bool ExtensionsGuestViewContainer::OnMessageReceived(
215 const IPC::Message& message) {
216 OnHandleCallback(message);
217 return true;
220 void ExtensionsGuestViewContainer::SetElementInstanceID(
221 int element_instance_id) {
222 GuestViewContainer::SetElementInstanceID(element_instance_id);
224 DCHECK(g_guest_view_container_map.Get().find(element_instance_id) ==
225 g_guest_view_container_map.Get().end());
226 g_guest_view_container_map.Get().insert(
227 std::make_pair(element_instance_id, this));
230 void ExtensionsGuestViewContainer::Ready() {
231 ready_ = true;
232 CHECK(!pending_response_.get());
233 PerformPendingRequest();
236 void ExtensionsGuestViewContainer::OnHandleCallback(
237 const IPC::Message& message) {
238 // Handle the callback for the current request with a pending response.
239 HandlePendingResponseCallback(message);
240 // Perform the subsequent attach request if one exists.
241 PerformPendingRequest();
244 void ExtensionsGuestViewContainer::CallElementResizeCallback(
245 const gfx::Size& old_size,
246 const gfx::Size& new_size) {
247 v8::HandleScope handle_scope(element_resize_isolate_);
248 v8::Handle<v8::Function> callback =
249 element_resize_callback_.NewHandle(element_resize_isolate_);
250 v8::Handle<v8::Context> context = callback->CreationContext();
251 if (context.IsEmpty())
252 return;
254 const int argc = 4;
255 v8::Handle<v8::Value> argv[argc] = {
256 v8::Integer::New(element_resize_isolate_, old_size.width()),
257 v8::Integer::New(element_resize_isolate_, old_size.height()),
258 v8::Integer::New(element_resize_isolate_, new_size.width()),
259 v8::Integer::New(element_resize_isolate_, new_size.height())};
261 v8::Context::Scope context_scope(context);
262 blink::WebScopedMicrotaskSuppression suppression;
264 callback->Call(context->Global(), argc, argv);
267 void ExtensionsGuestViewContainer::EnqueueRequest(linked_ptr<Request> request) {
268 pending_requests_.push_back(request);
271 void ExtensionsGuestViewContainer::PerformPendingRequest() {
272 if (!ready_ || pending_requests_.empty() || pending_response_.get())
273 return;
275 linked_ptr<Request> pending_request = pending_requests_.front();
276 pending_requests_.pop_front();
277 pending_request->PerformRequest();
278 pending_response_ = pending_request;
281 void ExtensionsGuestViewContainer::HandlePendingResponseCallback(
282 const IPC::Message& message) {
283 CHECK(pending_response_.get());
284 linked_ptr<Request> pending_response(pending_response_.release());
285 pending_response->HandleResponse(message);
288 } // namespace extensions