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