mirror of
https://github.com/lubosz/overte.git
synced 2025-04-09 08:22:30 +02:00
Addeed V8 getters/setters to ScriptVariantV8Proxy, fixed animation scripting
This commit is contained in:
parent
4e91765a3f
commit
27554da415
4 changed files with 173 additions and 10 deletions
|
@ -44,6 +44,8 @@ inline ScriptValue scriptValueFromValue<QVariant>(ScriptEngine* engine, const QV
|
|||
return engine->create(v.userType(), v.data());
|
||||
}
|
||||
|
||||
// V8TODO: check if it's typesafe
|
||||
// V8TODO: run through debugger for AnimationPointer/AnimationObject
|
||||
template <typename T>
|
||||
inline T scriptvalue_cast(const ScriptValue& value) {
|
||||
const int id = qMetaTypeId<T>();
|
||||
|
@ -62,6 +64,7 @@ inline T scriptvalue_cast(const ScriptValue& value) {
|
|||
return T();
|
||||
}
|
||||
|
||||
// V8TODO: check if it's typesafe
|
||||
template <>
|
||||
inline QVariant scriptvalue_cast<QVariant>(const ScriptValue& value) {
|
||||
return value.toVariant();
|
||||
|
|
|
@ -550,6 +550,14 @@ bool ScriptEngineV8::castValueToVariant(const V8ScriptValue& v8Val, QVariant& de
|
|||
dest = QVariant::fromValue(obj);
|
||||
break;
|
||||
}
|
||||
// check if it's a pointer to QVariant
|
||||
{
|
||||
QVariant var = *ScriptVariantV8Proxy::unwrapQVariantPointer(_v8Isolate, v8Val.constGet());
|
||||
if (var.isValid()) {
|
||||
dest = var;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// check to see if we have a registered prototype
|
||||
{
|
||||
QVariant var = ScriptVariantV8Proxy::unwrap(v8Val);
|
||||
|
|
|
@ -38,6 +38,9 @@ static const void *internalPointsToQObjectProxy = (void *)0x13370000;
|
|||
static const void *internalPointsToQVariantProxy = (void *)0x13371000;
|
||||
//static const void *internalPointsToSignalProxy = (void *)0x13372000;
|
||||
static const void *internalPointsToMethodProxy = (void *)0x13373000;
|
||||
// This is used to pass object in ScriptVariantV8Proxy to methods of prototype object, for example passing AnimationPointer to AnimationObject
|
||||
// Object is then converted using scriptvalue_cast for use inside the prototype
|
||||
static const void *internalPointsToQVariant = (void *)0x13374000;
|
||||
|
||||
// Used strictly to replace the "this" object value for property access. May expand to a full context element
|
||||
// if we find it necessary to, but hopefully not needed
|
||||
|
@ -703,6 +706,17 @@ void ScriptObjectV8Proxy::setProperty(V8ScriptValue& object, const V8ScriptStrin
|
|||
|
||||
ScriptVariantV8Proxy::ScriptVariantV8Proxy(ScriptEngineV8* engine, const QVariant& variant, V8ScriptValue scriptProto, ScriptObjectV8Proxy* proto) :
|
||||
_engine(engine), _variant(variant), _scriptProto(scriptProto), _proto(proto) {
|
||||
auto isolate = engine->getIsolate();
|
||||
v8::Locker locker(isolate);
|
||||
v8::Isolate::Scope isolateScope(isolate);
|
||||
v8::HandleScope handleScope(isolate);
|
||||
v8::Context::Scope contextScope(engine->getContext());
|
||||
auto variantDataTemplate = v8::ObjectTemplate::New(isolate);
|
||||
variantDataTemplate->SetInternalFieldCount(2);
|
||||
auto variantData = variantDataTemplate->NewInstance(engine->getContext()).ToLocalChecked();
|
||||
variantData->SetAlignedPointerInInternalField(0, const_cast<void*>(internalPointsToQVariant));
|
||||
variantData->SetAlignedPointerInInternalField(1, reinterpret_cast<void*>(&_variant));
|
||||
_v8Object.Reset(isolate, v8::Local<v8::Object>::Cast(variantData));
|
||||
_name = QString::fromLatin1(variant.typeName());
|
||||
}
|
||||
|
||||
|
@ -711,7 +725,7 @@ ScriptVariantV8Proxy::~ScriptVariantV8Proxy() {
|
|||
v8::Locker locker(isolate);
|
||||
v8::Isolate::Scope isolateScope(isolate);
|
||||
v8::HandleScope handleScope(isolate);
|
||||
_v8ObjectTemplate.Reset();
|
||||
//_v8ObjectTemplate.Reset();
|
||||
_v8Object.Reset();
|
||||
}
|
||||
|
||||
|
@ -728,14 +742,15 @@ V8ScriptValue ScriptVariantV8Proxy::newVariant(ScriptEngineV8* engine, const QVa
|
|||
return V8ScriptValue(engine, v8::Undefined(isolate));
|
||||
}
|
||||
// V8TODO probably needs connection to be deleted
|
||||
// V8TODO what to do with proto variable?
|
||||
auto proxy = new ScriptVariantV8Proxy(engine, variant, proto, protoProxy);
|
||||
auto variantDataTemplate = v8::ObjectTemplate::New(isolate);
|
||||
variantDataTemplate->SetInternalFieldCount(2);
|
||||
auto variantData = variantDataTemplate->NewInstance(engine->getContext()).ToLocalChecked();
|
||||
variantData->SetAlignedPointerInInternalField(0, const_cast<void*>(internalPointsToQVariantProxy));
|
||||
variantData->SetAlignedPointerInInternalField(1, reinterpret_cast<void*>(proxy));
|
||||
return V8ScriptValue(engine, variantData);
|
||||
|
||||
auto variantProxyTemplate = v8::ObjectTemplate::New(isolate);
|
||||
variantProxyTemplate->SetInternalFieldCount(2);
|
||||
variantProxyTemplate->SetHandler(v8::NamedPropertyHandlerConfiguration(v8Get, v8Set, nullptr, nullptr, v8GetPropertyNames));
|
||||
auto variantProxy = variantProxyTemplate->NewInstance(engine->getContext()).ToLocalChecked();
|
||||
variantProxy->SetAlignedPointerInInternalField(0, const_cast<void*>(internalPointsToQVariantProxy));
|
||||
variantProxy->SetAlignedPointerInInternalField(1, reinterpret_cast<void*>(proxy));
|
||||
return V8ScriptValue(engine, variantProxy);
|
||||
}
|
||||
|
||||
ScriptVariantV8Proxy* ScriptVariantV8Proxy::unwrapProxy(const V8ScriptValue& val) {
|
||||
|
@ -759,9 +774,141 @@ ScriptVariantV8Proxy* ScriptVariantV8Proxy::unwrapProxy(const V8ScriptValue& val
|
|||
return reinterpret_cast<ScriptVariantV8Proxy*>(v8Object->GetAlignedPointerFromInternalField(1));
|
||||
}
|
||||
|
||||
ScriptVariantV8Proxy* ScriptVariantV8Proxy::unwrapProxy(v8::Isolate* isolate, v8::Local<v8::Value> &value) {
|
||||
v8::Locker locker(isolate);
|
||||
v8::Isolate::Scope isolateScope(isolate);
|
||||
v8::HandleScope handleScope(isolate);
|
||||
|
||||
if (!value->IsObject()) {
|
||||
return nullptr;
|
||||
}
|
||||
v8::Local<v8::Object> v8Object = v8::Local<v8::Object>::Cast(value);
|
||||
if (v8Object->InternalFieldCount() != 2) {
|
||||
return nullptr;
|
||||
}
|
||||
if (v8Object->GetAlignedPointerFromInternalField(0) != internalPointsToQVariantProxy) {
|
||||
return nullptr;
|
||||
}
|
||||
return reinterpret_cast<ScriptVariantV8Proxy*>(v8Object->GetAlignedPointerFromInternalField(1));
|
||||
}
|
||||
|
||||
QVariant* ScriptVariantV8Proxy::unwrapQVariantPointer(v8::Isolate* isolate, const v8::Local<v8::Value> &value) {
|
||||
v8::Locker locker(isolate);
|
||||
v8::Isolate::Scope isolateScope(isolate);
|
||||
v8::HandleScope handleScope(isolate);
|
||||
|
||||
if (!value->IsObject()) {
|
||||
return nullptr;
|
||||
}
|
||||
v8::Local<v8::Object> v8Object = v8::Local<v8::Object>::Cast(value);
|
||||
if (v8Object->InternalFieldCount() != 2) {
|
||||
return nullptr;
|
||||
}
|
||||
if (v8Object->GetAlignedPointerFromInternalField(0) != internalPointsToQVariant) {
|
||||
return nullptr;
|
||||
}
|
||||
return reinterpret_cast<QVariant*>(v8Object->GetAlignedPointerFromInternalField(1));
|
||||
}
|
||||
|
||||
|
||||
void ScriptVariantV8Proxy::v8Get(v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
|
||||
v8::HandleScope handleScope(info.GetIsolate());
|
||||
v8::String::Utf8Value utf8Name(info.GetIsolate(), name);
|
||||
v8::Local<v8::Value> objectV8 = info.This();
|
||||
ScriptVariantV8Proxy *proxy = ScriptVariantV8Proxy::unwrapProxy(info.GetIsolate(), objectV8);
|
||||
if (!proxy) {
|
||||
qDebug(scriptengine) << "Proxy object not found when getting: " << *utf8Name;
|
||||
return;
|
||||
}
|
||||
V8ScriptValue object(proxy->_engine, proxy->_v8Object.Get(info.GetIsolate()));
|
||||
|
||||
if (name->IsString()) {
|
||||
V8ScriptString nameString(proxy->_engine, v8::Local<v8::String>::Cast(name));
|
||||
uint id;
|
||||
ScriptObjectV8Proxy::QueryFlags flags = proxy->_proto->queryProperty(object, nameString, ScriptObjectV8Proxy::HandlesReadAccess, &id);
|
||||
if (flags) {
|
||||
V8ScriptValue value = proxy->property(object, nameString, id);
|
||||
info.GetReturnValue().Set(value.get());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
qDebug(scriptengine) << "Value not found: " << *utf8Name;
|
||||
// V8TODO: this is done differently for variant proxy - use internal field of _v8Object instead?
|
||||
/*v8::Local<v8::Value> property;
|
||||
if(info.This()->GetInternalField(2).As<v8::Object>()->Get(proxy->_engine->getContext(), name).ToLocal(&property)) {
|
||||
info.GetReturnValue().Set(property);
|
||||
} else {
|
||||
qDebug(scriptengine) << "Value not found: " << *utf8Value;
|
||||
}*/
|
||||
}
|
||||
|
||||
void ScriptVariantV8Proxy::v8Set(v8::Local<v8::Name> name, v8::Local<v8::Value> value, const v8::PropertyCallbackInfo<v8::Value>& info) {
|
||||
v8::HandleScope handleScope(info.GetIsolate());
|
||||
v8::String::Utf8Value utf8Name(info.GetIsolate(), name);
|
||||
v8::Local<v8::Value> objectV8 = info.This();
|
||||
ScriptVariantV8Proxy *proxy = ScriptVariantV8Proxy::unwrapProxy(info.GetIsolate(), objectV8);
|
||||
if (!proxy) {
|
||||
qDebug(scriptengine) << "Proxy object not found when getting: " << *utf8Name;
|
||||
return;
|
||||
}
|
||||
|
||||
V8ScriptValue object(proxy->_engine, objectV8);
|
||||
if (!name->IsString() && !name->IsSymbol()) {
|
||||
QString notStringMessage("ScriptObjectV8Proxy::v8Set: " + proxy->_engine->scriptValueDebugDetailsV8(V8ScriptValue(proxy->_engine, name)));
|
||||
qDebug(scriptengine) << notStringMessage;
|
||||
Q_ASSERT(false);
|
||||
}
|
||||
|
||||
if (name->IsString()) {
|
||||
V8ScriptString nameString(proxy->_engine, v8::Local<v8::String>::Cast(name));
|
||||
uint id;
|
||||
ScriptObjectV8Proxy::QueryFlags flags = proxy->_proto->queryProperty(object, nameString, ScriptObjectV8Proxy::HandlesWriteAccess, &id);
|
||||
if (flags) {
|
||||
proxy->setProperty(object, nameString, id, V8ScriptValue(proxy->_engine, value));
|
||||
info.GetReturnValue().Set(value);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// V8TODO: this is done differently for variant proxy - use internal field of _v8Object instead?
|
||||
/*if (info.This()->GetInternalField(2).As<v8::Object>()->Set(proxy->_engine->getContext(), name, value).FromMaybe(false)) {
|
||||
info.GetReturnValue().Set(value);
|
||||
} else {
|
||||
qDebug(scriptengine) << "Set failed: " << *utf8Name;
|
||||
}*/
|
||||
qDebug(scriptengine) << "Set failed: " << *utf8Name;
|
||||
}
|
||||
|
||||
void ScriptVariantV8Proxy::v8GetPropertyNames(const v8::PropertyCallbackInfo<v8::Array>& info) {
|
||||
qDebug(scriptengine) << "ScriptObjectV8Proxy::v8GetPropertyNames called";
|
||||
v8::HandleScope handleScope(info.GetIsolate());
|
||||
auto context = info.GetIsolate()->GetCurrentContext();
|
||||
v8::Context::Scope contextScope(context);
|
||||
v8::Local<v8::Value> objectV8 = info.This();
|
||||
ScriptVariantV8Proxy *proxy = ScriptVariantV8Proxy::unwrapProxy(info.GetIsolate(), objectV8);
|
||||
if (!proxy) {
|
||||
qDebug(scriptengine) << "ScriptObjectV8Proxy::v8GetPropertyNames: Proxy object not found when listing";
|
||||
return;
|
||||
}
|
||||
V8ScriptValue object(proxy->_engine, objectV8);
|
||||
v8::Local<v8::Array> properties = proxy->_proto->getPropertyNames();
|
||||
v8::Local<v8::Array> objectProperties;
|
||||
// V8TODO: this is done differently for variant proxy - use internal field of _v8Object instead?
|
||||
/*uint32_t propertiesLength = properties->Length();
|
||||
if (info.This()->GetInternalField(2).As<v8::Object>()->GetPropertyNames(context).ToLocal(&objectProperties)) {
|
||||
for (uint32_t n = 0; n < objectProperties->Length(); n++) {
|
||||
if(!properties->Set(context, propertiesLength+n, objectProperties->Get(context, n).ToLocalChecked()).FromMaybe(false)) {
|
||||
qDebug(scriptengine) << "ScriptObjectV8Proxy::v8GetPropertyNames: Cannot add member name";
|
||||
}
|
||||
}
|
||||
}*/
|
||||
info.GetReturnValue().Set(properties);
|
||||
}
|
||||
|
||||
QVariant ScriptVariantV8Proxy::unwrap(const V8ScriptValue& val) {
|
||||
ScriptVariantV8Proxy* proxy = unwrapProxy(val);
|
||||
return proxy ? proxy->toQVariant() : QVariant();
|
||||
// V8TODO
|
||||
}
|
||||
|
||||
ScriptMethodV8Proxy::ScriptMethodV8Proxy(ScriptEngineV8* engine, QObject* object, V8ScriptValue lifetime,
|
||||
|
|
|
@ -133,6 +133,8 @@ public: // construction
|
|||
|
||||
static V8ScriptValue newVariant(ScriptEngineV8* engine, const QVariant& variant, V8ScriptValue proto);
|
||||
static ScriptVariantV8Proxy* unwrapProxy(const V8ScriptValue& val);
|
||||
static ScriptVariantV8Proxy* unwrapProxy(v8::Isolate* isolate, v8::Local<v8::Value> &value);
|
||||
static QVariant* unwrapQVariantPointer(v8::Isolate* isolate, const v8::Local<v8::Value> &value);
|
||||
static QVariant unwrap(const V8ScriptValue& val);
|
||||
inline QVariant toQVariant() const { return _variant; }
|
||||
//inline QVariant toV8Value() const { return _variant; }
|
||||
|
@ -158,14 +160,17 @@ public: // QScriptClass implementation
|
|||
virtual void setProperty(V8ScriptValue& object, const V8ScriptString& name, uint id, const V8ScriptValue& value) {
|
||||
return _proto->setProperty(object, name, id, value);
|
||||
}
|
||||
static void v8Get(v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info);
|
||||
static void v8Set(v8::Local<v8::Name> name, v8::Local<v8::Value> value_obj, const v8::PropertyCallbackInfo<v8::Value>& info);
|
||||
static void v8GetPropertyNames(const v8::PropertyCallbackInfo<v8::Array>& info);
|
||||
|
||||
private: // storage
|
||||
private:
|
||||
ScriptEngineV8* _engine;
|
||||
QVariant _variant;
|
||||
V8ScriptValue _scriptProto;
|
||||
ScriptObjectV8Proxy* _proto;
|
||||
QString _name;
|
||||
v8::UniquePersistent<v8::ObjectTemplate> _v8ObjectTemplate;
|
||||
//v8::UniquePersistent<v8::ObjectTemplate> _v8ObjectTemplate;
|
||||
v8::UniquePersistent<v8::Object> _v8Object;
|
||||
|
||||
Q_DISABLE_COPY(ScriptVariantV8Proxy)
|
||||
|
|
Loading…
Reference in a new issue