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/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" 24 25 using ppapi::V8ObjectVar; 26 using ppapi::PpapiGlobals; 27 using ppapi::ScopedPPVar; 28 using ppapi::ScopedPPVarArray; 29 using ppapi::StringVar; 30 using ppapi::Var; 31 32 namespace content { 33 34 namespace { 35 36 const char kInvalidIdentifierException[] = "Error: Invalid identifier."; 37 const char kInvalidObjectException[] = "Error: Invalid object"; 38 const char kUnableToCallMethodException[] = "Error: Unable to call method"; 39 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 } 46 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; 59 } 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_; } 64 65 private: 66 V8ObjectVar* object_var_; 67 PepperPluginInstanceImpl* instance_; 68 }; 69 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; 74 } 75 if (exception) 76 *exception = ppapi::StringVar::StringToPPVar(kInvalidIdentifierException); 77 return false; 78 } 79 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; 84 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; 89 90 bool result = accessor.GetObject()->Has(v8_name); 91 if (try_catch.HasException()) 92 return false; 93 return result; 94 } 95 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; 100 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; 105 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; 111 } 112 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(); 117 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(); 122 123 ScopedPPVar result_var = try_catch.FromV8(accessor.GetObject()->Get(v8_name)); 124 if (try_catch.HasException()) 125 return PP_MakeUndefined(); 126 127 return result_var.Release(); 128 } 129 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; 137 138 PepperTryCatchVar try_catch(accessor.instance(), exception); 139 140 *properties = NULL; 141 *property_count = 0; 142 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); 152 } 153 154 size_t size = identifier_vars.size(); 155 *properties = identifier_vars.Release( 156 ScopedPPVarArray::PassPPBMemoryAllocatedArray()); 157 *property_count = size; 158 } 159 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; 167 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); 171 172 if (try_catch.HasException()) 173 return; 174 175 accessor.GetObject()->Set(v8_name, v8_value); 176 try_catch.HasException(); // Ensure an exception gets set if one occured. 177 } 178 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; 183 184 PepperTryCatchVar try_catch(accessor.instance(), exception); 185 v8::Handle<v8::Value> v8_name = try_catch.ToV8(name); 186 187 if (try_catch.HasException()) 188 return; 189 190 accessor.GetObject()->Delete(v8_name); 191 try_catch.HasException(); // Ensure an exception gets set if one occured. 192 } 193 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(); 202 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("")); 209 } 210 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(); 215 216 if (!v8_method_name->IsString()) { 217 try_catch.SetException(kUnableToCallMethodException); 218 return PP_MakeUndefined(); 219 } 220 221 v8::Handle<v8::Object> function = accessor.GetObject(); 222 v8::Handle<v8::Object> recv = 223 accessor.instance()->GetMainWorldContext()->Global(); 224 if (v8_method_name.As<v8::String>()->Length() != 0) { 225 function = function->Get(v8_method_name)->ToObject(); 226 recv = accessor.GetObject(); 227 } 228 229 if (try_catch.HasException()) 230 return PP_MakeUndefined(); 231 232 if (!function->IsFunction()) { 233 try_catch.SetException(kUnableToCallMethodException); 234 return PP_MakeUndefined(); 235 } 236 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(); 243 } 244 245 blink::WebPluginContainer* container = accessor.instance()->container(); 246 blink::WebLocalFrame* frame = NULL; 247 if (container) 248 frame = container->element().document().frame(); 249 250 if (!frame) { 251 try_catch.SetException("No frame to execute script in."); 252 return PP_MakeUndefined(); 253 } 254 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); 258 259 if (try_catch.HasException()) 260 return PP_MakeUndefined(); 261 262 return result_var.Release(); 263 } 264 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); 275 } 276 return CallDeprecatedInternal(var, method_name, argc, argv, exception); 277 } 278 279 PP_Var Construct(PP_Var var, uint32_t argc, PP_Var* argv, PP_Var* exception) { 280 // Deprecated. 281 NOTREACHED(); 282 return PP_MakeUndefined(); 283 } 284 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. 291 292 v8::HandleScope handle_scope(object->instance()->GetIsolate()); 293 v8::Handle<v8::Context> context = object->instance()->GetMainWorldContext(); 294 if (context.IsEmpty()) 295 return false; 296 v8::Context::Scope context_scope(context); 297 PluginObject* plugin_object = PluginObject::FromV8Object( 298 object->instance()->GetIsolate(), object->GetHandle()); 299 if (plugin_object && plugin_object->ppp_class() == ppp_class) { 300 if (ppp_class_data) 301 *ppp_class_data = plugin_object->ppp_class_data(); 302 return true; 303 } 304 305 return false; 306 } 307 308 PP_Var CreateObjectDeprecated(PP_Instance pp_instance, 309 const PPP_Class_Deprecated* ppp_class, 310 void* ppp_class_data) { 311 PepperPluginInstanceImpl* instance = 312 HostGlobals::Get()->GetInstance(pp_instance); 313 if (!instance) { 314 DLOG(ERROR) << "Create object passed an invalid instance."; 315 return PP_MakeNull(); 316 } 317 return PluginObject::Create(instance, ppp_class, ppp_class_data); 318 } 319 320 PP_Var CreateObjectWithModuleDeprecated(PP_Module pp_module, 321 const PPP_Class_Deprecated* ppp_class, 322 void* ppp_class_data) { 323 PluginModule* module = HostGlobals::Get()->GetModule(pp_module); 324 if (!module) 325 return PP_MakeNull(); 326 return PluginObject::Create( 327 module->GetSomeInstance(), ppp_class, ppp_class_data); 328 } 329 330 } // namespace 331 332 // static 333 const PPB_Var_Deprecated* PPB_Var_Deprecated_Impl::GetVarDeprecatedInterface() { 334 static const PPB_Var_Deprecated var_deprecated_interface = { 335 ppapi::PPB_Var_Shared::GetVarInterface1_0()->AddRef, 336 ppapi::PPB_Var_Shared::GetVarInterface1_0()->Release, 337 ppapi::PPB_Var_Shared::GetVarInterface1_0()->VarFromUtf8, 338 ppapi::PPB_Var_Shared::GetVarInterface1_0()->VarToUtf8, 339 &HasPropertyDeprecated, 340 &HasMethodDeprecated, 341 &GetProperty, 342 &EnumerateProperties, 343 &SetPropertyDeprecated, 344 &DeletePropertyDeprecated, 345 &CallDeprecated, 346 &Construct, 347 &IsInstanceOfDeprecated, 348 &CreateObjectDeprecated, 349 &CreateObjectWithModuleDeprecated, }; 350 351 return &var_deprecated_interface; 352 } 353 354 } // namespace content 355