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 #ifndef CONTENT_RENDERER_PEPPER_NPAPI_GLUE_H_ 6 #define CONTENT_RENDERER_PEPPER_NPAPI_GLUE_H_ 7 8 #include "base/basictypes.h" 9 #include "base/memory/scoped_ptr.h" 10 #include "content/common/content_export.h" 11 #include "ppapi/c/pp_module.h" 12 #include "ppapi/c/pp_var.h" 13 14 struct NPObject; 15 typedef struct _NPVariant NPVariant; 16 typedef void* NPIdentifier; 17 18 namespace content { 19 20 class PepperPluginInstanceImpl; 21 class PluginObject; 22 23 // Utilities ------------------------------------------------------------------- 24 25 // Converts the given PP_Var to an NPVariant, returning true on success. 26 // False means that the given variant is invalid. In this case, the result 27 // NPVariant will be set to a void one. 28 // 29 // The contents of the PP_Var will be copied unless the PP_Var corresponds to 30 // an object. 31 bool PPVarToNPVariant(PP_Var var, NPVariant* result); 32 33 // Returns a PP_Var that corresponds to the given NPVariant. The contents of 34 // the NPVariant will be copied unless the NPVariant corresponds to an 35 // object. This will handle all Variant types including POD, strings, and 36 // objects. 37 // 38 // The returned PP_Var will have a refcount of 1, this passing ownership of 39 // the reference to the caller. This is suitable for returning to a plugin. 40 PP_Var NPVariantToPPVar(PepperPluginInstanceImpl* instance, 41 const NPVariant* variant); 42 43 // Returns a NPIdentifier that corresponds to the given PP_Var. The contents 44 // of the PP_Var will be copied. Returns 0 if the given PP_Var is not a a 45 // string or integer type. 46 NPIdentifier PPVarToNPIdentifier(PP_Var var); 47 48 // Returns a PP_Var corresponding to the given identifier. In the case of 49 // a string identifier, the returned string will have a reference count of 1. 50 PP_Var NPIdentifierToPPVar(NPIdentifier id); 51 52 // Helper function to create a PP_Var of type object that contains the given 53 // NPObject for use byt he given module. Calling this function multiple times 54 // given the same module + NPObject results in the same PP_Var, assuming that 55 // there is still a PP_Var with a reference open to it from the previous 56 // call. 57 // 58 // The instance is necessary because we can have different instances pointing to 59 // the same NPObject, and we want to keep their refs separate. 60 // 61 // If no ObjectVar currently exists corresponding to the NPObject, one is 62 // created associated with the given module. 63 // 64 // Note: this could easily be changed to take a PP_Instance instead if that 65 // makes certain calls in the future easier. Currently all callers have a 66 // PluginInstance so that's what we use here. 67 CONTENT_EXPORT PP_Var NPObjectToPPVar(PepperPluginInstanceImpl* instance, 68 NPObject* object); 69 70 // This version creates a default v8::Context rather than using the one from 71 // the container of |instance|. It is only for use in unit tests, where we don't 72 // have a real container for |instance|. 73 CONTENT_EXPORT PP_Var NPObjectToPPVarForTest(PepperPluginInstanceImpl* instance, 74 NPObject* object); 75 76 // PPResultAndExceptionToNPResult ---------------------------------------------- 77 78 // Convenience object for converting a PPAPI call that can throw an exception 79 // and optionally return a value, back to the NPAPI layer which expects a 80 // NPVariant as a result. 81 // 82 // Normal usage is that you will pass the result of exception() to the 83 // PPAPI function as the exception output parameter. Then you will either 84 // call SetResult with the result of the PPAPI call, or 85 // CheckExceptionForNoResult if the PPAPI call doesn't return a PP_Var. 86 // 87 // Both SetResult and CheckExceptionForNoResult will throw an exception to 88 // the JavaScript library if the plugin reported an exception. SetResult 89 // will additionally convert the result to an NPVariant and write it to the 90 // output parameter given in the constructor. 91 class PPResultAndExceptionToNPResult { 92 public: 93 // The object_var parameter is the object to associate any exception with. 94 // It may not be NULL. 95 // 96 // The np_result parameter is the NPAPI result output parameter. This may be 97 // NULL if there is no NPVariant result (like for HasProperty). If this is 98 // specified, you must call SetResult() to set it. If it is not, you must 99 // call CheckExceptionForNoResult to do the exception checking with no result 100 // conversion. 101 PPResultAndExceptionToNPResult(NPObject* object_var, NPVariant* np_result); 102 103 ~PPResultAndExceptionToNPResult(); 104 105 // Returns true if an exception has been set. has_exception()106 bool has_exception() const { return exception_.type != PP_VARTYPE_UNDEFINED; } 107 108 // Returns a pointer to the exception. You would pass this to the PPAPI 109 // function as the exception parameter. If it is set to non-void, this object 110 // will take ownership of destroying it. exception()111 PP_Var* exception() { return &exception_; } 112 113 // Returns true if everything succeeded with no exception. This is valid only 114 // after calling SetResult/CheckExceptionForNoResult. success()115 bool success() const { 116 return success_; 117 } 118 119 // Call this with the return value of the PPAPI function. It will convert 120 // the result to the NPVariant output parameter and pass any exception on to 121 // the JS engine. It will update the success flag and return it. 122 bool SetResult(PP_Var result); 123 124 // Call this after calling a PPAPI function that could have set the 125 // exception. It will pass the exception on to the JS engine and update 126 // the success flag. 127 // 128 // The success flag will be returned. 129 bool CheckExceptionForNoResult(); 130 131 // Call this to ignore any exception. This prevents the DCHECK from failing 132 // in the destructor. 133 void IgnoreException(); 134 135 private: 136 // Throws the current exception to JS. The exception must be set. 137 void ThrowException(); 138 139 NPObject* object_var_; // Non-owning ref (see constructor). 140 NPVariant* np_result_; // Output value, possibly NULL (see constructor). 141 PP_Var exception_; // Exception set by the PPAPI call. We own a ref to it. 142 bool success_; // See the success() function above. 143 bool checked_exception_; // SetResult/CheckExceptionForNoResult was called. 144 145 DISALLOW_COPY_AND_ASSIGN(PPResultAndExceptionToNPResult); 146 }; 147 148 // PPVarArrayFromNPVariantArray ------------------------------------------------ 149 150 // Converts an array of NPVariants to an array of PP_Var, and scopes the 151 // ownership of the PP_Var. This is used when converting argument lists from 152 // WebKit to the plugin. 153 class PPVarArrayFromNPVariantArray { 154 public: 155 PPVarArrayFromNPVariantArray(PepperPluginInstanceImpl* instance, 156 size_t size, 157 const NPVariant* variants); 158 ~PPVarArrayFromNPVariantArray(); 159 array()160 PP_Var* array() { return array_.get(); } 161 162 private: 163 size_t size_; 164 scoped_ptr<PP_Var[]> array_; 165 166 DISALLOW_COPY_AND_ASSIGN(PPVarArrayFromNPVariantArray); 167 }; 168 169 // PPVarFromNPObject ----------------------------------------------------------- 170 171 // Converts an NPObject tp PP_Var, and scopes the ownership of the PP_Var. This 172 // is used when converting 'this' pointer from WebKit to the plugin. 173 class PPVarFromNPObject { 174 public: 175 PPVarFromNPObject(PepperPluginInstanceImpl* instance, NPObject* object); 176 ~PPVarFromNPObject(); 177 var()178 PP_Var var() const { return var_; } 179 180 private: 181 const PP_Var var_; 182 183 DISALLOW_COPY_AND_ASSIGN(PPVarFromNPObject); 184 }; 185 186 // NPObjectAccessorWithIdentifier ---------------------------------------------- 187 188 // Helper class for our NPObject wrapper. This converts a call from WebKit 189 // where it gives us an NPObject and an NPIdentifier to an easily-accessible 190 // ObjectVar (corresponding to the NPObject) and PP_Var (corresponding to the 191 // NPIdentifier). 192 // 193 // If the NPObject or identifier is invalid, we'll set is_valid() to false. 194 // The caller should check is_valid() before doing anything with the class. 195 // 196 // JS can't have integer functions, so when dealing with these, we don't want 197 // to allow integer identifiers. The calling code can decode if it wants to 198 // allow integer identifiers (like for property access) or prohibit them 199 // (like for method calling) by setting |allow_integer_identifier|. If this 200 // is false and the identifier is an integer, we'll set is_valid() to false. 201 // 202 // Getting an integer identifier in this case should be impossible. V8 203 // shouldn't be allowing this, and the Pepper Var calls from the plugin are 204 // supposed to error out before calling into V8 (which will then call us back). 205 // Aside from an egregious error, the only time this could happen is an NPAPI 206 // plugin calling us. 207 class NPObjectAccessorWithIdentifier { 208 public: 209 NPObjectAccessorWithIdentifier(NPObject* object, 210 NPIdentifier identifier, 211 bool allow_integer_identifier); 212 ~NPObjectAccessorWithIdentifier(); 213 214 // Returns true if both the object and identifier are valid. is_valid()215 bool is_valid() const { 216 return object_ && identifier_.type != PP_VARTYPE_UNDEFINED; 217 } 218 object()219 PluginObject* object() { return object_; } identifier()220 PP_Var identifier() const { return identifier_; } 221 222 private: 223 PluginObject* object_; 224 PP_Var identifier_; 225 226 DISALLOW_COPY_AND_ASSIGN(NPObjectAccessorWithIdentifier); 227 }; 228 229 // TryCatch -------------------------------------------------------------------- 230 231 // Instantiate this object on the stack to catch V8 exceptions and pass them 232 // to an optional out parameter supplied by the plugin. 233 class TryCatch { 234 public: 235 // The given exception may be NULL if the consumer isn't interested in 236 // catching exceptions. If non-NULL, the given var will be updated if any 237 // exception is thrown (so it must outlive the TryCatch object). 238 TryCatch(PP_Var* exception); 239 ~TryCatch(); 240 241 // Returns true is an exception has been thrown. This can be true immediately 242 // after construction if the var passed to the constructor is non-void. has_exception()243 bool has_exception() const { return has_exception_; } 244 245 // Sets the given exception. If an exception has been previously set, this 246 // function will do nothing (normally you want only the first exception). 247 void SetException(const char* message); 248 249 private: 250 static void Catch(void* self, const char* message); 251 252 // True if an exception has been thrown. Since the exception itself may be 253 // NULL if the plugin isn't interested in getting the exception, this will 254 // always indicate if SetException has been called, regardless of whether 255 // the exception itself has been stored. 256 bool has_exception_; 257 258 // May be null if the consumer isn't interesting in catching exceptions. 259 PP_Var* exception_; 260 }; 261 262 } // namespace content 263 264 #endif // CONTENT_RENDERER_PEPPER_NPAPI_GLUE_H_ 265