blob: 49173b2ecd9747d97730bd9dfa323ae94e83907e [file] [log] [blame]
/*
* Copyright (C) 2018 Igalia S.L.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "config.h"
#include "JSCWrapperMap.h"
#include "APICast.h"
#include "JSAPIWrapperGlobalObject.h"
#include "JSAPIWrapperObject.h"
#include "JSCClassPrivate.h"
#include "JSCContextPrivate.h"
#include "JSCGLibWrapperObject.h"
#include "JSCInlines.h"
#include "JSCValuePrivate.h"
#include "JSCallbackObject.h"
#include "JSContextRef.h"
namespace JSC {
WrapperMap::WrapperMap(JSGlobalContextRef jsContext)
: m_cachedJSWrappers(makeUnique<JSC::WeakGCMap<gpointer, JSC::JSObject>>(toJS(jsContext)->vm()))
{
}
WrapperMap::~WrapperMap()
{
for (const auto& jscClass : m_classMap.values())
jscClassInvalidate(jscClass.get());
}
GRefPtr<JSCValue> WrapperMap::gobjectWrapper(JSCContext* jscContext, JSValueRef jsValue)
{
auto* jsContext = jscContextGetJSContext(jscContext);
JSC::JSLockHolder locker(toJS(jsContext));
ASSERT(toJSGlobalObject(jsContext)->wrapperMap() == this);
GRefPtr<JSCValue> value = m_cachedGObjectWrappers.get(jsValue);
if (!value) {
value = adoptGRef(jscValueCreate(jscContext, jsValue));
m_cachedGObjectWrappers.set(jsValue, value.get());
}
return value;
}
void WrapperMap::unwrap(JSValueRef jsValue)
{
ASSERT(m_cachedGObjectWrappers.contains(jsValue));
m_cachedGObjectWrappers.remove(jsValue);
}
void WrapperMap::registerClass(JSCClass* jscClass)
{
auto* jsClass = jscClassGetJSClass(jscClass);
ASSERT(!m_classMap.contains(jsClass));
m_classMap.set(jsClass, jscClass);
}
JSCClass* WrapperMap::registeredClass(JSClassRef jsClass) const
{
return m_classMap.get(jsClass);
}
JSObject* WrapperMap::createJSWrapper(JSGlobalContextRef jsContext, JSClassRef jsClass, JSValueRef prototype, gpointer wrappedObject, GDestroyNotify destroyFunction)
{
ASSERT(toJSGlobalObject(jsContext)->wrapperMap() == this);
JSGlobalObject* globalObject = toJS(jsContext);
VM& vm = globalObject->vm();
JSLockHolder locker(vm);
auto* object = JSC::JSCallbackObject<JSC::JSAPIWrapperObject>::create(globalObject, globalObject->glibWrapperObjectStructure(), jsClass, nullptr);
if (wrappedObject) {
object->setWrappedObject(new JSC::JSCGLibWrapperObject(wrappedObject, destroyFunction));
m_cachedJSWrappers->set(wrappedObject, object);
}
if (prototype)
JSObjectSetPrototype(jsContext, toRef(object), prototype);
else if (auto* jsPrototype = jsClass->prototype(globalObject))
object->setPrototypeDirect(vm, jsPrototype);
return object;
}
JSGlobalContextRef WrapperMap::createContextWithJSWrapper(JSContextGroupRef jsGroup, JSClassRef jsClass, JSValueRef prototype, gpointer wrappedObject, GDestroyNotify destroyFunction)
{
Ref<VM> vm(*toJS(jsGroup));
JSLockHolder locker(vm.ptr());
auto* globalObject = JSCallbackObject<JSAPIWrapperGlobalObject>::create(vm.get(), jsClass, JSCallbackObject<JSAPIWrapperGlobalObject>::createStructure(vm.get(), nullptr, jsNull()));
if (wrappedObject) {
globalObject->setWrappedObject(new JSC::JSCGLibWrapperObject(wrappedObject, destroyFunction));
m_cachedJSWrappers->set(wrappedObject, globalObject);
}
if (prototype)
globalObject->resetPrototype(vm.get(), toJS(globalObject, prototype));
else if (auto jsPrototype = jsClass->prototype(globalObject))
globalObject->resetPrototype(vm.get(), jsPrototype);
else
globalObject->resetPrototype(vm.get(), jsNull());
return JSGlobalContextRetain(toGlobalRef(globalObject));
}
JSObject* WrapperMap::jsWrapper(gpointer wrappedObject) const
{
if (!wrappedObject)
return nullptr;
return m_cachedJSWrappers->get(wrappedObject);
}
gpointer WrapperMap::wrappedObject(JSGlobalContextRef jsContext, JSObjectRef jsObject) const
{
ASSERT(toJSGlobalObject(jsContext)->wrapperMap() == this);
JSLockHolder locker(toJS(jsContext));
VM& vm = toJS(jsContext)->vm();
auto* object = toJS(jsObject);
if (object->inherits(vm, JSC::JSCallbackObject<JSC::JSAPIWrapperObject>::info())) {
if (auto* wrapper = JSC::jsCast<JSC::JSAPIWrapperObject*>(object)->wrappedObject())
return static_cast<JSC::JSCGLibWrapperObject*>(wrapper)->object();
}
if (object->inherits(vm, JSC::JSCallbackObject<JSC::JSAPIWrapperGlobalObject>::info())) {
if (auto* wrapper = JSC::jsCast<JSC::JSAPIWrapperGlobalObject*>(object)->wrappedObject())
return wrapper->object();
}
return nullptr;
}
} // namespace JSC