1 // Copyright (c) 2011 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/plugin_object.h" 6 7 #include "base/bind.h" 8 #include "base/logging.h" 9 #include "base/memory/ref_counted.h" 10 #include "base/memory/scoped_ptr.h" 11 #include "base/strings/string_number_conversions.h" 12 #include "base/strings/string_util.h" 13 #include "content/renderer/pepper/pepper_plugin_instance_impl.h" 14 #include "content/renderer/pepper/pepper_try_catch.h" 15 #include "content/renderer/pepper/plugin_module.h" 16 #include "content/renderer/pepper/v8_var_converter.h" 17 #include "gin/arguments.h" 18 #include "gin/converter.h" 19 #include "gin/function_template.h" 20 #include "gin/handle.h" 21 #include "gin/interceptor.h" 22 #include "gin/object_template_builder.h" 23 #include "gin/public/gin_embedders.h" 24 #include "ppapi/c/dev/ppb_var_deprecated.h" 25 #include "ppapi/c/dev/ppp_class_deprecated.h" 26 #include "ppapi/c/pp_resource.h" 27 #include "ppapi/c/pp_var.h" 28 #include "ppapi/shared_impl/ppapi_globals.h" 29 #include "ppapi/shared_impl/resource_tracker.h" 30 #include "ppapi/shared_impl/var.h" 31 #include "ppapi/shared_impl/var_tracker.h" 32 33 using ppapi::PpapiGlobals; 34 using ppapi::ScopedPPVar; 35 using ppapi::ScopedPPVarArray; 36 using ppapi::StringVar; 37 using ppapi::Var; 38 39 namespace content { 40 41 namespace { 42 43 const char kInvalidValueException[] = "Error: Invalid value"; 44 45 } // namespace 46 47 // PluginObject ---------------------------------------------------------------- 48 49 PluginObject::~PluginObject() { 50 if (instance_) { 51 ppp_class_->Deallocate(ppp_class_data_); 52 instance_->RemovePluginObject(this); 53 } 54 } 55 56 // static 57 gin::WrapperInfo PluginObject::kWrapperInfo = {gin::kEmbedderNativeGin}; 58 59 // static 60 PluginObject* PluginObject::FromV8Object(v8::Isolate* isolate, 61 v8::Handle<v8::Object> v8_object) { 62 PluginObject* plugin_object; 63 if (!v8_object.IsEmpty() && 64 gin::ConvertFromV8(isolate, v8_object, &plugin_object)) { 65 return plugin_object; 66 } 67 return NULL; 68 } 69 70 // static 71 PP_Var PluginObject::Create(PepperPluginInstanceImpl* instance, 72 const PPP_Class_Deprecated* ppp_class, 73 void* ppp_class_data) { 74 PepperTryCatchVar try_catch(instance, NULL); 75 gin::Handle<PluginObject> object = 76 gin::CreateHandle(instance->GetIsolate(), 77 new PluginObject(instance, ppp_class, ppp_class_data)); 78 ScopedPPVar result = try_catch.FromV8(object.ToV8()); 79 DCHECK(!try_catch.HasException()); 80 return result.Release(); 81 } 82 83 v8::Local<v8::Value> PluginObject::GetNamedProperty( 84 v8::Isolate* isolate, 85 const std::string& identifier) { 86 ScopedPPVar identifier_var(ScopedPPVar::PassRef(), 87 StringVar::StringToPPVar(identifier)); 88 return GetPropertyOrMethod(instance_->GetIsolate(), identifier_var.get()); 89 } 90 91 bool PluginObject::SetNamedProperty(v8::Isolate* isolate, 92 const std::string& identifier, 93 v8::Local<v8::Value> value) { 94 if (!instance_) 95 return false; 96 ScopedPPVar identifier_var(ScopedPPVar::PassRef(), 97 StringVar::StringToPPVar(identifier)); 98 PepperTryCatchV8 try_catch(instance_, V8VarConverter::kAllowObjectVars, 99 isolate); 100 101 bool has_property = 102 ppp_class_->HasProperty(ppp_class_data_, identifier_var.get(), 103 try_catch.exception()); 104 if (try_catch.ThrowException()) 105 return false; 106 107 if (!has_property) 108 return false; 109 110 ScopedPPVar var = try_catch.FromV8(value); 111 if (try_catch.ThrowException()) 112 return false; 113 114 ppp_class_->SetProperty(ppp_class_data_, identifier_var.get(), var.get(), 115 try_catch.exception()); 116 117 // If the plugin threw an exception, then throw a V8 version of it to 118 // JavaScript. Either way, return true, because we successfully dispatched 119 // the call to the plugin. 120 try_catch.ThrowException(); 121 return true; 122 } 123 124 std::vector<std::string> PluginObject::EnumerateNamedProperties( 125 v8::Isolate* isolate) { 126 std::vector<std::string> result; 127 if (!instance_) 128 return result; 129 130 PepperTryCatchV8 try_catch(instance_, V8VarConverter::kAllowObjectVars, 131 isolate); 132 133 PP_Var* name_vars; 134 uint32_t count = 0; 135 ppp_class_->GetAllPropertyNames(ppp_class_data_, &count, &name_vars, 136 try_catch.exception()); 137 ScopedPPVarArray scoped_name_vars( 138 ScopedPPVarArray::PassPPBMemoryAllocatedArray(), name_vars, count); 139 140 if (try_catch.ThrowException()) 141 return result; 142 143 for (uint32_t i = 0; i < count; ++i) { 144 StringVar* string_var = StringVar::FromPPVar(name_vars[i]); 145 if (string_var) { 146 result.push_back(string_var->value()); 147 } else { 148 try_catch.ThrowException(kInvalidValueException); 149 result.clear(); 150 return result; 151 } 152 } 153 154 return result; 155 } 156 157 void PluginObject::InstanceDeleted() { 158 instance_ = NULL; 159 } 160 161 PluginObject::PluginObject(PepperPluginInstanceImpl* instance, 162 const PPP_Class_Deprecated* ppp_class, 163 void* ppp_class_data) 164 : gin::NamedPropertyInterceptor(instance->GetIsolate(), this), 165 instance_(instance), 166 ppp_class_(ppp_class), 167 ppp_class_data_(ppp_class_data), 168 weak_factory_(this) { 169 instance_->AddPluginObject(this); 170 } 171 172 gin::ObjectTemplateBuilder PluginObject::GetObjectTemplateBuilder( 173 v8::Isolate* isolate) { 174 return Wrappable<PluginObject>::GetObjectTemplateBuilder(isolate) 175 .AddNamedPropertyInterceptor(); 176 } 177 178 v8::Local<v8::Value> PluginObject::GetPropertyOrMethod(v8::Isolate* isolate, 179 PP_Var identifier_var) { 180 if (!instance_) 181 return v8::Local<v8::Value>(); 182 183 PepperTryCatchV8 try_catch(instance_, V8VarConverter::kAllowObjectVars, 184 isolate); 185 bool has_property = 186 ppp_class_->HasProperty(ppp_class_data_, identifier_var, 187 try_catch.exception()); 188 if (try_catch.ThrowException()) 189 return v8::Local<v8::Value>(); 190 191 if (has_property) { 192 ScopedPPVar result_var(ScopedPPVar::PassRef(), 193 ppp_class_->GetProperty(ppp_class_data_, identifier_var, 194 try_catch.exception())); 195 if (try_catch.ThrowException()) 196 return v8::Local<v8::Value>(); 197 198 v8::Handle<v8::Value> result = try_catch.ToV8(result_var.get()); 199 if (try_catch.ThrowException()) 200 return v8::Local<v8::Value>(); 201 202 return result; 203 } 204 205 bool has_method = identifier_var.type == PP_VARTYPE_STRING && 206 ppp_class_->HasMethod(ppp_class_data_, identifier_var, 207 try_catch.exception()); 208 if (try_catch.ThrowException()) 209 return v8::Local<v8::Value>(); 210 211 if (has_method) { 212 const std::string& identifier = 213 StringVar::FromPPVar(identifier_var)->value(); 214 return gin::CreateFunctionTemplate(isolate, 215 base::Bind(&PluginObject::Call, 216 weak_factory_.GetWeakPtr(), 217 identifier))->GetFunction(); 218 } 219 220 return v8::Local<v8::Value>(); 221 } 222 223 void PluginObject::Call(const std::string& identifier, 224 gin::Arguments* args) { 225 if (!instance_) 226 return; 227 228 PepperTryCatchV8 try_catch(instance_, V8VarConverter::kAllowObjectVars, 229 args->isolate()); 230 ScopedPPVar identifier_var(ScopedPPVar::PassRef(), 231 StringVar::StringToPPVar(identifier)); 232 ScopedPPVarArray argument_vars(args->Length()); 233 234 for (uint32_t i = 0; i < argument_vars.size(); ++i) { 235 v8::Handle<v8::Value> arg; 236 if (!args->GetNext(&arg)) { 237 NOTREACHED(); 238 } 239 240 argument_vars.Set(i, try_catch.FromV8(arg)); 241 if (try_catch.ThrowException()) 242 return; 243 } 244 245 // For the OOP plugin case we need to grab a reference on the plugin module 246 // object to ensure that it is not destroyed courtesy an incoming 247 // ExecuteScript call which destroys the plugin module and in turn the 248 // dispatcher. 249 scoped_refptr<PluginModule> ref(instance_->module()); 250 251 ScopedPPVar result_var(ScopedPPVar::PassRef(), 252 ppp_class_->Call(ppp_class_data_, identifier_var.get(), 253 argument_vars.size(), argument_vars.get(), 254 try_catch.exception())); 255 if (try_catch.ThrowException()) 256 return; 257 258 v8::Handle<v8::Value> result = try_catch.ToV8(result_var.get()); 259 if (try_catch.ThrowException()) 260 return; 261 262 args->Return(result); 263 } 264 265 } // namespace content 266