PPAPI: Never re-enter JavaScript for PostMessage.
[chromium-blink-merge.git] / content / renderer / pepper / ppb_var_deprecated_impl.cc
blobd8ac026ed9d865a216ffd460c5d28201a96d86e3
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 "content/renderer/pepper/ppb_var_deprecated_impl.h"
7 #include <limits>
9 #include "content/renderer/pepper/host_globals.h"
10 #include "content/renderer/pepper/message_channel.h"
11 #include "content/renderer/pepper/pepper_plugin_instance_impl.h"
12 #include "content/renderer/pepper/pepper_try_catch.h"
13 #include "content/renderer/pepper/plugin_module.h"
14 #include "content/renderer/pepper/plugin_object.h"
15 #include "content/renderer/pepper/v8object_var.h"
16 #include "ppapi/c/dev/ppb_var_deprecated.h"
17 #include "ppapi/c/ppb_var.h"
18 #include "ppapi/shared_impl/ppb_var_shared.h"
19 #include "third_party/WebKit/public/web/WebDocument.h"
20 #include "third_party/WebKit/public/web/WebElement.h"
21 #include "third_party/WebKit/public/web/WebLocalFrame.h"
22 #include "third_party/WebKit/public/web/WebPluginContainer.h"
23 #include "third_party/WebKit/public/web/WebScopedUserGesture.h"
25 using ppapi::V8ObjectVar;
26 using ppapi::PpapiGlobals;
27 using ppapi::ScopedPPVar;
28 using ppapi::ScopedPPVarArray;
29 using ppapi::StringVar;
30 using ppapi::Var;
32 namespace content {
34 namespace {
36 const char kInvalidIdentifierException[] = "Error: Invalid identifier.";
37 const char kInvalidObjectException[] = "Error: Invalid object";
38 const char kUnableToCallMethodException[] = "Error: Unable to call method";
40 class ObjectAccessor {
41 public:
42 ObjectAccessor(PP_Var var)
43 : object_var_(V8ObjectVar::FromPPVar(var).get()),
44 instance_(object_var_ ? object_var_->instance() : NULL) {
47 // Check if the object is valid. If it isn't, set an exception and return
48 // false.
49 bool IsValid(PP_Var* exception) {
50 // If we already have an exception, then the call is invalid according to
51 // the unittests.
52 if (exception && exception->type != PP_VARTYPE_UNDEFINED)
53 return false;
54 if (instance_)
55 return true;
56 if (exception)
57 *exception = ppapi::StringVar::StringToPPVar(kInvalidObjectException);
58 return false;
60 // Lazily grab the object so that the handle is created in the current handle
61 // scope.
62 v8::Handle<v8::Object> GetObject() { return object_var_->GetHandle(); }
63 PepperPluginInstanceImpl* instance() { return instance_; }
65 private:
66 V8ObjectVar* object_var_;
67 PepperPluginInstanceImpl* instance_;
70 bool IsValidIdentifer(PP_Var identifier, PP_Var* exception) {
71 if (identifier.type == PP_VARTYPE_INT32 ||
72 identifier.type == PP_VARTYPE_STRING) {
73 return true;
75 if (exception)
76 *exception = ppapi::StringVar::StringToPPVar(kInvalidIdentifierException);
77 return false;
80 bool HasPropertyDeprecated(PP_Var var, PP_Var name, PP_Var* exception) {
81 ObjectAccessor accessor(var);
82 if (!accessor.IsValid(exception) || !IsValidIdentifer(name, exception))
83 return false;
85 PepperTryCatchVar try_catch(accessor.instance(), exception);
86 v8::Handle<v8::Value> v8_name = try_catch.ToV8(name);
87 if (try_catch.HasException())
88 return false;
90 bool result = accessor.GetObject()->Has(v8_name);
91 if (try_catch.HasException())
92 return false;
93 return result;
96 bool HasMethodDeprecated(PP_Var var, PP_Var name, PP_Var* exception) {
97 ObjectAccessor accessor(var);
98 if (!accessor.IsValid(exception) || !IsValidIdentifer(name, exception))
99 return false;
101 PepperTryCatchVar try_catch(accessor.instance(), exception);
102 v8::Handle<v8::Value> v8_name = try_catch.ToV8(name);
103 if (try_catch.HasException())
104 return false;
106 bool result = accessor.GetObject()->Has(v8_name) &&
107 accessor.GetObject()->Get(v8_name)->IsFunction();
108 if (try_catch.HasException())
109 return false;
110 return result;
113 PP_Var GetProperty(PP_Var var, PP_Var name, PP_Var* exception) {
114 ObjectAccessor accessor(var);
115 if (!accessor.IsValid(exception) || !IsValidIdentifer(name, exception))
116 return PP_MakeUndefined();
118 PepperTryCatchVar try_catch(accessor.instance(), exception);
119 v8::Handle<v8::Value> v8_name = try_catch.ToV8(name);
120 if (try_catch.HasException())
121 return PP_MakeUndefined();
123 ScopedPPVar result_var = try_catch.FromV8(accessor.GetObject()->Get(v8_name));
124 if (try_catch.HasException())
125 return PP_MakeUndefined();
127 return result_var.Release();
130 void EnumerateProperties(PP_Var var,
131 uint32_t* property_count,
132 PP_Var** properties,
133 PP_Var* exception) {
134 ObjectAccessor accessor(var);
135 if (!accessor.IsValid(exception))
136 return;
138 PepperTryCatchVar try_catch(accessor.instance(), exception);
140 *properties = NULL;
141 *property_count = 0;
143 v8::Local<v8::Array> identifiers = accessor.GetObject()->GetPropertyNames();
144 if (try_catch.HasException())
145 return;
146 ScopedPPVarArray identifier_vars(identifiers->Length());
147 for (uint32_t i = 0; i < identifiers->Length(); ++i) {
148 ScopedPPVar var = try_catch.FromV8(identifiers->Get(i));
149 if (try_catch.HasException())
150 return;
151 identifier_vars.Set(i, var);
154 size_t size = identifier_vars.size();
155 *properties = identifier_vars.Release(
156 ScopedPPVarArray::PassPPBMemoryAllocatedArray());
157 *property_count = size;
160 void SetPropertyDeprecated(PP_Var var,
161 PP_Var name,
162 PP_Var value,
163 PP_Var* exception) {
164 ObjectAccessor accessor(var);
165 if (!accessor.IsValid(exception) || !IsValidIdentifer(name, exception))
166 return;
168 PepperTryCatchVar try_catch(accessor.instance(), exception);
169 v8::Handle<v8::Value> v8_name = try_catch.ToV8(name);
170 v8::Handle<v8::Value> v8_value = try_catch.ToV8(value);
172 if (try_catch.HasException())
173 return;
175 accessor.GetObject()->Set(v8_name, v8_value);
176 try_catch.HasException(); // Ensure an exception gets set if one occured.
179 void DeletePropertyDeprecated(PP_Var var, PP_Var name, PP_Var* exception) {
180 ObjectAccessor accessor(var);
181 if (!accessor.IsValid(exception) || !IsValidIdentifer(name, exception))
182 return;
184 PepperTryCatchVar try_catch(accessor.instance(), exception);
185 v8::Handle<v8::Value> v8_name = try_catch.ToV8(name);
187 if (try_catch.HasException())
188 return;
190 accessor.GetObject()->Delete(v8_name);
191 try_catch.HasException(); // Ensure an exception gets set if one occured.
194 PP_Var CallDeprecatedInternal(PP_Var var,
195 PP_Var method_name,
196 uint32_t argc,
197 PP_Var* argv,
198 PP_Var* exception) {
199 ObjectAccessor accessor(var);
200 if (!accessor.IsValid(exception))
201 return PP_MakeUndefined();
203 // If the method name is undefined, set it to the empty string to trigger
204 // calling |var| as a function.
205 ScopedPPVar scoped_name(method_name);
206 if (method_name.type == PP_VARTYPE_UNDEFINED) {
207 scoped_name = ScopedPPVar(ScopedPPVar::PassRef(),
208 StringVar::StringToPPVar(""));
211 PepperTryCatchVar try_catch(accessor.instance(), exception);
212 v8::Handle<v8::Value> v8_method_name = try_catch.ToV8(scoped_name.get());
213 if (try_catch.HasException())
214 return PP_MakeUndefined();
216 if (!v8_method_name->IsString()) {
217 try_catch.SetException(kUnableToCallMethodException);
218 return PP_MakeUndefined();
221 v8::Handle<v8::Object> function = accessor.GetObject();
222 v8::Handle<v8::Object> recv =
223 accessor.instance()->GetContext()->Global();
224 if (v8_method_name.As<v8::String>()->Length() != 0) {
225 function = function->Get(v8_method_name)->ToObject();
226 recv = accessor.GetObject();
229 if (try_catch.HasException())
230 return PP_MakeUndefined();
232 if (!function->IsFunction()) {
233 try_catch.SetException(kUnableToCallMethodException);
234 return PP_MakeUndefined();
237 scoped_ptr<v8::Handle<v8::Value>[] > converted_args(
238 new v8::Handle<v8::Value>[argc]);
239 for (uint32_t i = 0; i < argc; ++i) {
240 converted_args[i] = try_catch.ToV8(argv[i]);
241 if (try_catch.HasException())
242 return PP_MakeUndefined();
245 blink::WebPluginContainer* container = accessor.instance()->container();
246 blink::WebLocalFrame* frame = NULL;
247 if (container)
248 frame = container->element().document().frame();
250 if (!frame) {
251 try_catch.SetException("No frame to execute script in.");
252 return PP_MakeUndefined();
255 v8::Handle<v8::Value> result = frame->callFunctionEvenIfScriptDisabled(
256 function.As<v8::Function>(), recv, argc, converted_args.get());
257 ScopedPPVar result_var = try_catch.FromV8(result);
259 if (try_catch.HasException())
260 return PP_MakeUndefined();
262 return result_var.Release();
265 PP_Var CallDeprecated(PP_Var var,
266 PP_Var method_name,
267 uint32_t argc,
268 PP_Var* argv,
269 PP_Var* exception) {
270 ObjectAccessor accessor(var);
271 if (accessor.instance() && accessor.instance()->IsProcessingUserGesture()) {
272 blink::WebScopedUserGesture user_gesture(
273 accessor.instance()->CurrentUserGestureToken());
274 return CallDeprecatedInternal(var, method_name, argc, argv, exception);
276 return CallDeprecatedInternal(var, method_name, argc, argv, exception);
279 PP_Var Construct(PP_Var var, uint32_t argc, PP_Var* argv, PP_Var* exception) {
280 // Deprecated.
281 NOTREACHED();
282 return PP_MakeUndefined();
285 bool IsInstanceOfDeprecated(PP_Var var,
286 const PPP_Class_Deprecated* ppp_class,
287 void** ppp_class_data) {
288 scoped_refptr<V8ObjectVar> object(V8ObjectVar::FromPPVar(var));
289 if (!object.get())
290 return false; // Not an object at all.
292 v8::HandleScope handle_scope(object->instance()->GetIsolate());
293 v8::Context::Scope context_scope(object->instance()->GetContext());
294 PluginObject* plugin_object = PluginObject::FromV8Object(
295 object->instance()->GetIsolate(), object->GetHandle());
296 if (plugin_object && plugin_object->ppp_class() == ppp_class) {
297 if (ppp_class_data)
298 *ppp_class_data = plugin_object->ppp_class_data();
299 return true;
302 return false;
305 PP_Var CreateObjectDeprecated(PP_Instance pp_instance,
306 const PPP_Class_Deprecated* ppp_class,
307 void* ppp_class_data) {
308 PepperPluginInstanceImpl* instance =
309 HostGlobals::Get()->GetInstance(pp_instance);
310 if (!instance) {
311 DLOG(ERROR) << "Create object passed an invalid instance.";
312 return PP_MakeNull();
314 return PluginObject::Create(instance, ppp_class, ppp_class_data);
317 PP_Var CreateObjectWithModuleDeprecated(PP_Module pp_module,
318 const PPP_Class_Deprecated* ppp_class,
319 void* ppp_class_data) {
320 PluginModule* module = HostGlobals::Get()->GetModule(pp_module);
321 if (!module)
322 return PP_MakeNull();
323 return PluginObject::Create(
324 module->GetSomeInstance(), ppp_class, ppp_class_data);
327 } // namespace
329 // static
330 const PPB_Var_Deprecated* PPB_Var_Deprecated_Impl::GetVarDeprecatedInterface() {
331 static const PPB_Var_Deprecated var_deprecated_interface = {
332 ppapi::PPB_Var_Shared::GetVarInterface1_0()->AddRef,
333 ppapi::PPB_Var_Shared::GetVarInterface1_0()->Release,
334 ppapi::PPB_Var_Shared::GetVarInterface1_0()->VarFromUtf8,
335 ppapi::PPB_Var_Shared::GetVarInterface1_0()->VarToUtf8,
336 &HasPropertyDeprecated,
337 &HasMethodDeprecated,
338 &GetProperty,
339 &EnumerateProperties,
340 &SetPropertyDeprecated,
341 &DeletePropertyDeprecated,
342 &CallDeprecated,
343 &Construct,
344 &IsInstanceOfDeprecated,
345 &CreateObjectDeprecated,
346 &CreateObjectWithModuleDeprecated, };
348 return &var_deprecated_interface;
351 } // namespace content