Re-subimission of https://codereview.chromium.org/1041213003/
[chromium-blink-merge.git] / content / renderer / pepper / ppb_var_deprecated_impl.cc
blob589981cfb9c4ca82d7b31a32e0d9c4a03407730f
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) {
45 if (instance_) {
46 converter_.reset(new V8VarConverter(instance_->pp_instance(),
47 V8VarConverter::kAllowObjectVars));
51 // Check if the object is valid. If it isn't, set an exception and return
52 // false.
53 bool IsValid(PP_Var* exception) {
54 // If we already have an exception, then the call is invalid according to
55 // the unittests.
56 if (exception && exception->type != PP_VARTYPE_UNDEFINED)
57 return false;
58 if (instance_)
59 return true;
60 if (exception)
61 *exception = ppapi::StringVar::StringToPPVar(kInvalidObjectException);
62 return false;
64 // Lazily grab the object so that the handle is created in the current handle
65 // scope.
66 v8::Handle<v8::Object> GetObject() { return object_var_->GetHandle(); }
67 PepperPluginInstanceImpl* instance() { return instance_; }
68 V8VarConverter* converter() { return converter_.get(); }
70 private:
71 V8ObjectVar* object_var_;
72 PepperPluginInstanceImpl* instance_;
73 scoped_ptr<V8VarConverter> converter_;
76 bool IsValidIdentifer(PP_Var identifier, PP_Var* exception) {
77 if (identifier.type == PP_VARTYPE_INT32 ||
78 identifier.type == PP_VARTYPE_STRING) {
79 return true;
81 if (exception)
82 *exception = ppapi::StringVar::StringToPPVar(kInvalidIdentifierException);
83 return false;
86 bool HasPropertyDeprecated(PP_Var var, PP_Var name, PP_Var* exception) {
87 ObjectAccessor accessor(var);
88 if (!accessor.IsValid(exception) || !IsValidIdentifer(name, exception))
89 return false;
91 PepperTryCatchVar try_catch(accessor.instance(), accessor.converter(),
92 exception);
93 v8::Handle<v8::Value> v8_name = try_catch.ToV8(name);
94 if (try_catch.HasException())
95 return false;
97 bool result = accessor.GetObject()->Has(v8_name);
98 if (try_catch.HasException())
99 return false;
100 return result;
103 bool HasMethodDeprecated(PP_Var var, PP_Var name, PP_Var* exception) {
104 ObjectAccessor accessor(var);
105 if (!accessor.IsValid(exception) || !IsValidIdentifer(name, exception))
106 return false;
108 PepperTryCatchVar try_catch(accessor.instance(), accessor.converter(),
109 exception);
110 v8::Handle<v8::Value> v8_name = try_catch.ToV8(name);
111 if (try_catch.HasException())
112 return false;
114 bool result = accessor.GetObject()->Has(v8_name) &&
115 accessor.GetObject()->Get(v8_name)->IsFunction();
116 if (try_catch.HasException())
117 return false;
118 return result;
121 PP_Var GetProperty(PP_Var var, PP_Var name, PP_Var* exception) {
122 ObjectAccessor accessor(var);
123 if (!accessor.IsValid(exception) || !IsValidIdentifer(name, exception))
124 return PP_MakeUndefined();
126 PepperTryCatchVar try_catch(accessor.instance(), accessor.converter(),
127 exception);
128 v8::Handle<v8::Value> v8_name = try_catch.ToV8(name);
129 if (try_catch.HasException())
130 return PP_MakeUndefined();
132 ScopedPPVar result_var = try_catch.FromV8(accessor.GetObject()->Get(v8_name));
133 if (try_catch.HasException())
134 return PP_MakeUndefined();
136 return result_var.Release();
139 void EnumerateProperties(PP_Var var,
140 uint32_t* property_count,
141 PP_Var** properties,
142 PP_Var* exception) {
143 ObjectAccessor accessor(var);
144 if (!accessor.IsValid(exception))
145 return;
147 PepperTryCatchVar try_catch(accessor.instance(), accessor.converter(),
148 exception);
150 *properties = NULL;
151 *property_count = 0;
153 v8::Local<v8::Array> identifiers = accessor.GetObject()->GetPropertyNames();
154 if (try_catch.HasException())
155 return;
156 ScopedPPVarArray identifier_vars(identifiers->Length());
157 for (uint32_t i = 0; i < identifiers->Length(); ++i) {
158 ScopedPPVar var = try_catch.FromV8(identifiers->Get(i));
159 if (try_catch.HasException())
160 return;
161 identifier_vars.Set(i, var);
164 size_t size = identifier_vars.size();
165 *properties = identifier_vars.Release(
166 ScopedPPVarArray::PassPPBMemoryAllocatedArray());
167 *property_count = size;
170 void SetPropertyDeprecated(PP_Var var,
171 PP_Var name,
172 PP_Var value,
173 PP_Var* exception) {
174 ObjectAccessor accessor(var);
175 if (!accessor.IsValid(exception) || !IsValidIdentifer(name, exception))
176 return;
178 PepperTryCatchVar try_catch(accessor.instance(), accessor.converter(),
179 exception);
180 v8::Handle<v8::Value> v8_name = try_catch.ToV8(name);
181 v8::Handle<v8::Value> v8_value = try_catch.ToV8(value);
183 if (try_catch.HasException())
184 return;
186 accessor.GetObject()->Set(v8_name, v8_value);
187 try_catch.HasException(); // Ensure an exception gets set if one occured.
190 void DeletePropertyDeprecated(PP_Var var, PP_Var name, PP_Var* exception) {
191 ObjectAccessor accessor(var);
192 if (!accessor.IsValid(exception) || !IsValidIdentifer(name, exception))
193 return;
195 PepperTryCatchVar try_catch(accessor.instance(), accessor.converter(),
196 exception);
197 v8::Handle<v8::Value> v8_name = try_catch.ToV8(name);
199 if (try_catch.HasException())
200 return;
202 accessor.GetObject()->Delete(v8_name);
203 try_catch.HasException(); // Ensure an exception gets set if one occured.
206 PP_Var CallDeprecatedInternal(PP_Var var,
207 PP_Var method_name,
208 uint32_t argc,
209 PP_Var* argv,
210 PP_Var* exception) {
211 ObjectAccessor accessor(var);
212 if (!accessor.IsValid(exception))
213 return PP_MakeUndefined();
215 // If the method name is undefined, set it to the empty string to trigger
216 // calling |var| as a function.
217 ScopedPPVar scoped_name(method_name);
218 if (method_name.type == PP_VARTYPE_UNDEFINED) {
219 scoped_name = ScopedPPVar(ScopedPPVar::PassRef(),
220 StringVar::StringToPPVar(""));
223 PepperTryCatchVar try_catch(accessor.instance(), accessor.converter(),
224 exception);
225 v8::Handle<v8::Value> v8_method_name = try_catch.ToV8(scoped_name.get());
226 if (try_catch.HasException())
227 return PP_MakeUndefined();
229 if (!v8_method_name->IsString()) {
230 try_catch.SetException(kUnableToCallMethodException);
231 return PP_MakeUndefined();
234 v8::Handle<v8::Object> function = accessor.GetObject();
235 v8::Handle<v8::Object> recv =
236 accessor.instance()->GetMainWorldContext()->Global();
237 if (v8_method_name.As<v8::String>()->Length() != 0) {
238 function = function->Get(v8_method_name)
239 ->ToObject(accessor.instance()->GetIsolate());
240 recv = accessor.GetObject();
243 if (try_catch.HasException())
244 return PP_MakeUndefined();
246 if (!function->IsFunction()) {
247 try_catch.SetException(kUnableToCallMethodException);
248 return PP_MakeUndefined();
251 scoped_ptr<v8::Handle<v8::Value>[] > converted_args(
252 new v8::Handle<v8::Value>[argc]);
253 for (uint32_t i = 0; i < argc; ++i) {
254 converted_args[i] = try_catch.ToV8(argv[i]);
255 if (try_catch.HasException())
256 return PP_MakeUndefined();
259 blink::WebPluginContainer* container = accessor.instance()->container();
260 blink::WebLocalFrame* frame = NULL;
261 if (container)
262 frame = container->element().document().frame();
264 if (!frame) {
265 try_catch.SetException("No frame to execute script in.");
266 return PP_MakeUndefined();
269 v8::Handle<v8::Value> result = frame->callFunctionEvenIfScriptDisabled(
270 function.As<v8::Function>(), recv, argc, converted_args.get());
271 ScopedPPVar result_var = try_catch.FromV8(result);
273 if (try_catch.HasException())
274 return PP_MakeUndefined();
276 return result_var.Release();
279 PP_Var CallDeprecated(PP_Var var,
280 PP_Var method_name,
281 uint32_t argc,
282 PP_Var* argv,
283 PP_Var* exception) {
284 ObjectAccessor accessor(var);
285 if (accessor.instance() && accessor.instance()->IsProcessingUserGesture()) {
286 blink::WebScopedUserGesture user_gesture(
287 accessor.instance()->CurrentUserGestureToken());
288 return CallDeprecatedInternal(var, method_name, argc, argv, exception);
290 return CallDeprecatedInternal(var, method_name, argc, argv, exception);
293 PP_Var Construct(PP_Var var, uint32_t argc, PP_Var* argv, PP_Var* exception) {
294 // Deprecated.
295 NOTREACHED();
296 return PP_MakeUndefined();
299 bool IsInstanceOfDeprecated(PP_Var var,
300 const PPP_Class_Deprecated* ppp_class,
301 void** ppp_class_data) {
302 scoped_refptr<V8ObjectVar> object(V8ObjectVar::FromPPVar(var));
303 if (!object.get())
304 return false; // Not an object at all.
306 v8::HandleScope handle_scope(object->instance()->GetIsolate());
307 v8::Handle<v8::Context> context = object->instance()->GetMainWorldContext();
308 if (context.IsEmpty())
309 return false;
310 v8::Context::Scope context_scope(context);
311 PluginObject* plugin_object = PluginObject::FromV8Object(
312 object->instance()->GetIsolate(), object->GetHandle());
313 if (plugin_object && plugin_object->ppp_class() == ppp_class) {
314 if (ppp_class_data)
315 *ppp_class_data = plugin_object->ppp_class_data();
316 return true;
319 return false;
322 PP_Var CreateObjectDeprecated(PP_Instance pp_instance,
323 const PPP_Class_Deprecated* ppp_class,
324 void* ppp_class_data) {
325 PepperPluginInstanceImpl* instance =
326 HostGlobals::Get()->GetInstance(pp_instance);
327 if (!instance) {
328 DLOG(ERROR) << "Create object passed an invalid instance.";
329 return PP_MakeNull();
331 return PluginObject::Create(instance, ppp_class, ppp_class_data);
334 PP_Var CreateObjectWithModuleDeprecated(PP_Module pp_module,
335 const PPP_Class_Deprecated* ppp_class,
336 void* ppp_class_data) {
337 PluginModule* module = HostGlobals::Get()->GetModule(pp_module);
338 if (!module)
339 return PP_MakeNull();
340 return PluginObject::Create(
341 module->GetSomeInstance(), ppp_class, ppp_class_data);
344 } // namespace
346 // static
347 const PPB_Var_Deprecated* PPB_Var_Deprecated_Impl::GetVarDeprecatedInterface() {
348 static const PPB_Var_Deprecated var_deprecated_interface = {
349 ppapi::PPB_Var_Shared::GetVarInterface1_0()->AddRef,
350 ppapi::PPB_Var_Shared::GetVarInterface1_0()->Release,
351 ppapi::PPB_Var_Shared::GetVarInterface1_0()->VarFromUtf8,
352 ppapi::PPB_Var_Shared::GetVarInterface1_0()->VarToUtf8,
353 &HasPropertyDeprecated,
354 &HasMethodDeprecated,
355 &GetProperty,
356 &EnumerateProperties,
357 &SetPropertyDeprecated,
358 &DeletePropertyDeprecated,
359 &CallDeprecated,
360 &Construct,
361 &IsInstanceOfDeprecated,
362 &CreateObjectDeprecated,
363 &CreateObjectWithModuleDeprecated, };
365 return &var_deprecated_interface;
368 } // namespace content