Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / content / renderer / pepper / ppb_var_deprecated_impl.cc
blobdd2c80bbe839235f53f32e0f88e97ba16e59e1a9
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/WebPluginScriptForbiddenScope.h"
24 #include "third_party/WebKit/public/web/WebScopedUserGesture.h"
26 using ppapi::V8ObjectVar;
27 using ppapi::PpapiGlobals;
28 using ppapi::ScopedPPVar;
29 using ppapi::ScopedPPVarArray;
30 using ppapi::StringVar;
31 using ppapi::Var;
33 namespace content {
35 namespace {
37 const char kInvalidIdentifierException[] = "Error: Invalid identifier.";
38 const char kInvalidObjectException[] = "Error: Invalid object";
39 const char kUnableToCallMethodException[] = "Error: Unable to call method";
41 class ObjectAccessor {
42 public:
43 ObjectAccessor(PP_Var var)
44 : object_var_(V8ObjectVar::FromPPVar(var).get()),
45 instance_(object_var_ ? object_var_->instance() : NULL) {
46 if (instance_) {
47 converter_.reset(new V8VarConverter(instance_->pp_instance(),
48 V8VarConverter::kAllowObjectVars));
52 // Check if the object is valid. If it isn't, set an exception and return
53 // false.
54 bool IsValid(PP_Var* exception) {
55 // If we already have an exception, then the call is invalid according to
56 // the unittests.
57 if (exception && exception->type != PP_VARTYPE_UNDEFINED)
58 return false;
59 if (instance_)
60 return !instance_->is_deleted() ||
61 !blink::WebPluginScriptForbiddenScope::isForbidden();
62 if (exception)
63 *exception = ppapi::StringVar::StringToPPVar(kInvalidObjectException);
64 return false;
66 // Lazily grab the object so that the handle is created in the current handle
67 // scope.
68 v8::Local<v8::Object> GetObject() { return object_var_->GetHandle(); }
69 PepperPluginInstanceImpl* instance() { return instance_; }
70 V8VarConverter* converter() { return converter_.get(); }
72 private:
73 V8ObjectVar* object_var_;
74 PepperPluginInstanceImpl* instance_;
75 scoped_ptr<V8VarConverter> converter_;
78 bool IsValidIdentifer(PP_Var identifier, PP_Var* exception) {
79 if (identifier.type == PP_VARTYPE_INT32 ||
80 identifier.type == PP_VARTYPE_STRING) {
81 return true;
83 if (exception)
84 *exception = ppapi::StringVar::StringToPPVar(kInvalidIdentifierException);
85 return false;
88 bool HasPropertyDeprecated(PP_Var var, PP_Var name, PP_Var* exception) {
89 ObjectAccessor accessor(var);
90 if (!accessor.IsValid(exception) || !IsValidIdentifer(name, exception))
91 return false;
93 PepperTryCatchVar try_catch(accessor.instance(), accessor.converter(),
94 exception);
95 v8::Local<v8::Value> v8_name = try_catch.ToV8(name);
96 if (try_catch.HasException())
97 return false;
99 bool result = accessor.GetObject()->Has(v8_name);
100 if (try_catch.HasException())
101 return false;
102 return result;
105 bool HasMethodDeprecated(PP_Var var, PP_Var name, PP_Var* exception) {
106 ObjectAccessor accessor(var);
107 if (!accessor.IsValid(exception) || !IsValidIdentifer(name, exception))
108 return false;
110 PepperTryCatchVar try_catch(accessor.instance(), accessor.converter(),
111 exception);
112 v8::Local<v8::Value> v8_name = try_catch.ToV8(name);
113 if (try_catch.HasException())
114 return false;
116 bool result = accessor.GetObject()->Has(v8_name) &&
117 accessor.GetObject()->Get(v8_name)->IsFunction();
118 if (try_catch.HasException())
119 return false;
120 return result;
123 PP_Var GetProperty(PP_Var var, PP_Var name, PP_Var* exception) {
124 ObjectAccessor accessor(var);
125 if (!accessor.IsValid(exception) || !IsValidIdentifer(name, exception))
126 return PP_MakeUndefined();
128 PepperTryCatchVar try_catch(accessor.instance(), accessor.converter(),
129 exception);
130 v8::Local<v8::Value> v8_name = try_catch.ToV8(name);
131 if (try_catch.HasException())
132 return PP_MakeUndefined();
134 ScopedPPVar result_var = try_catch.FromV8(accessor.GetObject()->Get(v8_name));
135 if (try_catch.HasException())
136 return PP_MakeUndefined();
138 return result_var.Release();
141 void EnumerateProperties(PP_Var var,
142 uint32_t* property_count,
143 PP_Var** properties,
144 PP_Var* exception) {
145 ObjectAccessor accessor(var);
146 if (!accessor.IsValid(exception))
147 return;
149 PepperTryCatchVar try_catch(accessor.instance(), accessor.converter(),
150 exception);
152 *properties = NULL;
153 *property_count = 0;
155 v8::Local<v8::Array> identifiers = accessor.GetObject()->GetPropertyNames();
156 if (try_catch.HasException())
157 return;
158 ScopedPPVarArray identifier_vars(identifiers->Length());
159 for (uint32_t i = 0; i < identifiers->Length(); ++i) {
160 ScopedPPVar var = try_catch.FromV8(identifiers->Get(i));
161 if (try_catch.HasException())
162 return;
163 identifier_vars.Set(i, var);
166 size_t size = identifier_vars.size();
167 *properties = identifier_vars.Release(
168 ScopedPPVarArray::PassPPBMemoryAllocatedArray());
169 *property_count = size;
172 void SetPropertyDeprecated(PP_Var var,
173 PP_Var name,
174 PP_Var value,
175 PP_Var* exception) {
176 ObjectAccessor accessor(var);
177 if (!accessor.IsValid(exception) || !IsValidIdentifer(name, exception))
178 return;
180 PepperTryCatchVar try_catch(accessor.instance(), accessor.converter(),
181 exception);
182 v8::Local<v8::Value> v8_name = try_catch.ToV8(name);
183 v8::Local<v8::Value> v8_value = try_catch.ToV8(value);
185 if (try_catch.HasException())
186 return;
188 accessor.GetObject()->Set(v8_name, v8_value);
189 try_catch.HasException(); // Ensure an exception gets set if one occured.
192 void DeletePropertyDeprecated(PP_Var var, PP_Var name, PP_Var* exception) {
193 ObjectAccessor accessor(var);
194 if (!accessor.IsValid(exception) || !IsValidIdentifer(name, exception))
195 return;
197 PepperTryCatchVar try_catch(accessor.instance(), accessor.converter(),
198 exception);
199 v8::Local<v8::Value> v8_name = try_catch.ToV8(name);
201 if (try_catch.HasException())
202 return;
204 accessor.GetObject()->Delete(v8_name);
205 try_catch.HasException(); // Ensure an exception gets set if one occured.
208 PP_Var CallDeprecatedInternal(PP_Var var,
209 PP_Var method_name,
210 uint32_t argc,
211 PP_Var* argv,
212 PP_Var* exception) {
213 ObjectAccessor accessor(var);
214 if (!accessor.IsValid(exception))
215 return PP_MakeUndefined();
217 // If the method name is undefined, set it to the empty string to trigger
218 // calling |var| as a function.
219 ScopedPPVar scoped_name(method_name);
220 if (method_name.type == PP_VARTYPE_UNDEFINED) {
221 scoped_name = ScopedPPVar(ScopedPPVar::PassRef(),
222 StringVar::StringToPPVar(""));
225 PepperTryCatchVar try_catch(accessor.instance(), accessor.converter(),
226 exception);
227 v8::Local<v8::Value> v8_method_name = try_catch.ToV8(scoped_name.get());
228 if (try_catch.HasException())
229 return PP_MakeUndefined();
231 if (!v8_method_name->IsString()) {
232 try_catch.SetException(kUnableToCallMethodException);
233 return PP_MakeUndefined();
236 v8::Local<v8::Object> function = accessor.GetObject();
237 v8::Local<v8::Object> recv =
238 accessor.instance()->GetMainWorldContext()->Global();
239 if (v8_method_name.As<v8::String>()->Length() != 0) {
240 function = function->Get(v8_method_name)
241 ->ToObject(accessor.instance()->GetIsolate());
242 recv = accessor.GetObject();
245 if (try_catch.HasException())
246 return PP_MakeUndefined();
248 if (!function->IsFunction()) {
249 try_catch.SetException(kUnableToCallMethodException);
250 return PP_MakeUndefined();
253 scoped_ptr<v8::Local<v8::Value>[] > converted_args(
254 new v8::Local<v8::Value>[argc]);
255 for (uint32_t i = 0; i < argc; ++i) {
256 converted_args[i] = try_catch.ToV8(argv[i]);
257 if (try_catch.HasException())
258 return PP_MakeUndefined();
261 blink::WebPluginContainer* container = accessor.instance()->container();
262 blink::WebLocalFrame* frame = NULL;
263 if (container)
264 frame = container->element().document().frame();
266 if (!frame) {
267 try_catch.SetException("No frame to execute script in.");
268 return PP_MakeUndefined();
271 v8::Local<v8::Value> result = frame->callFunctionEvenIfScriptDisabled(
272 function.As<v8::Function>(), recv, argc, converted_args.get());
273 ScopedPPVar result_var = try_catch.FromV8(result);
275 if (try_catch.HasException())
276 return PP_MakeUndefined();
278 return result_var.Release();
281 PP_Var CallDeprecated(PP_Var var,
282 PP_Var method_name,
283 uint32_t argc,
284 PP_Var* argv,
285 PP_Var* exception) {
286 ObjectAccessor accessor(var);
287 if (accessor.instance() && accessor.instance()->IsProcessingUserGesture()) {
288 blink::WebScopedUserGesture user_gesture(
289 accessor.instance()->CurrentUserGestureToken());
290 return CallDeprecatedInternal(var, method_name, argc, argv, exception);
292 return CallDeprecatedInternal(var, method_name, argc, argv, exception);
295 PP_Var Construct(PP_Var var, uint32_t argc, PP_Var* argv, PP_Var* exception) {
296 // Deprecated.
297 NOTREACHED();
298 return PP_MakeUndefined();
301 bool IsInstanceOfDeprecated(PP_Var var,
302 const PPP_Class_Deprecated* ppp_class,
303 void** ppp_class_data) {
304 scoped_refptr<V8ObjectVar> object(V8ObjectVar::FromPPVar(var));
305 if (!object.get())
306 return false; // Not an object at all.
308 v8::HandleScope handle_scope(object->instance()->GetIsolate());
309 v8::Local<v8::Context> context = object->instance()->GetMainWorldContext();
310 if (context.IsEmpty())
311 return false;
312 v8::Context::Scope context_scope(context);
313 PluginObject* plugin_object = PluginObject::FromV8Object(
314 object->instance()->GetIsolate(), object->GetHandle());
315 if (plugin_object && plugin_object->ppp_class() == ppp_class) {
316 if (ppp_class_data)
317 *ppp_class_data = plugin_object->ppp_class_data();
318 return true;
321 return false;
324 PP_Var CreateObjectDeprecated(PP_Instance pp_instance,
325 const PPP_Class_Deprecated* ppp_class,
326 void* ppp_class_data) {
327 PepperPluginInstanceImpl* instance =
328 HostGlobals::Get()->GetInstance(pp_instance);
329 if (!instance) {
330 DLOG(ERROR) << "Create object passed an invalid instance.";
331 return PP_MakeNull();
333 return PluginObject::Create(instance, ppp_class, ppp_class_data);
336 PP_Var CreateObjectWithModuleDeprecated(PP_Module pp_module,
337 const PPP_Class_Deprecated* ppp_class,
338 void* ppp_class_data) {
339 PluginModule* module = HostGlobals::Get()->GetModule(pp_module);
340 if (!module)
341 return PP_MakeNull();
342 return PluginObject::Create(
343 module->GetSomeInstance(), ppp_class, ppp_class_data);
346 } // namespace
348 // static
349 const PPB_Var_Deprecated* PPB_Var_Deprecated_Impl::GetVarDeprecatedInterface() {
350 static const PPB_Var_Deprecated var_deprecated_interface = {
351 ppapi::PPB_Var_Shared::GetVarInterface1_0()->AddRef,
352 ppapi::PPB_Var_Shared::GetVarInterface1_0()->Release,
353 ppapi::PPB_Var_Shared::GetVarInterface1_0()->VarFromUtf8,
354 ppapi::PPB_Var_Shared::GetVarInterface1_0()->VarToUtf8,
355 &HasPropertyDeprecated,
356 &HasMethodDeprecated,
357 &GetProperty,
358 &EnumerateProperties,
359 &SetPropertyDeprecated,
360 &DeletePropertyDeprecated,
361 &CallDeprecated,
362 &Construct,
363 &IsInstanceOfDeprecated,
364 &CreateObjectDeprecated,
365 &CreateObjectWithModuleDeprecated, };
367 return &var_deprecated_interface;
370 } // namespace content