- add sources.
[platform/framework/web/crosswalk.git] / src / content / renderer / pepper / ppb_var_deprecated_impl.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 "content/renderer/pepper/ppb_var_deprecated_impl.h"
6
7 #include <limits>
8
9 #include "content/renderer/pepper/common.h"
10 #include "content/renderer/pepper/host_globals.h"
11 #include "content/renderer/pepper/npapi_glue.h"
12 #include "content/renderer/pepper/npobject_var.h"
13 #include "content/renderer/pepper/pepper_plugin_instance_impl.h"
14 #include "content/renderer/pepper/plugin_module.h"
15 #include "content/renderer/pepper/plugin_object.h"
16 #include "ppapi/c/dev/ppb_var_deprecated.h"
17 #include "ppapi/c/ppb_var.h"
18 #include "ppapi/c/pp_var.h"
19 #include "ppapi/shared_impl/ppb_var_shared.h"
20 #include "third_party/WebKit/public/web/WebBindings.h"
21 #include "third_party/WebKit/public/web/WebScopedUserGesture.h"
22
23 using ppapi::NPObjectVar;
24 using ppapi::PpapiGlobals;
25 using ppapi::StringVar;
26 using ppapi::Var;
27 using WebKit::WebBindings;
28
29 namespace content {
30
31 namespace {
32
33 const char kInvalidObjectException[] = "Error: Invalid object";
34 const char kInvalidPropertyException[] = "Error: Invalid property";
35 const char kInvalidValueException[] = "Error: Invalid value";
36 const char kUnableToGetPropertyException[] = "Error: Unable to get property";
37 const char kUnableToSetPropertyException[] = "Error: Unable to set property";
38 const char kUnableToRemovePropertyException[] =
39     "Error: Unable to remove property";
40 const char kUnableToGetAllPropertiesException[] =
41     "Error: Unable to get all properties";
42 const char kUnableToCallMethodException[] = "Error: Unable to call method";
43 const char kUnableToConstructException[] = "Error: Unable to construct";
44
45 // ---------------------------------------------------------------------------
46 // Utilities
47
48 // Converts the given PP_Var to an NPVariant, returning true on success.
49 // False means that the given variant is invalid. In this case, the result
50 // NPVariant will be set to a void one.
51 //
52 // The contents of the PP_Var will NOT be copied, so you need to ensure that
53 // the PP_Var remains valid while the resultant NPVariant is in use.
54 bool PPVarToNPVariantNoCopy(PP_Var var, NPVariant* result) {
55   switch (var.type) {
56     case PP_VARTYPE_UNDEFINED:
57       VOID_TO_NPVARIANT(*result);
58       break;
59     case PP_VARTYPE_NULL:
60       NULL_TO_NPVARIANT(*result);
61       break;
62     case PP_VARTYPE_BOOL:
63       BOOLEAN_TO_NPVARIANT(var.value.as_bool, *result);
64       break;
65     case PP_VARTYPE_INT32:
66       INT32_TO_NPVARIANT(var.value.as_int, *result);
67       break;
68     case PP_VARTYPE_DOUBLE:
69       DOUBLE_TO_NPVARIANT(var.value.as_double, *result);
70       break;
71     case PP_VARTYPE_STRING: {
72       StringVar* string = StringVar::FromPPVar(var);
73       if (!string) {
74         VOID_TO_NPVARIANT(*result);
75         return false;
76       }
77       const std::string& value = string->value();
78       STRINGN_TO_NPVARIANT(value.c_str(), value.size(), *result);
79       break;
80     }
81     case PP_VARTYPE_OBJECT: {
82       scoped_refptr<NPObjectVar> object(NPObjectVar::FromPPVar(var));
83       if (!object.get()) {
84         VOID_TO_NPVARIANT(*result);
85         return false;
86       }
87       OBJECT_TO_NPVARIANT(object->np_object(), *result);
88       break;
89     }
90     default:
91       VOID_TO_NPVARIANT(*result);
92       return false;
93   }
94   return true;
95 }
96
97 // ObjectAccessorTryCatch ------------------------------------------------------
98
99 // Automatically sets up a TryCatch for accessing the object identified by the
100 // given PP_Var. The module from the object will be used for the exception
101 // strings generated by the TryCatch.
102 //
103 // This will automatically retrieve the ObjectVar from the object and throw
104 // an exception if it's invalid. At the end of construction, if there is no
105 // exception, you know that there is no previously set exception, that the
106 // object passed in is valid and ready to use (via the object() getter), and
107 // that the TryCatch's pp_module() getter is also set up properly and ready to
108 // use.
109 class ObjectAccessorTryCatch : public TryCatch {
110  public:
111   ObjectAccessorTryCatch(PP_Var object, PP_Var* exception)
112       : TryCatch(exception),
113         object_(NPObjectVar::FromPPVar(object)) {
114     if (!object_.get()) {
115       SetException(kInvalidObjectException);
116     }
117   }
118
119   NPObjectVar* object() { return object_.get(); }
120
121   PepperPluginInstanceImpl* GetPluginInstance() {
122     return HostGlobals::Get()->GetInstance(object()->pp_instance());
123   }
124
125  protected:
126   scoped_refptr<NPObjectVar> object_;
127
128   DISALLOW_COPY_AND_ASSIGN(ObjectAccessorTryCatch);
129 };
130
131 // ObjectAccessiorWithIdentifierTryCatch ---------------------------------------
132
133 // Automatically sets up a TryCatch for accessing the identifier on the given
134 // object. This just extends ObjectAccessorTryCatch to additionally convert
135 // the given identifier to an NPIdentifier and validate it, throwing an
136 // exception if it's invalid.
137 //
138 // At the end of construction, if there is no exception, you know that there is
139 // no previously set exception, that the object passed in is valid and ready to
140 // use (via the object() getter), that the identifier is valid and ready to
141 // use (via the identifier() getter), and that the TryCatch's pp_module() getter
142 // is also set up properly and ready to use.
143 class ObjectAccessorWithIdentifierTryCatch : public ObjectAccessorTryCatch {
144  public:
145   ObjectAccessorWithIdentifierTryCatch(PP_Var object,
146                                        PP_Var identifier,
147                                        PP_Var* exception)
148       : ObjectAccessorTryCatch(object, exception),
149         identifier_(0) {
150     if (!has_exception()) {
151       identifier_ = PPVarToNPIdentifier(identifier);
152       if (!identifier_)
153         SetException(kInvalidPropertyException);
154     }
155   }
156
157   NPIdentifier identifier() const { return identifier_; }
158
159  private:
160   NPIdentifier identifier_;
161
162   DISALLOW_COPY_AND_ASSIGN(ObjectAccessorWithIdentifierTryCatch);
163 };
164
165 PP_Bool HasProperty(PP_Var var,
166                     PP_Var name,
167                     PP_Var* exception) {
168   ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception);
169   if (accessor.has_exception())
170     return PP_FALSE;
171   return BoolToPPBool(WebBindings::hasProperty(NULL,
172                                                accessor.object()->np_object(),
173                                                accessor.identifier()));
174 }
175
176 bool HasPropertyDeprecated(PP_Var var,
177                            PP_Var name,
178                            PP_Var* exception) {
179   return PPBoolToBool(HasProperty(var, name, exception));
180 }
181
182 bool HasMethodDeprecated(PP_Var var,
183                          PP_Var name,
184                          PP_Var* exception) {
185   ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception);
186   if (accessor.has_exception())
187     return false;
188   return WebBindings::hasMethod(NULL, accessor.object()->np_object(),
189                                 accessor.identifier());
190 }
191
192 PP_Var GetProperty(PP_Var var,
193                    PP_Var name,
194                    PP_Var* exception) {
195   ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception);
196   if (accessor.has_exception())
197     return PP_MakeUndefined();
198
199   NPVariant result;
200   if (!WebBindings::getProperty(NULL, accessor.object()->np_object(),
201                                 accessor.identifier(), &result)) {
202     // An exception may have been raised.
203     accessor.SetException(kUnableToGetPropertyException);
204     return PP_MakeUndefined();
205   }
206
207   PP_Var ret = NPVariantToPPVar(accessor.GetPluginInstance(), &result);
208   WebBindings::releaseVariantValue(&result);
209   return ret;
210 }
211
212 void EnumerateProperties(PP_Var var,
213                          uint32_t* property_count,
214                          PP_Var** properties,
215                          PP_Var* exception) {
216   *properties = NULL;
217   *property_count = 0;
218
219   ObjectAccessorTryCatch accessor(var, exception);
220   if (accessor.has_exception())
221     return;
222
223   NPIdentifier* identifiers = NULL;
224   uint32_t count = 0;
225   if (!WebBindings::enumerate(NULL, accessor.object()->np_object(),
226                               &identifiers, &count)) {
227     accessor.SetException(kUnableToGetAllPropertiesException);
228     return;
229   }
230
231   if (count == 0)
232     return;
233
234   *property_count = count;
235   *properties = static_cast<PP_Var*>(malloc(sizeof(PP_Var) * count));
236   for (uint32_t i = 0; i < count; ++i) {
237     (*properties)[i] = NPIdentifierToPPVar(identifiers[i]);
238   }
239   free(identifiers);
240 }
241
242 void SetPropertyDeprecated(PP_Var var,
243                            PP_Var name,
244                            PP_Var value,
245                            PP_Var* exception) {
246   ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception);
247   if (accessor.has_exception())
248     return;
249
250   NPVariant variant;
251   if (!PPVarToNPVariantNoCopy(value, &variant)) {
252     accessor.SetException(kInvalidValueException);
253     return;
254   }
255   if (!WebBindings::setProperty(NULL, accessor.object()->np_object(),
256                                 accessor.identifier(), &variant))
257     accessor.SetException(kUnableToSetPropertyException);
258 }
259
260 void DeletePropertyDeprecated(PP_Var var,
261                               PP_Var name,
262                               PP_Var* exception) {
263   ObjectAccessorWithIdentifierTryCatch accessor(var, name, exception);
264   if (accessor.has_exception())
265     return;
266
267   if (!WebBindings::removeProperty(NULL, accessor.object()->np_object(),
268                                    accessor.identifier()))
269     accessor.SetException(kUnableToRemovePropertyException);
270 }
271
272 PP_Var InternalCallDeprecated(ObjectAccessorTryCatch* accessor,
273                               PP_Var method_name,
274                               uint32_t argc,
275                               PP_Var* argv,
276                               PP_Var* exception) {
277   NPIdentifier identifier;
278   if (method_name.type == PP_VARTYPE_UNDEFINED) {
279     identifier = NULL;
280   } else if (method_name.type == PP_VARTYPE_STRING) {
281     // Specifically allow only string functions to be called.
282     identifier = PPVarToNPIdentifier(method_name);
283     if (!identifier) {
284       accessor->SetException(kInvalidPropertyException);
285       return PP_MakeUndefined();
286     }
287   } else {
288     accessor->SetException(kInvalidPropertyException);
289     return PP_MakeUndefined();
290   }
291
292   scoped_ptr<NPVariant[]> args;
293   if (argc) {
294     args.reset(new NPVariant[argc]);
295     for (uint32_t i = 0; i < argc; ++i) {
296       if (!PPVarToNPVariantNoCopy(argv[i], &args[i])) {
297         // This argument was invalid, throw an exception & give up.
298         accessor->SetException(kInvalidValueException);
299         return PP_MakeUndefined();
300       }
301     }
302   }
303
304   bool ok;
305
306   NPVariant result;
307   if (identifier) {
308     ok = WebBindings::invoke(NULL, accessor->object()->np_object(),
309                              identifier, args.get(), argc, &result);
310   } else {
311     ok = WebBindings::invokeDefault(NULL, accessor->object()->np_object(),
312                                     args.get(), argc, &result);
313   }
314
315   if (!ok) {
316     // An exception may have been raised.
317     accessor->SetException(kUnableToCallMethodException);
318     return PP_MakeUndefined();
319   }
320
321   PP_Var ret = NPVariantToPPVar(accessor->GetPluginInstance(), &result);
322   WebBindings::releaseVariantValue(&result);
323   return ret;
324 }
325
326 PP_Var CallDeprecated(PP_Var var,
327                       PP_Var method_name,
328                       uint32_t argc,
329                       PP_Var* argv,
330                       PP_Var* exception) {
331   ObjectAccessorTryCatch accessor(var, exception);
332   if (accessor.has_exception())
333     return PP_MakeUndefined();
334   PepperPluginInstanceImpl* plugin = accessor.GetPluginInstance();
335   if (plugin && plugin->IsProcessingUserGesture()) {
336     WebKit::WebScopedUserGesture user_gesture(
337         plugin->CurrentUserGestureToken());
338     return InternalCallDeprecated(&accessor, method_name, argc, argv,
339                                   exception);
340   }
341   return InternalCallDeprecated(&accessor, method_name, argc, argv, exception);
342 }
343
344 PP_Var Construct(PP_Var var,
345                  uint32_t argc,
346                  PP_Var* argv,
347                  PP_Var* exception) {
348   ObjectAccessorTryCatch accessor(var, exception);
349   if (accessor.has_exception())
350     return PP_MakeUndefined();
351
352   scoped_ptr<NPVariant[]> args;
353   if (argc) {
354     args.reset(new NPVariant[argc]);
355     for (uint32_t i = 0; i < argc; ++i) {
356       if (!PPVarToNPVariantNoCopy(argv[i], &args[i])) {
357         // This argument was invalid, throw an exception & give up.
358         accessor.SetException(kInvalidValueException);
359         return PP_MakeUndefined();
360       }
361     }
362   }
363
364   NPVariant result;
365   if (!WebBindings::construct(NULL, accessor.object()->np_object(),
366                               args.get(), argc, &result)) {
367     // An exception may have been raised.
368     accessor.SetException(kUnableToConstructException);
369     return PP_MakeUndefined();
370   }
371
372   PP_Var ret = NPVariantToPPVar(accessor.GetPluginInstance(), &result);
373   WebBindings::releaseVariantValue(&result);
374   return ret;
375 }
376
377 bool IsInstanceOfDeprecated(PP_Var var,
378                             const PPP_Class_Deprecated* ppp_class,
379                             void** ppp_class_data) {
380   scoped_refptr<NPObjectVar> object(NPObjectVar::FromPPVar(var));
381   if (!object.get())
382     return false;  // Not an object at all.
383
384   return PluginObject::IsInstanceOf(object->np_object(),
385                                     ppp_class, ppp_class_data);
386 }
387
388 PP_Var CreateObjectDeprecated(PP_Instance pp_instance,
389                               const PPP_Class_Deprecated* ppp_class,
390                               void* ppp_class_data) {
391   PepperPluginInstanceImpl* instance =
392       HostGlobals::Get()->GetInstance(pp_instance);
393   if (!instance) {
394     DLOG(ERROR) << "Create object passed an invalid instance.";
395     return PP_MakeNull();
396   }
397   return PluginObject::Create(instance, ppp_class, ppp_class_data);
398 }
399
400 PP_Var CreateObjectWithModuleDeprecated(PP_Module pp_module,
401                                         const PPP_Class_Deprecated* ppp_class,
402                                         void* ppp_class_data) {
403   PluginModule* module = HostGlobals::Get()->GetModule(pp_module);
404   if (!module)
405     return PP_MakeNull();
406   return PluginObject::Create(module->GetSomeInstance(),
407                               ppp_class, ppp_class_data);
408 }
409
410 }  // namespace
411
412 // static
413 const PPB_Var_Deprecated* PPB_Var_Deprecated_Impl::GetVarDeprecatedInterface() {
414   static const PPB_Var_Deprecated var_deprecated_interface = {
415     ppapi::PPB_Var_Shared::GetVarInterface1_0()->AddRef,
416     ppapi::PPB_Var_Shared::GetVarInterface1_0()->Release,
417     ppapi::PPB_Var_Shared::GetVarInterface1_0()->VarFromUtf8,
418     ppapi::PPB_Var_Shared::GetVarInterface1_0()->VarToUtf8,
419     &HasPropertyDeprecated,
420     &HasMethodDeprecated,
421     &GetProperty,
422     &EnumerateProperties,
423     &SetPropertyDeprecated,
424     &DeletePropertyDeprecated,
425     &CallDeprecated,
426     &Construct,
427     &IsInstanceOfDeprecated,
428     &CreateObjectDeprecated,
429     &CreateObjectWithModuleDeprecated,
430   };
431
432   return &var_deprecated_interface;
433 }
434
435 }  // namespace content
436