Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / ppapi / proxy / ppb_var_deprecated_proxy.cc
blob7adda60381b6e5818c338929cc721a07bfd5094f
1 // Copyright (c) 2012 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 "ppapi/proxy/ppb_var_deprecated_proxy.h"
7 #include <stdlib.h> // For malloc
9 #include "base/bind.h"
10 #include "base/logging.h"
11 #include "base/message_loop/message_loop.h"
12 #include "ppapi/c/dev/ppb_var_deprecated.h"
13 #include "ppapi/c/pp_var.h"
14 #include "ppapi/c/ppb_core.h"
15 #include "ppapi/c/ppb_var.h"
16 #include "ppapi/proxy/host_dispatcher.h"
17 #include "ppapi/proxy/plugin_dispatcher.h"
18 #include "ppapi/proxy/plugin_globals.h"
19 #include "ppapi/proxy/plugin_resource_tracker.h"
20 #include "ppapi/proxy/plugin_var_tracker.h"
21 #include "ppapi/proxy/ppapi_messages.h"
22 #include "ppapi/proxy/ppp_class_proxy.h"
23 #include "ppapi/proxy/proxy_object_var.h"
24 #include "ppapi/proxy/serialized_var.h"
25 #include "ppapi/shared_impl/ppapi_globals.h"
26 #include "ppapi/shared_impl/ppb_var_shared.h"
27 #include "ppapi/shared_impl/proxy_lock.h"
28 #include "ppapi/shared_impl/var.h"
30 namespace ppapi {
31 namespace proxy {
33 namespace {
35 // Used to do get the set-up information for calling a var object. If the
36 // exception is set, returns NULL. Otherwise, computes the dispatcher for the
37 // given var object. If the var is not a valid object, returns NULL and sets
38 // the exception.
39 PluginDispatcher* CheckExceptionAndGetDispatcher(const PP_Var& object,
40 PP_Var* exception) {
41 // If an exception is already set, we don't need to do anything, just return
42 // an error to the caller.
43 if (exception && exception->type != PP_VARTYPE_UNDEFINED)
44 return NULL;
47 if (object.type == PP_VARTYPE_OBJECT) {
48 // Get the dispatcher for the object.
49 PluginDispatcher* dispatcher =
50 PluginGlobals::Get()->plugin_var_tracker()->
51 DispatcherForPluginObject(object);
52 if (dispatcher)
53 return dispatcher;
56 // The object is invalid. This means we can't figure out which dispatcher
57 // to use, which is OK because the call will fail anyway. Set the exception.
58 if (exception) {
59 *exception = StringVar::StringToPPVar(
60 std::string("Attempting to use an invalid object"));
62 return NULL;
65 // PPB_Var_Deprecated plugin ---------------------------------------------------
67 bool HasProperty(PP_Var var,
68 PP_Var name,
69 PP_Var* exception) {
70 ProxyAutoLock lock;
71 Dispatcher* dispatcher = CheckExceptionAndGetDispatcher(var, exception);
72 if (!dispatcher)
73 return false;
75 ReceiveSerializedException se(dispatcher, exception);
76 PP_Bool result = PP_FALSE;
77 if (!se.IsThrown()) {
78 dispatcher->Send(new PpapiHostMsg_PPBVar_HasProperty(
79 API_ID_PPB_VAR_DEPRECATED,
80 SerializedVarSendInput(dispatcher, var),
81 SerializedVarSendInput(dispatcher, name), &se, &result));
83 return PP_ToBool(result);
86 bool HasMethod(PP_Var var,
87 PP_Var name,
88 PP_Var* exception) {
89 ProxyAutoLock lock;
90 Dispatcher* dispatcher = CheckExceptionAndGetDispatcher(var, exception);
91 if (!dispatcher)
92 return false;
94 ReceiveSerializedException se(dispatcher, exception);
95 PP_Bool result = PP_FALSE;
96 if (!se.IsThrown()) {
97 dispatcher->Send(new PpapiHostMsg_PPBVar_HasMethodDeprecated(
98 API_ID_PPB_VAR_DEPRECATED,
99 SerializedVarSendInput(dispatcher, var),
100 SerializedVarSendInput(dispatcher, name), &se, &result));
102 return PP_ToBool(result);
105 PP_Var GetProperty(PP_Var var,
106 PP_Var name,
107 PP_Var* exception) {
108 ProxyAutoLock lock;
109 Dispatcher* dispatcher = CheckExceptionAndGetDispatcher(var, exception);
110 if (!dispatcher)
111 return PP_MakeUndefined();
113 ReceiveSerializedException se(dispatcher, exception);
114 ReceiveSerializedVarReturnValue result;
115 if (!se.IsThrown()) {
116 dispatcher->Send(new PpapiHostMsg_PPBVar_GetProperty(
117 API_ID_PPB_VAR_DEPRECATED,
118 SerializedVarSendInput(dispatcher, var),
119 SerializedVarSendInput(dispatcher, name), &se, &result));
121 return result.Return(dispatcher);
124 void EnumerateProperties(PP_Var var,
125 uint32_t* property_count,
126 PP_Var** properties,
127 PP_Var* exception) {
128 ProxyAutoLock lock;
129 Dispatcher* dispatcher = CheckExceptionAndGetDispatcher(var, exception);
130 if (!dispatcher) {
131 *property_count = 0;
132 *properties = NULL;
133 return;
136 ReceiveSerializedVarVectorOutParam out_vector(dispatcher,
137 property_count, properties);
138 ReceiveSerializedException se(dispatcher, exception);
139 if (!se.IsThrown()) {
140 dispatcher->Send(new PpapiHostMsg_PPBVar_EnumerateProperties(
141 API_ID_PPB_VAR_DEPRECATED,
142 SerializedVarSendInput(dispatcher, var),
143 out_vector.OutParam(), &se));
147 void SetProperty(PP_Var var,
148 PP_Var name,
149 PP_Var value,
150 PP_Var* exception) {
151 ProxyAutoLock lock;
152 Dispatcher* dispatcher = CheckExceptionAndGetDispatcher(var, exception);
153 if (!dispatcher)
154 return;
156 ReceiveSerializedException se(dispatcher, exception);
157 if (!se.IsThrown()) {
158 dispatcher->Send(new PpapiHostMsg_PPBVar_SetPropertyDeprecated(
159 API_ID_PPB_VAR_DEPRECATED,
160 SerializedVarSendInput(dispatcher, var),
161 SerializedVarSendInput(dispatcher, name),
162 SerializedVarSendInput(dispatcher, value), &se));
166 void RemoveProperty(PP_Var var,
167 PP_Var name,
168 PP_Var* exception) {
169 ProxyAutoLock lock;
170 Dispatcher* dispatcher = CheckExceptionAndGetDispatcher(var, exception);
171 if (!dispatcher)
172 return;
174 ReceiveSerializedException se(dispatcher, exception);
175 PP_Bool result = PP_FALSE;
176 if (!se.IsThrown()) {
177 dispatcher->Send(new PpapiHostMsg_PPBVar_DeleteProperty(
178 API_ID_PPB_VAR_DEPRECATED,
179 SerializedVarSendInput(dispatcher, var),
180 SerializedVarSendInput(dispatcher, name), &se, &result));
184 PP_Var Call(PP_Var object,
185 PP_Var method_name,
186 uint32_t argc,
187 PP_Var* argv,
188 PP_Var* exception) {
189 ProxyAutoLock lock;
190 Dispatcher* dispatcher = CheckExceptionAndGetDispatcher(object, exception);
191 if (!dispatcher)
192 return PP_MakeUndefined();
194 ReceiveSerializedVarReturnValue result;
195 ReceiveSerializedException se(dispatcher, exception);
196 if (!se.IsThrown()) {
197 std::vector<SerializedVar> argv_vect;
198 SerializedVarSendInput::ConvertVector(dispatcher, argv, argc, &argv_vect);
200 dispatcher->Send(new PpapiHostMsg_PPBVar_CallDeprecated(
201 API_ID_PPB_VAR_DEPRECATED,
202 SerializedVarSendInput(dispatcher, object),
203 SerializedVarSendInput(dispatcher, method_name), argv_vect,
204 &se, &result));
206 return result.Return(dispatcher);
209 PP_Var Construct(PP_Var object,
210 uint32_t argc,
211 PP_Var* argv,
212 PP_Var* exception) {
213 ProxyAutoLock lock;
214 Dispatcher* dispatcher = CheckExceptionAndGetDispatcher(object, exception);
215 if (!dispatcher)
216 return PP_MakeUndefined();
218 ReceiveSerializedVarReturnValue result;
219 ReceiveSerializedException se(dispatcher, exception);
220 if (!se.IsThrown()) {
221 std::vector<SerializedVar> argv_vect;
222 SerializedVarSendInput::ConvertVector(dispatcher, argv, argc, &argv_vect);
224 dispatcher->Send(new PpapiHostMsg_PPBVar_Construct(
225 API_ID_PPB_VAR_DEPRECATED,
226 SerializedVarSendInput(dispatcher, object),
227 argv_vect, &se, &result));
229 return result.Return(dispatcher);
232 bool IsInstanceOf(PP_Var var,
233 const PPP_Class_Deprecated* ppp_class,
234 void** ppp_class_data) {
235 ProxyAutoLock lock;
236 Dispatcher* dispatcher = CheckExceptionAndGetDispatcher(var, NULL);
237 if (!dispatcher)
238 return false;
240 PP_Bool result = PP_FALSE;
241 int64 class_int = static_cast<int64>(reinterpret_cast<intptr_t>(ppp_class));
242 int64 class_data_int = 0;
243 dispatcher->Send(new PpapiHostMsg_PPBVar_IsInstanceOfDeprecated(
244 API_ID_PPB_VAR_DEPRECATED, SerializedVarSendInput(dispatcher, var),
245 class_int, &class_data_int, &result));
246 *ppp_class_data =
247 reinterpret_cast<void*>(static_cast<intptr_t>(class_data_int));
248 return PP_ToBool(result);
251 PP_Var CreateObject(PP_Instance instance,
252 const PPP_Class_Deprecated* ppp_class,
253 void* ppp_class_data) {
254 ProxyAutoLock lock;
255 Dispatcher* dispatcher = PluginDispatcher::GetForInstance(instance);
256 if (!dispatcher)
257 return PP_MakeUndefined();
259 PluginVarTracker* tracker = PluginGlobals::Get()->plugin_var_tracker();
260 if (tracker->IsPluginImplementedObjectAlive(ppp_class_data))
261 return PP_MakeUndefined(); // Object already exists with this user data.
263 ReceiveSerializedVarReturnValue result;
264 int64 class_int = static_cast<int64>(reinterpret_cast<intptr_t>(ppp_class));
265 int64 data_int =
266 static_cast<int64>(reinterpret_cast<intptr_t>(ppp_class_data));
267 dispatcher->Send(new PpapiHostMsg_PPBVar_CreateObjectDeprecated(
268 API_ID_PPB_VAR_DEPRECATED, instance, class_int, data_int,
269 &result));
270 PP_Var ret_var = result.Return(dispatcher);
272 // Register this object as being implemented by the plugin.
273 if (ret_var.type == PP_VARTYPE_OBJECT) {
274 tracker->PluginImplementedObjectCreated(instance, ret_var,
275 ppp_class, ppp_class_data);
277 return ret_var;
280 } // namespace
282 PPB_Var_Deprecated_Proxy::PPB_Var_Deprecated_Proxy(
283 Dispatcher* dispatcher)
284 : InterfaceProxy(dispatcher),
285 ppb_var_impl_(NULL),
286 task_factory_(this) {
287 if (!dispatcher->IsPlugin()) {
288 ppb_var_impl_ = static_cast<const PPB_Var_Deprecated*>(
289 dispatcher->local_get_interface()(PPB_VAR_DEPRECATED_INTERFACE));
293 PPB_Var_Deprecated_Proxy::~PPB_Var_Deprecated_Proxy() {
296 // static
297 const PPB_Var_Deprecated* PPB_Var_Deprecated_Proxy::GetProxyInterface() {
298 static const PPB_Var_Deprecated var_deprecated_interface = {
299 ppapi::PPB_Var_Shared::GetVarInterface1_0()->AddRef,
300 ppapi::PPB_Var_Shared::GetVarInterface1_0()->Release,
301 ppapi::PPB_Var_Shared::GetVarInterface1_0()->VarFromUtf8,
302 ppapi::PPB_Var_Shared::GetVarInterface1_0()->VarToUtf8,
303 &HasProperty,
304 &HasMethod,
305 &GetProperty,
306 &EnumerateProperties,
307 &SetProperty,
308 &RemoveProperty,
309 &Call,
310 &Construct,
311 &IsInstanceOf,
312 &CreateObject
314 return &var_deprecated_interface;
317 bool PPB_Var_Deprecated_Proxy::OnMessageReceived(const IPC::Message& msg) {
318 if (!dispatcher()->permissions().HasPermission(PERMISSION_DEV))
319 return false;
321 // Prevent the dispatcher from going away during a call to Call or other
322 // function that could mutate the DOM. This must happen OUTSIDE of
323 // the message handlers since the SerializedVars use the dispatcher upon
324 // return of the function (converting the SerializedVarReturnValue/OutParam
325 // to a SerializedVar in the destructor).
326 ScopedModuleReference death_grip(dispatcher());
328 bool handled = true;
329 IPC_BEGIN_MESSAGE_MAP(PPB_Var_Deprecated_Proxy, msg)
330 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_AddRefObject, OnMsgAddRefObject)
331 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_ReleaseObject, OnMsgReleaseObject)
332 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_HasProperty,
333 OnMsgHasProperty)
334 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_HasMethodDeprecated,
335 OnMsgHasMethodDeprecated)
336 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_GetProperty,
337 OnMsgGetProperty)
338 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_DeleteProperty,
339 OnMsgDeleteProperty)
340 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_EnumerateProperties,
341 OnMsgEnumerateProperties)
342 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_SetPropertyDeprecated,
343 OnMsgSetPropertyDeprecated)
344 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_CallDeprecated,
345 OnMsgCallDeprecated)
346 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_Construct,
347 OnMsgConstruct)
348 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_IsInstanceOfDeprecated,
349 OnMsgIsInstanceOfDeprecated)
350 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBVar_CreateObjectDeprecated,
351 OnMsgCreateObjectDeprecated)
352 IPC_MESSAGE_UNHANDLED(handled = false)
353 IPC_END_MESSAGE_MAP()
354 // TODO(brettw) handle bad messages!
355 return handled;
358 void PPB_Var_Deprecated_Proxy::OnMsgAddRefObject(int64 object_id) {
359 PP_Var var = { PP_VARTYPE_OBJECT };
360 var.value.as_id = object_id;
361 ppb_var_impl_->AddRef(var);
364 void PPB_Var_Deprecated_Proxy::OnMsgReleaseObject(int64 object_id) {
365 // Ok, so this is super subtle.
366 // When the browser side sends a sync IPC message that returns a var, and the
367 // plugin wants to give ownership of that var to the browser, dropping all
368 // references, it may call ReleaseObject right after returning the result.
369 // However, the IPC system doesn't enforce strict ordering of messages in that
370 // case, where a message that is set to unblock (e.g. a sync message, or in
371 // our case all messages coming from the plugin) that is sent *after* the
372 // result may be dispatched on the browser side *before* the sync send
373 // returned (see ipc_sync_channel.cc). In this case, that means it could
374 // release the object before it is AddRef'ed on the browser side.
375 // To work around this, we post a task here, that will not execute before
376 // control goes back to the main message loop, that will ensure the sync send
377 // has returned and the browser side can take its reference before we Release.
378 // Note: if the instance is gone by the time the task is executed, then it
379 // will Release the objects itself and this Release will be a NOOP (aside of a
380 // spurious warning).
381 // TODO(piman): See if we can fix the IPC code to enforce strict ordering, and
382 // then remove this.
383 PpapiGlobals::Get()->GetMainThreadMessageLoop()->PostNonNestableTask(
384 FROM_HERE,
385 RunWhileLocked(base::Bind(&PPB_Var_Deprecated_Proxy::DoReleaseObject,
386 task_factory_.GetWeakPtr(),
387 object_id)));
390 void PPB_Var_Deprecated_Proxy::OnMsgHasProperty(
391 SerializedVarReceiveInput var,
392 SerializedVarReceiveInput name,
393 SerializedVarOutParam exception,
394 PP_Bool* result) {
395 SetAllowPluginReentrancy();
396 *result = PP_FromBool(ppb_var_impl_->HasProperty(
397 var.Get(dispatcher()),
398 name.Get(dispatcher()),
399 exception.OutParam(dispatcher())));
402 void PPB_Var_Deprecated_Proxy::OnMsgHasMethodDeprecated(
403 SerializedVarReceiveInput var,
404 SerializedVarReceiveInput name,
405 SerializedVarOutParam exception,
406 PP_Bool* result) {
407 SetAllowPluginReentrancy();
408 *result = PP_FromBool(ppb_var_impl_->HasMethod(
409 var.Get(dispatcher()),
410 name.Get(dispatcher()),
411 exception.OutParam(dispatcher())));
414 void PPB_Var_Deprecated_Proxy::OnMsgGetProperty(
415 SerializedVarReceiveInput var,
416 SerializedVarReceiveInput name,
417 SerializedVarOutParam exception,
418 SerializedVarReturnValue result) {
419 SetAllowPluginReentrancy();
420 result.Return(dispatcher(), ppb_var_impl_->GetProperty(
421 var.Get(dispatcher()), name.Get(dispatcher()),
422 exception.OutParam(dispatcher())));
425 void PPB_Var_Deprecated_Proxy::OnMsgEnumerateProperties(
426 SerializedVarReceiveInput var,
427 SerializedVarVectorOutParam props,
428 SerializedVarOutParam exception) {
429 SetAllowPluginReentrancy();
430 ppb_var_impl_->GetAllPropertyNames(var.Get(dispatcher()),
431 props.CountOutParam(), props.ArrayOutParam(dispatcher()),
432 exception.OutParam(dispatcher()));
435 void PPB_Var_Deprecated_Proxy::OnMsgSetPropertyDeprecated(
436 SerializedVarReceiveInput var,
437 SerializedVarReceiveInput name,
438 SerializedVarReceiveInput value,
439 SerializedVarOutParam exception) {
440 SetAllowPluginReentrancy();
441 ppb_var_impl_->SetProperty(var.Get(dispatcher()),
442 name.Get(dispatcher()),
443 value.Get(dispatcher()),
444 exception.OutParam(dispatcher()));
447 void PPB_Var_Deprecated_Proxy::OnMsgDeleteProperty(
448 SerializedVarReceiveInput var,
449 SerializedVarReceiveInput name,
450 SerializedVarOutParam exception,
451 PP_Bool* result) {
452 SetAllowPluginReentrancy();
453 ppb_var_impl_->RemoveProperty(var.Get(dispatcher()),
454 name.Get(dispatcher()),
455 exception.OutParam(dispatcher()));
456 // This deprecated function doesn't actually return a value, but we re-use
457 // the message from the non-deprecated interface with the return value.
458 *result = PP_TRUE;
461 void PPB_Var_Deprecated_Proxy::OnMsgCallDeprecated(
462 SerializedVarReceiveInput object,
463 SerializedVarReceiveInput method_name,
464 SerializedVarVectorReceiveInput arg_vector,
465 SerializedVarOutParam exception,
466 SerializedVarReturnValue result) {
467 SetAllowPluginReentrancy();
468 uint32_t arg_count = 0;
469 PP_Var* args = arg_vector.Get(dispatcher(), &arg_count);
470 result.Return(dispatcher(), ppb_var_impl_->Call(
471 object.Get(dispatcher()),
472 method_name.Get(dispatcher()),
473 arg_count, args,
474 exception.OutParam(dispatcher())));
477 void PPB_Var_Deprecated_Proxy::OnMsgConstruct(
478 SerializedVarReceiveInput var,
479 SerializedVarVectorReceiveInput arg_vector,
480 SerializedVarOutParam exception,
481 SerializedVarReturnValue result) {
482 SetAllowPluginReentrancy();
483 uint32_t arg_count = 0;
484 PP_Var* args = arg_vector.Get(dispatcher(), &arg_count);
485 result.Return(dispatcher(), ppb_var_impl_->Construct(
486 var.Get(dispatcher()), arg_count, args,
487 exception.OutParam(dispatcher())));
490 void PPB_Var_Deprecated_Proxy::OnMsgIsInstanceOfDeprecated(
491 SerializedVarReceiveInput var,
492 int64 ppp_class,
493 int64* ppp_class_data,
494 PP_Bool* result) {
495 SetAllowPluginReentrancy();
496 *result = PPP_Class_Proxy::IsInstanceOf(ppb_var_impl_,
497 var.Get(dispatcher()),
498 ppp_class,
499 ppp_class_data);
502 void PPB_Var_Deprecated_Proxy::OnMsgCreateObjectDeprecated(
503 PP_Instance instance,
504 int64 ppp_class,
505 int64 class_data,
506 SerializedVarReturnValue result) {
507 SetAllowPluginReentrancy();
508 result.Return(dispatcher(), PPP_Class_Proxy::CreateProxiedObject(
509 ppb_var_impl_, dispatcher(), instance, ppp_class, class_data));
512 void PPB_Var_Deprecated_Proxy::SetAllowPluginReentrancy() {
513 if (dispatcher()->IsPlugin())
514 NOTREACHED();
515 else
516 static_cast<HostDispatcher*>(dispatcher())->set_allow_plugin_reentrancy();
519 void PPB_Var_Deprecated_Proxy::DoReleaseObject(int64 object_id) {
520 PP_Var var = { PP_VARTYPE_OBJECT };
521 var.value.as_id = object_id;
522 ppb_var_impl_->Release(var);
525 } // namespace proxy
526 } // namespace ppapi