/* * Copyright 2009, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // Code relating to interoperation of V8 JavaScript engine with NPAPI. #ifndef O3D_PLUGIN_CROSS_NP_V8_BRIDGE_H_ #define O3D_PLUGIN_CROSS_NP_V8_BRIDGE_H_ #include #include #include #include "base/cross/std_hash.h" #include "core/cross/error_status.h" #include "core/cross/service_dependency.h" #include "core/cross/types.h" // The XLib header files define these preprocessor macros which v8 uses as // identifiers. Need to undefine them before including v8. #ifdef None #undef None #endif #ifdef True #undef True #endif #ifdef False #undef False #endif #ifdef Value #undef Value #endif #include "v8/include/v8.h" namespace o3d { // Smart pointer for NPObjects that automatically retains and releases the // reference count. template class NPObjectPtr { public: NPObjectPtr() : owned(true), object_(NULL) { } template explicit NPObjectPtr(U* object) : object_(object) { Retain(); } NPObjectPtr(const NPObjectPtr& rhs) : object_(rhs.object_) { Retain(); } template explicit NPObjectPtr(const NPObjectPtr& rhs) : object_(rhs.Get()) { Retain(); } ~NPObjectPtr() { Release(); } template NPObjectPtr& operator=(U* rhs) { Release(); object_ = rhs; Retain(); return *this; } NPObjectPtr& operator=(const NPObjectPtr& rhs) { Release(); object_ = rhs.object_; Retain(); return *this; } template NPObjectPtr& operator=(const NPObjectPtr& rhs) { Release(); object_ = rhs.Get(); Retain(); return *this; } bool operator<(const NPObjectPtr& rhs) const { return object_ < rhs.object_; } bool operator==(const NPObjectPtr& rhs) const { return object_ == rhs.object_; } T* operator->() const { return object_; } T* Get() const { return object_; } bool IsNull() const { return object_ == NULL; } void Clear() { Release(); object_ = NULL; } // Does not increment the reference count. When a function returns a pointer // to an NPObject, the rule is that its reference count has already been // incremented on behalf of the caller. static NPObjectPtr AttachToReturned(T* object) { NPObjectPtr result(object); result.Release(); return result; } // Calling this prevents the NPObject's reference count from being decremented // by this smart pointer when it is destroyed or a new reference is assigned. T* Disown() const { owned = false; return object_; } private: void Retain() { owned = true; if (object_ != NULL) { NPN_RetainObject(object_); } } void Release() { if (owned && object_ != NULL) { NPN_ReleaseObject(object_); } } mutable bool owned; T* object_; }; // Hashes an NPObject so it can be used in a hash_map. template class NPObjectPtrHash { public: size_t operator() (const NPObjectPtr& ptr) const { return o3d::base::hash()(reinterpret_cast(ptr.Get())); } }; // A V8 handle that automatically disposes itself when it is destroyed. There // must be only one of these for each persistent handle, otherwise they might // be disposed more than once. template class AutoV8Persistent : public v8::Persistent { public: AutoV8Persistent() {} template explicit AutoV8Persistent(const v8::Persistent& rhs) : v8::Persistent(rhs) { } template AutoV8Persistent& operator=(const v8::Persistent& rhs) { *(v8::Persistent*)this = rhs; return *this; } ~AutoV8Persistent() { this->Dispose(); this->Clear(); } }; // The bridge provides a way of evaluating JavaScript in the V8 engine and // marshalling between V8 and NPAPI representations of objects and values. class NPV8Bridge { friend class NPV8Object; public: NPV8Bridge(ServiceLocator* service_locator, NPP npp); ~NPV8Bridge(); NPP npp() { return npp_; } // Initializes the V8 environment. The global NPObject is wrapped with a V8 // proxy and used as the global environment's prototype. This means that if // a variable cannot be resolved in the V8 environment then it will attempt // to resolve it in the NPObject. This allows V8 to read global variables in // the browser environment. Note that assignments will never go to the // global environment's prototype, changes will only be visible locally. void Initialize(const NPObjectPtr& global_np_object); // This function tells the bridge to forget and release all of the NPObjects // that it knows about. void ReleaseNPObjects(); v8::Handle script_context(); // Evaluates some JavaScript code in V8. It currently expects only one // argument in the argument array, which must be a string containing the // JavaScript code to evaluate. It returns the result of the evaluation // as an NPAPI variant, which must be freed using NPN_ReleaseVariantValue. bool Evaluate(const NPVariant* np_args, int numArgs, NPVariant* np_result); // Adds an object property to the V8 global environment. void SetGlobalProperty(const String& name, NPObjectPtr& np_object); // Converts a V8 value into an NPVariant. The NPVariant must be freed with // NPN_ReleaseVariantValue. Caller must enter the script context. NPVariant V8ToNPVariant(v8::Local value); // Converts an NPVariant to a V8 value. Caller must enter the script context. v8::Local NPToV8Variant(const NPVariant& np_variant); // Converts a V8 object to an NPObject, either by wrapping the V8 object // with an NPV8Object proxy or if the V8 object is a proxy, returning the // NPObject it wraps. Caller must enter the script context. NPObjectPtr V8ToNPObject(v8::Local v8_object); // Converts an NPObject to a V8 object, either by wrapping the NPObject with // a V8 proxy or if the NPObject is a proxy, returning the V8 object it wraps. // Caller must enter the script context. v8::Local NPToV8Object(const NPObjectPtr& np_object); // Determines whether the given NPObject is currently referenced by V8 through // a proxy. bool IsNPObjectReferenced(NPObjectPtr np_object); private: NPObjectPtr NPEvaluateObject(const char* script); void NPToV8Object(v8::Local v8_target, const NPObjectPtr& np_object); bool IsNPFunction(const NPObjectPtr& np_object); v8::Local NPToV8Function( const NPObjectPtr& np_function); void ReleaseUnreferencedWrapperFunctions(); NPObjectPtr WrapV8Function(const NPObjectPtr& np_object); void RegisterV8Object(v8::Local v8_object, const NPObjectPtr& np_object); void InitializeV8ObjectTemplate( v8::Local v8_object_template); static void NPV8WeakReferenceCallback(v8::Persistent value, void* parameter); void ReportV8Exception(const v8::TryCatch& tryCatch); v8::Local NPToV8IdentifierArray( const NPVariant& np_array, bool named); v8::Local NPToV8IdentifierArray( const NPIdentifier* ids, uint32_t id_count, bool named); // Implements enumeration of NPObject properties using NPN_Evaluate where // supported by the browser or otherwise falling back on emulation. Returns // either named or indexed properties depending on named parameter. v8::Local Enumerate(const NPObjectPtr np_object, bool named); static v8::Handle V8PropertyGetter(v8::Local v8_name, const v8::AccessorInfo& info); static v8::Handle V8PropertySetter(v8::Local v8_name, v8::Local v8_value, const v8::AccessorInfo& info); static v8::Handle V8PropertyQuery(v8::Local v8_name, const v8::AccessorInfo& info); static v8::Handle V8PropertyDeleter( v8::Local v8_name, const v8::AccessorInfo& info); static v8::Handle V8NamedPropertyGetter( v8::Local v8_name, const v8::AccessorInfo& info); static v8::Handle V8NamedPropertySetter( v8::Local v8_name, v8::Local v8_value, const v8::AccessorInfo& info); static v8::Handle V8NamedPropertyQuery( v8::Local v8_name, const v8::AccessorInfo& info); static v8::Handle V8NamedPropertyDeleter( v8::Local v8_name, const v8::AccessorInfo& info); static v8::Handle V8NamedPropertyEnumerator( const v8::AccessorInfo& info); static v8::Handle V8IndexedPropertyGetter( uint32_t index, const v8::AccessorInfo& info); static v8::Handle V8IndexedPropertySetter( uint32_t index, v8::Local v8_value, const v8::AccessorInfo& info); static v8::Handle V8IndexedPropertyQuery( uint32_t index, const v8::AccessorInfo& info); static v8::Handle V8IndexedPropertyDeleter( uint32_t index, const v8::AccessorInfo& info); static v8::Handle V8IndexedPropertyEnumerator( const v8::AccessorInfo& info); static v8::Handle V8CallNamedMethod(const v8::Arguments& args); static v8::Handle V8CallFunction(const v8::Arguments& args); static v8::Handle V8CallAsFunction(const v8::Arguments& args); NPObjectPtr GetNPConstructFunction(int arity); typedef o3d::base::hash_map, AutoV8Persistent, NPObjectPtrHash > NPV8ObjectMap; typedef std::map > NPConstructFunctionMap; ServiceLocator* service_locator_; ServiceDependency error_status_; NPP npp_; NPObjectPtr global_np_object_; AutoV8Persistent script_context_; AutoV8Persistent v8_np_constructor_template_; AutoV8Persistent function_map_; AutoV8Persistent global_prototype_; NPV8ObjectMap np_v8_object_map_; NPObjectPtr np_enumerate_function_; NPObjectPtr np_is_function_function_; NPObjectPtr np_wrap_function_function_; NPConstructFunctionMap np_construct_functions_; NPIdentifier np_name_identifier_; NPIdentifier np_call_identifier_; NPIdentifier np_length_identifier_; NPIdentifier np_proxy_identifier_; NPObjectPtr np_empty_array_; DISALLOW_COPY_AND_ASSIGN(NPV8Bridge); }; } // namespace o3d #endif // O3D_PLUGIN_CROSS_NP_V8_BRIDGE_H_