void npObjectPropertyEnumerator(const v8::PropertyCallbackInfo<v8::Array>& info, bool namedProperty) { NPObject* npObject = v8ObjectToNPObject(info.Holder()); // Verify that our wrapper wasn't using a NPObject which // has already been deleted. if (!npObject || !_NPN_IsAlive(npObject)) throwError(v8ReferenceError, "NPObject deleted", info.GetIsolate()); if (NP_CLASS_STRUCT_VERSION_HAS_ENUM(npObject->_class) && npObject->_class->enumerate) { uint32_t count; NPIdentifier* identifiers; if (npObject->_class->enumerate(npObject, &identifiers, &count)) { v8::Handle<v8::Array> properties = v8::Array::New(count); for (uint32_t i = 0; i < count; ++i) { IdentifierRep* identifier = static_cast<IdentifierRep*>(identifiers[i]); if (namedProperty) properties->Set(v8::Integer::New(i, info.GetIsolate()), v8::String::NewSymbol(identifier->string())); else properties->Set(v8::Integer::New(i, info.GetIsolate()), v8::Integer::New(identifier->number(), info.GetIsolate())); } v8SetReturnValue(info, properties); return; } } }
static v8::Handle<v8::Value> npObjectGetProperty(v8::Local<v8::Object> self, NPIdentifier identifier, v8::Local<v8::Value> key, v8::Isolate* isolate) { NPObject* npObject = v8ObjectToNPObject(self); // Verify that our wrapper wasn't using a NPObject which // has already been deleted. if (!npObject || !_NPN_IsAlive(npObject)) return throwError(v8ReferenceError, "NPObject deleted", isolate); if (npObject->_class->hasProperty && npObject->_class->getProperty && npObject->_class->hasProperty(npObject, identifier)) { if (!_NPN_IsAlive(npObject)) return throwError(v8ReferenceError, "NPObject deleted", isolate); NPVariant result; VOID_TO_NPVARIANT(result); if (!npObject->_class->getProperty(npObject, identifier, &result)) return v8Undefined(); v8::Handle<v8::Value> returnValue; if (_NPN_IsAlive(npObject)) returnValue = convertNPVariantToV8Object(&result, npObject, isolate); _NPN_ReleaseVariantValue(&result); return returnValue; } if (!_NPN_IsAlive(npObject)) return throwError(v8ReferenceError, "NPObject deleted", isolate); if (key->IsString() && npObject->_class->hasMethod && npObject->_class->hasMethod(npObject, identifier)) { if (!_NPN_IsAlive(npObject)) return throwError(v8ReferenceError, "NPObject deleted", isolate); PrivateIdentifier* id = static_cast<PrivateIdentifier*>(identifier); UnsafePersistent<v8::FunctionTemplate> functionTemplate = V8NPTemplateMap::sharedInstance(isolate).get(id); // FunctionTemplate caches function for each context. v8::Local<v8::Function> v8Function; // Cache templates using identifier as the key. if (functionTemplate.isEmpty()) { // Create a new template. v8::Local<v8::FunctionTemplate> temp = v8::FunctionTemplate::New(); temp->SetCallHandler(npObjectMethodHandler, key); V8NPTemplateMap::sharedInstance(isolate).set(id, temp); v8Function = temp->GetFunction(); } else { v8Function = functionTemplate.newLocal(isolate)->GetFunction(); } v8Function->SetName(v8::Handle<v8::String>::Cast(key)); return v8Function; } return v8Undefined(); }
NPObject* npCreateV8ScriptObject(NPP npp, v8::Handle<v8::Object> object, DOMWindow* root, v8::Isolate* isolate) { // Check to see if this object is already wrapped. if (object->InternalFieldCount() == npObjectInternalFieldCount) { const WrapperTypeInfo* typeInfo = static_cast<const WrapperTypeInfo*>(object->GetAlignedPointerFromInternalField(v8DOMWrapperTypeIndex)); if (typeInfo == npObjectTypeInfo()) { NPObject* returnValue = v8ObjectToNPObject(object); _NPN_RetainObject(returnValue); return returnValue; } } V8NPObjectVector* objectVector = 0; if (V8PerContextData* perContextData = V8PerContextData::from(object->CreationContext())) { int v8ObjectHash = object->GetIdentityHash(); ASSERT(v8ObjectHash); V8NPObjectMap* v8NPObjectMap = perContextData->v8NPObjectMap(); V8NPObjectMap::iterator iter = v8NPObjectMap->find(v8ObjectHash); if (iter != v8NPObjectMap->end()) { V8NPObjectVector& objects = iter->value; for (size_t index = 0; index < objects.size(); ++index) { V8NPObject* v8npObject = objects.at(index); if (v8npObject->v8Object == object && v8npObject->rootObject == root) { _NPN_RetainObject(&v8npObject->object); return reinterpret_cast<NPObject*>(v8npObject); } } } else { iter = v8NPObjectMap->set(v8ObjectHash, V8NPObjectVector()).iterator; } objectVector = &iter->value; } V8NPObject* v8npObject = reinterpret_cast<V8NPObject*>(_NPN_CreateObject(npp, &V8NPObjectClass)); // This is uninitialized memory, we need to clear it so that // Persistent::Reset won't try to Dispose anything bogus. v8npObject->v8Object.Clear(); v8npObject->v8Object.Reset(isolate, object); v8npObject->rootObject = root; if (objectVector) objectVector->append(v8npObject); return reinterpret_cast<NPObject*>(v8npObject); }
PassRefPtr<SharedPersistent<v8::Object>> ScriptController::createPluginWrapper(Widget* widget) { ASSERT(widget); if (!widget->isPluginView()) return nullptr; v8::HandleScope handleScope(isolate()); v8::Local<v8::Object> scriptableObject = toPluginView(widget)->scriptableObject(isolate()); if (scriptableObject.IsEmpty()) return nullptr; // LocalFrame Memory Management for NPObjects // ------------------------------------- // NPObjects are treated differently than other objects wrapped by JS. // NPObjects can be created either by the browser (e.g. the main // window object) or by the plugin (the main plugin object // for a HTMLEmbedElement). Further, unlike most DOM Objects, the frame // is especially careful to ensure NPObjects terminate at frame teardown because // if a plugin leaks a reference, it could leak its objects (or the browser's objects). // // The LocalFrame maintains a list of plugin objects (m_pluginObjects) // which it can use to quickly find the wrapped embed object. // // Inside the NPRuntime, we've added a few methods for registering // wrapped NPObjects. The purpose of the registration is because // javascript garbage collection is non-deterministic, yet we need to // be able to tear down the plugin objects immediately. When an object // is registered, javascript can use it. When the object is destroyed, // or when the object's "owning" object is destroyed, the object will // be un-registered, and the javascript engine must not use it. // // Inside the javascript engine, the engine can keep a reference to the // NPObject as part of its wrapper. However, before accessing the object // it must consult the _NPN_Registry. if (isWrappedNPObject(scriptableObject)) { // Track the plugin object. We've been given a reference to the object. m_pluginObjects.set(widget, v8ObjectToNPObject(scriptableObject)); } return SharedPersistent<v8::Object>::create(scriptableObject, isolate()); }
NPObject* npCreateV8ScriptObject(NPP npp, v8::Handle<v8::Object> object, DOMWindow* root) { // Check to see if this object is already wrapped. if (object->InternalFieldCount() == npObjectInternalFieldCount) { WrapperTypeInfo* typeInfo = static_cast<WrapperTypeInfo*>(object->GetAlignedPointerFromInternalField(v8DOMWrapperTypeIndex)); if (typeInfo == npObjectTypeInfo()) { NPObject* returnValue = v8ObjectToNPObject(object); _NPN_RetainObject(returnValue); return returnValue; } } V8NPObjectVector* objectVector = 0; if (V8PerContextData* perContextData = V8PerContextData::from(object->CreationContext())) { int v8ObjectHash = object->GetIdentityHash(); ASSERT(v8ObjectHash); V8NPObjectMap* v8NPObjectMap = perContextData->v8NPObjectMap(); V8NPObjectMap::iterator iter = v8NPObjectMap->find(v8ObjectHash); if (iter != v8NPObjectMap->end()) { V8NPObjectVector& objects = iter->value; for (size_t index = 0; index < objects.size(); ++index) { V8NPObject* v8npObject = objects.at(index); if (v8npObject->v8Object == object && v8npObject->rootObject == root) { _NPN_RetainObject(&v8npObject->object); return reinterpret_cast<NPObject*>(v8npObject); } } } else { iter = v8NPObjectMap->set(v8ObjectHash, V8NPObjectVector()).iterator; } objectVector = &iter->value; } V8NPObject* v8npObject = reinterpret_cast<V8NPObject*>(_NPN_CreateObject(npp, &V8NPObjectClass)); v8npObject->v8Object = v8::Persistent<v8::Object>::New(v8::Isolate::GetCurrent(), object); v8npObject->rootObject = root; if (objectVector) objectVector->append(v8npObject); return reinterpret_cast<NPObject*>(v8npObject); }
NPObject* npCreateV8ScriptObject(NPP npp, v8::Handle<v8::Object> object, DOMWindow* root) { // Check to see if this object is already wrapped. if (object->InternalFieldCount() == npObjectInternalFieldCount) { WrapperTypeInfo* typeInfo = static_cast<WrapperTypeInfo*>(object->GetPointerFromInternalField(v8DOMWrapperTypeIndex)); if (typeInfo == npObjectTypeInfo()) { NPObject* returnValue = v8ObjectToNPObject(object); _NPN_RetainObject(returnValue); return returnValue; } } V8NPObject* v8npObject = reinterpret_cast<V8NPObject*>(_NPN_CreateObject(npp, &V8NPObjectClass)); v8npObject->v8Object = v8::Persistent<v8::Object>::New(object); #ifndef NDEBUG V8GCController::registerGlobalHandle(NPOBJECT, v8npObject, v8npObject->v8Object); #endif v8npObject->rootObject = root; return reinterpret_cast<NPObject*>(v8npObject); }
static v8::Handle<v8::Value> npObjectSetProperty(v8::Local<v8::Object> self, NPIdentifier identifier, v8::Local<v8::Value> value, v8::Isolate* isolate) { NPObject* npObject = v8ObjectToNPObject(self); // Verify that our wrapper wasn't using a NPObject which has already been deleted. if (!npObject || !_NPN_IsAlive(npObject)) { throwError(v8ReferenceError, "NPObject deleted", isolate); return value; // Intercepted, but an exception was thrown. } if (npObject->_class->hasProperty && npObject->_class->setProperty && npObject->_class->hasProperty(npObject, identifier)) { if (!_NPN_IsAlive(npObject)) return throwError(v8ReferenceError, "NPObject deleted", isolate); NPVariant npValue; VOID_TO_NPVARIANT(npValue); convertV8ObjectToNPVariant(value, npObject, &npValue); bool success = npObject->_class->setProperty(npObject, identifier, &npValue); _NPN_ReleaseVariantValue(&npValue); if (success) return value; // Intercept the call. } return v8Undefined(); }
// FIXME: need comments. // Params: holder could be HTMLEmbedElement or NPObject static void npObjectInvokeImpl(const v8::FunctionCallbackInfo<v8::Value>& args, InvokeFunctionType functionId) { NPObject* npObject; WrapperWorldType currentWorldType = worldType(args.GetIsolate()); // These three types are subtypes of HTMLPlugInElement. if (V8HTMLAppletElement::HasInstance(args.Holder(), args.GetIsolate(), currentWorldType) || V8HTMLEmbedElement::HasInstance(args.Holder(), args.GetIsolate(), currentWorldType) || V8HTMLObjectElement::HasInstance(args.Holder(), args.GetIsolate(), currentWorldType)) { // The holder object is a subtype of HTMLPlugInElement. HTMLPlugInElement* element; if (V8HTMLAppletElement::HasInstance(args.Holder(), args.GetIsolate(), currentWorldType)) element = V8HTMLAppletElement::toNative(args.Holder()); else if (V8HTMLEmbedElement::HasInstance(args.Holder(), args.GetIsolate(), currentWorldType)) element = V8HTMLEmbedElement::toNative(args.Holder()); else element = V8HTMLObjectElement::toNative(args.Holder()); ScriptInstance scriptInstance = element->getInstance(); if (scriptInstance) { v8::Isolate* isolate = v8::Isolate::GetCurrent(); v8::HandleScope handleScope(isolate); npObject = v8ObjectToNPObject(scriptInstance->newLocal(isolate)); } else npObject = 0; } else { // The holder object is not a subtype of HTMLPlugInElement, it must be an NPObject which has three // internal fields. if (args.Holder()->InternalFieldCount() != npObjectInternalFieldCount) { throwError(v8ReferenceError, "NPMethod called on non-NPObject", args.GetIsolate()); return; } npObject = v8ObjectToNPObject(args.Holder()); } // Verify that our wrapper wasn't using a NPObject which has already been deleted. if (!npObject || !_NPN_IsAlive(npObject)) { throwError(v8ReferenceError, "NPObject deleted", args.GetIsolate()); return; } // Wrap up parameters. int numArgs = args.Length(); OwnArrayPtr<NPVariant> npArgs = adoptArrayPtr(new NPVariant[numArgs]); for (int i = 0; i < numArgs; i++) convertV8ObjectToNPVariant(args[i], npObject, &npArgs[i]); NPVariant result; VOID_TO_NPVARIANT(result); bool retval = true; switch (functionId) { case InvokeMethod: if (npObject->_class->invoke) { v8::Handle<v8::String> functionName = v8::Handle<v8::String>::Cast(args.Data()); NPIdentifier identifier = getStringIdentifier(functionName); retval = npObject->_class->invoke(npObject, identifier, npArgs.get(), numArgs, &result); } break; case InvokeConstruct: if (npObject->_class->construct) retval = npObject->_class->construct(npObject, npArgs.get(), numArgs, &result); break; case InvokeDefault: if (npObject->_class->invokeDefault) retval = npObject->_class->invokeDefault(npObject, npArgs.get(), numArgs, &result); break; default: break; } if (!retval) throwError(v8GeneralError, "Error calling method on NPObject.", args.GetIsolate()); for (int i = 0; i < numArgs; i++) _NPN_ReleaseVariantValue(&npArgs[i]); // Unwrap return values. v8::Handle<v8::Value> returnValue; if (_NPN_IsAlive(npObject)) returnValue = convertNPVariantToV8Object(&result, npObject, args.GetIsolate()); _NPN_ReleaseVariantValue(&result); v8SetReturnValue(args, returnValue); }