| OLD | NEW | 
 | (Empty) | 
|    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/npapi_glue.h" |  | 
|    6  |  | 
|    7 #include "base/logging.h" |  | 
|    8 #include "base/memory/ref_counted.h" |  | 
|    9 #include "base/strings/string_util.h" |  | 
|   10 #include "content/renderer/pepper/host_array_buffer_var.h" |  | 
|   11 #include "content/renderer/pepper/host_globals.h" |  | 
|   12 #include "content/renderer/pepper/host_var_tracker.h" |  | 
|   13 #include "content/renderer/pepper/npobject_var.h" |  | 
|   14 #include "content/renderer/pepper/pepper_plugin_instance_impl.h" |  | 
|   15 #include "content/renderer/pepper/plugin_module.h" |  | 
|   16 #include "content/renderer/pepper/plugin_object.h" |  | 
|   17 #include "ppapi/c/pp_var.h" |  | 
|   18 #include "third_party/npapi/bindings/npapi.h" |  | 
|   19 #include "third_party/npapi/bindings/npruntime.h" |  | 
|   20 #include "third_party/WebKit/public/web/WebBindings.h" |  | 
|   21 #include "third_party/WebKit/public/web/WebDocument.h" |  | 
|   22 #include "third_party/WebKit/public/web/WebElement.h" |  | 
|   23 #include "third_party/WebKit/public/web/WebLocalFrame.h" |  | 
|   24 #include "third_party/WebKit/public/web/WebPluginContainer.h" |  | 
|   25 #include "v8/include/v8.h" |  | 
|   26  |  | 
|   27 using ppapi::NPObjectVar; |  | 
|   28 using ppapi::PpapiGlobals; |  | 
|   29 using ppapi::StringVar; |  | 
|   30 using ppapi::Var; |  | 
|   31 using blink::WebArrayBuffer; |  | 
|   32 using blink::WebBindings; |  | 
|   33 using blink::WebLocalFrame; |  | 
|   34 using blink::WebPluginContainer; |  | 
|   35  |  | 
|   36 namespace content { |  | 
|   37  |  | 
|   38 namespace { |  | 
|   39  |  | 
|   40 const char kInvalidPluginValue[] = "Error: Plugin returned invalid value."; |  | 
|   41  |  | 
|   42 PP_Var NPObjectToPPVarImpl(PepperPluginInstanceImpl* instance, |  | 
|   43                            NPObject* object, |  | 
|   44                            v8::Local<v8::Context> context) { |  | 
|   45   DCHECK(object); |  | 
|   46   if (context.IsEmpty()) |  | 
|   47     return PP_MakeUndefined(); |  | 
|   48   v8::Context::Scope context_scope(context); |  | 
|   49  |  | 
|   50   WebArrayBuffer buffer; |  | 
|   51   // TODO(dmichael): Should I protect against duplicate Vars representing the |  | 
|   52   // same array buffer? It's probably not worth the trouble, since it will only |  | 
|   53   // affect in-process plugins. |  | 
|   54   if (WebBindings::getArrayBuffer(object, &buffer)) { |  | 
|   55     scoped_refptr<HostArrayBufferVar> buffer_var( |  | 
|   56         new HostArrayBufferVar(buffer)); |  | 
|   57     return buffer_var->GetPPVar(); |  | 
|   58   } |  | 
|   59   scoped_refptr<NPObjectVar> object_var( |  | 
|   60       HostGlobals::Get()->host_var_tracker()->NPObjectVarForNPObject( |  | 
|   61           instance->pp_instance(), object)); |  | 
|   62   if (!object_var.get()) {  // No object for this module yet, make a new one. |  | 
|   63     object_var = new NPObjectVar(instance->pp_instance(), object); |  | 
|   64   } |  | 
|   65   return object_var->GetPPVar(); |  | 
|   66 } |  | 
|   67  |  | 
|   68 }  // namespace |  | 
|   69  |  | 
|   70 // Utilities ------------------------------------------------------------------- |  | 
|   71  |  | 
|   72 bool PPVarToNPVariant(PP_Var var, NPVariant* result) { |  | 
|   73   switch (var.type) { |  | 
|   74     case PP_VARTYPE_UNDEFINED: |  | 
|   75       VOID_TO_NPVARIANT(*result); |  | 
|   76       break; |  | 
|   77     case PP_VARTYPE_NULL: |  | 
|   78       NULL_TO_NPVARIANT(*result); |  | 
|   79       break; |  | 
|   80     case PP_VARTYPE_BOOL: |  | 
|   81       BOOLEAN_TO_NPVARIANT(var.value.as_bool, *result); |  | 
|   82       break; |  | 
|   83     case PP_VARTYPE_INT32: |  | 
|   84       INT32_TO_NPVARIANT(var.value.as_int, *result); |  | 
|   85       break; |  | 
|   86     case PP_VARTYPE_DOUBLE: |  | 
|   87       DOUBLE_TO_NPVARIANT(var.value.as_double, *result); |  | 
|   88       break; |  | 
|   89     case PP_VARTYPE_STRING: { |  | 
|   90       StringVar* string = StringVar::FromPPVar(var); |  | 
|   91       if (!string) { |  | 
|   92         VOID_TO_NPVARIANT(*result); |  | 
|   93         return false; |  | 
|   94       } |  | 
|   95       const std::string& value = string->value(); |  | 
|   96       char* c_string = static_cast<char*>(malloc(value.size())); |  | 
|   97       memcpy(c_string, value.data(), value.size()); |  | 
|   98       STRINGN_TO_NPVARIANT(c_string, value.size(), *result); |  | 
|   99       break; |  | 
|  100     } |  | 
|  101     case PP_VARTYPE_OBJECT: { |  | 
|  102       scoped_refptr<NPObjectVar> object(NPObjectVar::FromPPVar(var)); |  | 
|  103       if (!object.get()) { |  | 
|  104         VOID_TO_NPVARIANT(*result); |  | 
|  105         return false; |  | 
|  106       } |  | 
|  107       OBJECT_TO_NPVARIANT(WebBindings::retainObject(object->np_object()), |  | 
|  108                           *result); |  | 
|  109       break; |  | 
|  110     } |  | 
|  111     // The following types are not supported for use with PPB_Var_Deprecated, |  | 
|  112     // because PPB_Var_Deprecated is only for trusted plugins, and the trusted |  | 
|  113     // plugins we have don't need these types. We can add support in the future |  | 
|  114     // if it becomes necessary. |  | 
|  115     case PP_VARTYPE_ARRAY: |  | 
|  116     case PP_VARTYPE_DICTIONARY: |  | 
|  117     case PP_VARTYPE_ARRAY_BUFFER: |  | 
|  118     case PP_VARTYPE_RESOURCE: |  | 
|  119       VOID_TO_NPVARIANT(*result); |  | 
|  120       break; |  | 
|  121   } |  | 
|  122   return true; |  | 
|  123 } |  | 
|  124  |  | 
|  125 PP_Var NPVariantToPPVar(PepperPluginInstanceImpl* instance, |  | 
|  126                         const NPVariant* variant) { |  | 
|  127   switch (variant->type) { |  | 
|  128     case NPVariantType_Void: |  | 
|  129       return PP_MakeUndefined(); |  | 
|  130     case NPVariantType_Null: |  | 
|  131       return PP_MakeNull(); |  | 
|  132     case NPVariantType_Bool: |  | 
|  133       return PP_MakeBool(PP_FromBool(NPVARIANT_TO_BOOLEAN(*variant))); |  | 
|  134     case NPVariantType_Int32: |  | 
|  135       return PP_MakeInt32(NPVARIANT_TO_INT32(*variant)); |  | 
|  136     case NPVariantType_Double: |  | 
|  137       return PP_MakeDouble(NPVARIANT_TO_DOUBLE(*variant)); |  | 
|  138     case NPVariantType_String: |  | 
|  139       return StringVar::StringToPPVar( |  | 
|  140           NPVARIANT_TO_STRING(*variant).UTF8Characters, |  | 
|  141           NPVARIANT_TO_STRING(*variant).UTF8Length); |  | 
|  142     case NPVariantType_Object: |  | 
|  143       return NPObjectToPPVar(instance, NPVARIANT_TO_OBJECT(*variant)); |  | 
|  144   } |  | 
|  145   NOTREACHED(); |  | 
|  146   return PP_MakeUndefined(); |  | 
|  147 } |  | 
|  148  |  | 
|  149 NPIdentifier PPVarToNPIdentifier(PP_Var var) { |  | 
|  150   switch (var.type) { |  | 
|  151     case PP_VARTYPE_STRING: { |  | 
|  152       StringVar* string = StringVar::FromPPVar(var); |  | 
|  153       if (!string) |  | 
|  154         return NULL; |  | 
|  155       return WebBindings::getStringIdentifier(string->value().c_str()); |  | 
|  156     } |  | 
|  157     case PP_VARTYPE_INT32: |  | 
|  158       return WebBindings::getIntIdentifier(var.value.as_int); |  | 
|  159     default: |  | 
|  160       return NULL; |  | 
|  161   } |  | 
|  162 } |  | 
|  163  |  | 
|  164 PP_Var NPIdentifierToPPVar(NPIdentifier id) { |  | 
|  165   const NPUTF8* string_value = NULL; |  | 
|  166   int32_t int_value = 0; |  | 
|  167   bool is_string = false; |  | 
|  168   WebBindings::extractIdentifierData(id, string_value, int_value, is_string); |  | 
|  169   if (is_string) |  | 
|  170     return StringVar::StringToPPVar(string_value); |  | 
|  171  |  | 
|  172   return PP_MakeInt32(int_value); |  | 
|  173 } |  | 
|  174  |  | 
|  175 PP_Var NPObjectToPPVar(PepperPluginInstanceImpl* instance, NPObject* object) { |  | 
|  176   WebPluginContainer* container = instance->container(); |  | 
|  177   // It's possible that container() is NULL if the plugin has been removed from |  | 
|  178   // the DOM (but the PluginInstance is not destroyed yet). |  | 
|  179   if (!container) |  | 
|  180     return PP_MakeUndefined(); |  | 
|  181   WebLocalFrame* frame = container->element().document().frame(); |  | 
|  182   if (!frame) |  | 
|  183     return PP_MakeUndefined(); |  | 
|  184  |  | 
|  185   v8::HandleScope scope(instance->GetIsolate()); |  | 
|  186   v8::Local<v8::Context> context = frame->mainWorldScriptContext(); |  | 
|  187   return NPObjectToPPVarImpl(instance, object, context); |  | 
|  188 } |  | 
|  189  |  | 
|  190 PP_Var NPObjectToPPVarForTest(PepperPluginInstanceImpl* instance, |  | 
|  191                               NPObject* object) { |  | 
|  192   v8::Isolate* test_isolate = v8::Isolate::New(); |  | 
|  193   PP_Var result = PP_MakeUndefined(); |  | 
|  194   { |  | 
|  195     v8::HandleScope scope(test_isolate); |  | 
|  196     v8::Isolate::Scope isolate_scope(test_isolate); |  | 
|  197     v8::Local<v8::Context> context = v8::Context::New(test_isolate); |  | 
|  198     result = NPObjectToPPVarImpl(instance, object, context); |  | 
|  199   } |  | 
|  200   test_isolate->Dispose(); |  | 
|  201   return result; |  | 
|  202 } |  | 
|  203  |  | 
|  204 // PPResultAndExceptionToNPResult ---------------------------------------------- |  | 
|  205  |  | 
|  206 PPResultAndExceptionToNPResult::PPResultAndExceptionToNPResult( |  | 
|  207     NPObject* object_var, |  | 
|  208     NPVariant* np_result) |  | 
|  209     : object_var_(object_var), |  | 
|  210       np_result_(np_result), |  | 
|  211       exception_(PP_MakeUndefined()), |  | 
|  212       success_(false), |  | 
|  213       checked_exception_(false) {} |  | 
|  214  |  | 
|  215 PPResultAndExceptionToNPResult::~PPResultAndExceptionToNPResult() { |  | 
|  216   // The user should have called SetResult or CheckExceptionForNoResult |  | 
|  217   // before letting this class go out of scope, or the exception will have |  | 
|  218   // been lost. |  | 
|  219   DCHECK(checked_exception_); |  | 
|  220  |  | 
|  221   PpapiGlobals::Get()->GetVarTracker()->ReleaseVar(exception_); |  | 
|  222 } |  | 
|  223  |  | 
|  224 // Call this with the return value of the PPAPI function. It will convert |  | 
|  225 // the result to the NPVariant output parameter and pass any exception on to |  | 
|  226 // the JS engine. It will update the success flag and return it. |  | 
|  227 bool PPResultAndExceptionToNPResult::SetResult(PP_Var result) { |  | 
|  228   DCHECK(!checked_exception_);  // Don't call more than once. |  | 
|  229   DCHECK(np_result_);           // Should be expecting a result. |  | 
|  230  |  | 
|  231   checked_exception_ = true; |  | 
|  232  |  | 
|  233   if (has_exception()) { |  | 
|  234     ThrowException(); |  | 
|  235     success_ = false; |  | 
|  236   } else if (!PPVarToNPVariant(result, np_result_)) { |  | 
|  237     WebBindings::setException(object_var_, kInvalidPluginValue); |  | 
|  238     success_ = false; |  | 
|  239   } else { |  | 
|  240     success_ = true; |  | 
|  241   } |  | 
|  242  |  | 
|  243   // No matter what happened, we need to release the reference to the |  | 
|  244   // value passed in. On success, a reference to this value will be in |  | 
|  245   // the np_result_. |  | 
|  246   PpapiGlobals::Get()->GetVarTracker()->ReleaseVar(result); |  | 
|  247   return success_; |  | 
|  248 } |  | 
|  249  |  | 
|  250 // Call this after calling a PPAPI function that could have set the |  | 
|  251 // exception. It will pass the exception on to the JS engine and update |  | 
|  252 // the success flag. |  | 
|  253 // |  | 
|  254 // The success flag will be returned. |  | 
|  255 bool PPResultAndExceptionToNPResult::CheckExceptionForNoResult() { |  | 
|  256   DCHECK(!checked_exception_);  // Don't call more than once. |  | 
|  257   DCHECK(!np_result_);          // Can't have a result when doing this. |  | 
|  258  |  | 
|  259   checked_exception_ = true; |  | 
|  260  |  | 
|  261   if (has_exception()) { |  | 
|  262     ThrowException(); |  | 
|  263     success_ = false; |  | 
|  264     return false; |  | 
|  265   } |  | 
|  266   success_ = true; |  | 
|  267   return true; |  | 
|  268 } |  | 
|  269  |  | 
|  270 // Call this to ignore any exception. This prevents the DCHECK from failing |  | 
|  271 // in the destructor. |  | 
|  272 void PPResultAndExceptionToNPResult::IgnoreException() { |  | 
|  273   checked_exception_ = true; |  | 
|  274 } |  | 
|  275  |  | 
|  276 // Throws the current exception to JS. The exception must be set. |  | 
|  277 void PPResultAndExceptionToNPResult::ThrowException() { |  | 
|  278   StringVar* string = StringVar::FromPPVar(exception_); |  | 
|  279   if (string) |  | 
|  280     WebBindings::setException(object_var_, string->value().c_str()); |  | 
|  281 } |  | 
|  282  |  | 
|  283 // PPVarArrayFromNPVariantArray ------------------------------------------------ |  | 
|  284  |  | 
|  285 PPVarArrayFromNPVariantArray::PPVarArrayFromNPVariantArray( |  | 
|  286     PepperPluginInstanceImpl* instance, |  | 
|  287     size_t size, |  | 
|  288     const NPVariant* variants) |  | 
|  289     : size_(size) { |  | 
|  290   if (size_ > 0) { |  | 
|  291     array_.reset(new PP_Var[size_]); |  | 
|  292     for (size_t i = 0; i < size_; i++) |  | 
|  293       array_[i] = NPVariantToPPVar(instance, &variants[i]); |  | 
|  294   } |  | 
|  295 } |  | 
|  296  |  | 
|  297 PPVarArrayFromNPVariantArray::~PPVarArrayFromNPVariantArray() { |  | 
|  298   ppapi::VarTracker* var_tracker = PpapiGlobals::Get()->GetVarTracker(); |  | 
|  299   for (size_t i = 0; i < size_; i++) |  | 
|  300     var_tracker->ReleaseVar(array_[i]); |  | 
|  301 } |  | 
|  302  |  | 
|  303 // PPVarFromNPObject ----------------------------------------------------------- |  | 
|  304  |  | 
|  305 PPVarFromNPObject::PPVarFromNPObject(PepperPluginInstanceImpl* instance, |  | 
|  306                                      NPObject* object) |  | 
|  307     : var_(NPObjectToPPVar(instance, object)) {} |  | 
|  308  |  | 
|  309 PPVarFromNPObject::~PPVarFromNPObject() { |  | 
|  310   PpapiGlobals::Get()->GetVarTracker()->ReleaseVar(var_); |  | 
|  311 } |  | 
|  312  |  | 
|  313 // NPObjectAccessorWithIdentifier ---------------------------------------------- |  | 
|  314  |  | 
|  315 NPObjectAccessorWithIdentifier::NPObjectAccessorWithIdentifier( |  | 
|  316     NPObject* object, |  | 
|  317     NPIdentifier identifier, |  | 
|  318     bool allow_integer_identifier) |  | 
|  319     : object_(PluginObject::FromNPObject(object)), |  | 
|  320       identifier_(PP_MakeUndefined()) { |  | 
|  321   if (object_) { |  | 
|  322     identifier_ = NPIdentifierToPPVar(identifier); |  | 
|  323     if (identifier_.type == PP_VARTYPE_INT32 && !allow_integer_identifier) |  | 
|  324       identifier_.type = PP_VARTYPE_UNDEFINED;  // Mark it invalid. |  | 
|  325   } |  | 
|  326 } |  | 
|  327  |  | 
|  328 NPObjectAccessorWithIdentifier::~NPObjectAccessorWithIdentifier() { |  | 
|  329   PpapiGlobals::Get()->GetVarTracker()->ReleaseVar(identifier_); |  | 
|  330 } |  | 
|  331  |  | 
|  332 // TryCatch -------------------------------------------------------------------- |  | 
|  333  |  | 
|  334 TryCatch::TryCatch(PP_Var* exception) |  | 
|  335     : has_exception_(exception && exception->type != PP_VARTYPE_UNDEFINED), |  | 
|  336       exception_(exception) { |  | 
|  337   WebBindings::pushExceptionHandler(&TryCatch::Catch, this); |  | 
|  338 } |  | 
|  339  |  | 
|  340 TryCatch::~TryCatch() { WebBindings::popExceptionHandler(); } |  | 
|  341  |  | 
|  342 void TryCatch::SetException(const char* message) { |  | 
|  343   if (!has_exception()) { |  | 
|  344     has_exception_ = true; |  | 
|  345     if (exception_) { |  | 
|  346       if (!message) |  | 
|  347         message = "Unknown exception."; |  | 
|  348       *exception_ = ppapi::StringVar::StringToPPVar(message, strlen(message)); |  | 
|  349     } |  | 
|  350   } |  | 
|  351 } |  | 
|  352  |  | 
|  353 // static |  | 
|  354 void TryCatch::Catch(void* self, const char* message) { |  | 
|  355   static_cast<TryCatch*>(self)->SetException(message); |  | 
|  356 } |  | 
|  357  |  | 
|  358 }  // namespace content |  | 
| OLD | NEW |