This commit is contained in:
ksuprynowicz 2023-02-19 15:28:32 +01:00
parent f65e72c8f2
commit 5cf32a968c
14 changed files with 142 additions and 17 deletions

View file

@ -1,4 +1,4 @@
'use strict';
'no use strict';
//
// activator-doppleganger.js
//
@ -23,6 +23,8 @@
autoUpdate: true
});
// V8TODO: does this need to be fixed? Right now it refers to global object in non-strict mode,
// and in strict mode it's undefined
this.preload = function(entityID) {
thisEntityID = entityID;
}

View file

@ -77,6 +77,7 @@ WindowScriptingInterface::~WindowScriptingInterface() {
}
ScriptValue WindowScriptingInterface::hasFocus() {
Q_ASSERT(engine);
return engine()->newValue(qApp->hasFocus());
}
@ -105,6 +106,7 @@ void WindowScriptingInterface::alert(const QString& message) {
/// \param const QString& message message to display
/// \return ScriptValue `true` if 'Yes' was clicked, `false` otherwise
ScriptValue WindowScriptingInterface::confirm(const QString& message) {
Q_ASSERT(engine);
return engine()->newValue((QMessageBox::Yes == OffscreenUi::question("", message, QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes)));
}
@ -114,6 +116,7 @@ ScriptValue WindowScriptingInterface::confirm(const QString& message) {
/// \return ScriptValue string text value in text box if the dialog was accepted, `null` otherwise.
ScriptValue WindowScriptingInterface::prompt(const QString& message, const QString& defaultText) {
QString result = OffscreenUi::getText(nullptr, "", message, QLineEdit::Normal, defaultText);
Q_ASSERT(engine);
auto sResult = engine()->newValue(result);
if (sResult.equals(engine()->newValue(""))) {
return engine()->nullValue();
@ -232,6 +235,7 @@ ScriptValue WindowScriptingInterface::browseDir(const QString& title, const QStr
if (!result.isEmpty()) {
setPreviousBrowseLocation(QFileInfo(result).absolutePath());
}
Q_ASSERT(engine);
return result.isEmpty() ? engine()->nullValue() : engine()->newValue(result);
}
@ -276,6 +280,7 @@ ScriptValue WindowScriptingInterface::browse(const QString& title, const QString
if (!result.isEmpty()) {
setPreviousBrowseLocation(QFileInfo(result).absolutePath());
}
Q_ASSERT(engine);
return result.isEmpty() ? engine()->nullValue() : engine()->newValue(result);
}
@ -323,6 +328,7 @@ ScriptValue WindowScriptingInterface::save(const QString& title, const QString&
if (!result.isEmpty()) {
setPreviousBrowseLocation(QFileInfo(result).absolutePath());
}
Q_ASSERT(engine);
return result.isEmpty() ? engine()->nullValue() : engine()->newValue(result);
}
@ -373,6 +379,7 @@ ScriptValue WindowScriptingInterface::browseAssets(const QString& title, const Q
if (!result.isEmpty()) {
setPreviousBrowseAssetLocation(QFileInfo(result).absolutePath());
}
Q_ASSERT(engine);
return result.isEmpty() ? engine()->nullValue() : engine()->newValue(result);
}

View file

@ -2557,6 +2557,7 @@ QDataStream& operator>>(QDataStream& in, AttachmentData& attachment) {
void AttachmentDataObject::setModelURL(const QString& modelURL) {
AttachmentData data = scriptvalue_cast<AttachmentData>(thisObject());
data.modelURL = modelURL;
Q_ASSERT(engine);
thisObject() = engine()->toScriptValue(data);
}
@ -2567,6 +2568,7 @@ QString AttachmentDataObject::getModelURL() const {
void AttachmentDataObject::setJointName(const QString& jointName) {
AttachmentData data = scriptvalue_cast<AttachmentData>(thisObject());
data.jointName = jointName;
Q_ASSERT(engine);
thisObject() = engine()->toScriptValue(data);
}
@ -2577,6 +2579,7 @@ QString AttachmentDataObject::getJointName() const {
void AttachmentDataObject::setTranslation(const glm::vec3& translation) {
AttachmentData data = scriptvalue_cast<AttachmentData>(thisObject());
data.translation = translation;
Q_ASSERT(engine);
thisObject() = engine()->toScriptValue(data);
}
@ -2587,6 +2590,7 @@ glm::vec3 AttachmentDataObject::getTranslation() const {
void AttachmentDataObject::setRotation(const glm::quat& rotation) {
AttachmentData data = scriptvalue_cast<AttachmentData>(thisObject());
data.rotation = rotation;
Q_ASSERT(engine);
thisObject() = engine()->toScriptValue(data);
}
@ -2597,6 +2601,7 @@ glm::quat AttachmentDataObject::getRotation() const {
void AttachmentDataObject::setScale(float scale) {
AttachmentData data = scriptvalue_cast<AttachmentData>(thisObject());
data.scale = scale;
Q_ASSERT(engine);
thisObject() = engine()->toScriptValue(data);
}
@ -2607,6 +2612,7 @@ float AttachmentDataObject::getScale() const {
void AttachmentDataObject::setIsSoft(bool isSoft) {
AttachmentData data = scriptvalue_cast<AttachmentData>(thisObject());
data.isSoft = isSoft;
Q_ASSERT(engine);
thisObject() = engine()->toScriptValue(data);
}

View file

@ -73,6 +73,7 @@ void AssetScriptingInterface::uploadData(QString data, const ScriptValue& callba
auto upload = DependencyManager::get<AssetClient>()->createUpload(dataByteArray);
Promise deferred = makePromise(__FUNCTION__);
Q_ASSERT(engine);
auto scriptEngine = engine();
deferred->ready([=](QString error, QVariantMap result) {
auto url = result.value("url").toString();
@ -96,6 +97,7 @@ void AssetScriptingInterface::setMapping(QString path, QString hash, const Scrip
auto handler = jsBindCallback(thisObject(), callback);
auto setMappingRequest = assetClient()->createSetMappingRequest(path, hash);
Promise deferred = makePromise(__FUNCTION__);
Q_ASSERT(engine);
auto scriptEngine = engine();
deferred->ready([=](QString error, QVariantMap result) {
jsCallback(handler, scriptEngine->newValue(error), result);
@ -133,6 +135,7 @@ void AssetScriptingInterface::downloadData(QString urlString, const ScriptValue&
auto assetRequest = assetClient->createRequest(hash);
Promise deferred = makePromise(__FUNCTION__);
Q_ASSERT(engine);
auto scriptEngine = engine();
deferred->ready([=](QString error, QVariantMap result) {
// FIXME: to remain backwards-compatible the signature here is "callback(data, n/a)"
@ -196,6 +199,7 @@ void AssetScriptingInterface::getMapping(QString asset, const ScriptValue& callb
JS_VERIFY(AssetUtils::isValidFilePath(path), "invalid ATP file path: " + asset + "(path:"+path+")");
JS_VERIFY(callback.isFunction(), "expected second parameter to be a callback function");
Promise promise = getAssetInfo(path);
Q_ASSERT(engine);
auto scriptEngine = engine();
promise->ready([=](QString error, QVariantMap result) {
jsCallback(handler, scriptEngine->newValue(error), scriptEngine->newValue(result.value("hash").toString()));
@ -229,6 +233,7 @@ Promise AssetScriptingInterface::jsPromiseReady(Promise promise, const ScriptVal
if (!jsVerify(handler.isValid(), "jsPromiseReady -- invalid callback handler")) {
return nullptr;
}
Q_ASSERT(engine);
auto scriptEngine = engine();
return promise->ready([this, handler, scriptEngine](QString error, QVariantMap result) {
jsCallback(handler, scriptEngine->newValue(error), result);
@ -238,6 +243,7 @@ Promise AssetScriptingInterface::jsPromiseReady(Promise promise, const ScriptVal
void AssetScriptingInterface::jsCallback(const ScriptValue& handler,
const ScriptValue& error, const ScriptValue& result) {
Q_ASSERT(thread() == QThread::currentThread());
Q_ASSERT(engine);
auto errorValue = !error.toBool() ? engine()->nullValue() : error;
JS_VERIFY(handler.isObject() && handler.property("callback").isFunction(),
QString("jsCallback -- .callback is not a function (%1)")
@ -536,6 +542,7 @@ void AssetScriptingInterface::loadFromCache(const ScriptValue& options, const Sc
}
bool AssetScriptingInterface::canWriteCacheValue(const QUrl& url) {
Q_ASSERT(engine);
auto scriptManager = engine()->manager();
if (!scriptManager) {
return false;

View file

@ -80,12 +80,14 @@ ScriptValue ConsoleScriptingInterface::exception(ScriptContext* context, ScriptE
void ConsoleScriptingInterface::time(QString labelName) {
_timerDetails.insert(labelName, QDateTime::currentDateTime().toUTC());
QString message = QString("%1: Timer started").arg(labelName);
Q_ASSERT(engine);
if (ScriptManager* scriptManager = engine()->manager()) {
scriptManager->scriptPrintedMessage(message);
}
}
void ConsoleScriptingInterface::timeEnd(QString labelName) {
Q_ASSERT(engine);
if (ScriptManager* scriptManager = engine()->manager()) {
if (!_timerDetails.contains(labelName)) {
scriptManager->scriptErrorMessage("No such label found " + labelName);
@ -134,6 +136,7 @@ ScriptValue ConsoleScriptingInterface::assertion(ScriptContext* context, ScriptE
}
void ConsoleScriptingInterface::trace() {
Q_ASSERT(engine);
ScriptEnginePointer scriptEngine = engine();
if (ScriptManager* scriptManager = scriptEngine->manager()) {
scriptManager->scriptPrintedMessage
@ -143,6 +146,7 @@ void ConsoleScriptingInterface::trace() {
}
void ConsoleScriptingInterface::clear() {
Q_ASSERT(engine);
if (ScriptManager* scriptManager = engine()->manager()) {
scriptManager->clearDebugLogWindow();
}

View file

@ -88,6 +88,7 @@ void Mat4::print(const QString& label, const glm::mat4& m, bool transpose) const
QString message = QString("%1 %2").arg(qPrintable(label));
message = message.arg(glm::to_string(out).c_str());
qCDebug(scriptengine) << message;
Q_ASSERT(engine);
if (ScriptManager* scriptManager = engine()->manager()) {
scriptManager->print(message);
}

View file

@ -124,6 +124,7 @@ void Quat::print(const QString& label, const glm::quat& q, bool asDegrees) {
message = message.arg(glm::to_string(glm::dquat(q)).c_str());
}
qCDebug(scriptengine) << message;
Q_ASSERT(engine);
if (ScriptManager* scriptManager = engine()->manager()) {
scriptManager->print(message);
}

View file

@ -43,6 +43,7 @@ void ScriptUUID::print(const QString& label, const QUuid& id) {
QString message = QString("%1 %2").arg(qPrintable(label));
message = message.arg(id.toString());
qCDebug(scriptengine) << message;
Q_ASSERT(engine);
if (ScriptManager* scriptManager = engine()->manager()) {
scriptManager->print(message);
}

View file

@ -37,6 +37,7 @@ void Vec3::print(const QString& label, const glm::vec3& v) {
QString message = QString("%1 %2").arg(qPrintable(label));
message = message.arg(glm::to_string(glm::dvec3(v)).c_str());
qCDebug(scriptengine) << message;
Q_ASSERT(engine);
if (ScriptManager* scriptManager = engine()->manager()) {
scriptManager->print(message);
}

View file

@ -427,7 +427,6 @@ ScriptEngineV8::ScriptEngineV8(ScriptManager* scriptManager) :
v8::Context::Scope contextScope(context);
_contexts.append(std::make_shared<ScriptContextV8Wrapper>(this,context, ScriptContextPointer()));
V8ScriptValue nullScriptValue(this, v8::Null(_v8Isolate));
_nullValue = ScriptValue(new ScriptValueV8Wrapper(this, nullScriptValue));
@ -802,6 +801,32 @@ const v8::Local<v8::Context> ScriptEngineV8::getConstContext() const {
Q_ASSERT(!_contexts.isEmpty());
return handleScope.Escape(_contexts.last().get()->toV8Value());
}
// Stored objects are used to create global objects for evaluateInClosure
void ScriptEngineV8::storeGlobalObjectContents() {
if (areGlobalObjectContentsStored) {
return;
}
v8::Locker locker(_v8Isolate);
v8::Isolate::Scope isolateScope(_v8Isolate);
v8::HandleScope handleScope(_v8Isolate);
auto context = getContext();
v8::Context::Scope contextScope(context);
v8::Local<v8::Object> globalMemberObjects = v8::Object::New(_v8Isolate);
auto globalMemberNames = context->Global()->GetPropertyNames(context).ToLocalChecked();
for (size_t i = 0; i < globalMemberNames->Length(); i++) {
auto name = globalMemberNames->Get(context, i).ToLocalChecked();
if(!globalMemberObjects->Set(context, name, context->Global()->Get(context, name).ToLocalChecked()).FromMaybe(false)) {
Q_ASSERT(false);
}
}
_globalObjectContents.Reset(_v8Isolate, globalMemberObjects);
qDebug() << "ScriptEngineV8::storeGlobalObjectContents: " << globalMemberNames->Length() << " objects stored";
areGlobalObjectContentsStored = true;
}
ScriptValue ScriptEngineV8::evaluateInClosure(const ScriptValue& _closure,
const ScriptProgramPointer& _program) {
PROFILE_RANGE(script, "evaluateInClosure");
@ -812,6 +837,7 @@ ScriptValue ScriptEngineV8::evaluateInClosure(const ScriptValue& _closure,
v8::Locker locker(_v8Isolate);
v8::Isolate::Scope isolateScope(_v8Isolate);
v8::HandleScope handleScope(_v8Isolate);
storeGlobalObjectContents();
v8::Local<v8::Object> closureObject;
//v8::Local<v8::Value> oldGlobal;
@ -896,6 +922,7 @@ ScriptValue ScriptEngineV8::evaluateInClosure(const ScriptValue& _closure,
if (!unwrappedProgram->compile()) {
qDebug(scriptengine) << "Can't compile script for evaluating in closure";
Q_ASSERT(false);
popContext();
return nullValue();
}
const V8ScriptProgram& program = unwrappedProgram->toV8Value();
@ -928,18 +955,35 @@ ScriptValue ScriptEngineV8::evaluateInClosure(const ScriptValue& _closure,
{
v8::TryCatch tryCatch(getIsolate());
// Since V8 cannot use arbitrary object as global object, objects from main global need to be copied to closure's global object
auto oldGlobalMemberNames = oldContext->Global()->GetPropertyNames(oldContext).ToLocalChecked();
for (size_t i = 0; i < oldGlobalMemberNames->Length(); i++) {
auto name = oldGlobalMemberNames->Get(closureContext, i).ToLocalChecked();
if(!closureContext->Global()->Set(closureContext, name, oldContext->Global()->Get(oldContext, name).ToLocalChecked()).FromMaybe(false)) {
auto globalObjectContents = _globalObjectContents.Get(_v8Isolate);
auto globalMemberNames = globalObjectContents->GetPropertyNames(globalObjectContents->CreationContext()).ToLocalChecked();
for (size_t i = 0; i < globalMemberNames->Length(); i++) {
auto name = globalMemberNames->Get(closureContext, i).ToLocalChecked();
if(!closureContext->Global()->Set(closureContext, name, globalObjectContents->Get(globalObjectContents->CreationContext(), name).ToLocalChecked()).FromMaybe(false)) {
Q_ASSERT(false);
}
}
qDebug() << "ScriptEngineV8::evaluateInClosure: " << globalMemberNames->Length() << " objects added to global";
/*auto oldGlobalMemberNames = oldContext->Global()->GetPropertyNames(oldContext).ToLocalChecked();
//auto oldGlobalMemberNames = oldContext->Global()->GetPropertyNames(closureContext).ToLocalChecked();
for (size_t i = 0; i < oldGlobalMemberNames->Length(); i++) {
auto name = oldGlobalMemberNames->Get(closureContext, i).ToLocalChecked();
//auto name = oldGlobalMemberNames->Get(oldContext, i).ToLocalChecked();
if(!closureContext->Global()->Set(closureContext, name, oldContext->Global()->Get(oldContext, name).ToLocalChecked()).FromMaybe(false)) {
//if(!closureContext->Global()->Set(closureContext, name, oldContext->Global()->Get(closureContext, name).ToLocalChecked()).FromMaybe(false)) {
Q_ASSERT(false);
}
}*/
// Objects from closure need to be copied to global object too
// V8TODO: I'm not sure which context to use with Get
auto closureMemberNames = closureObject->GetPropertyNames(closureContext).ToLocalChecked();
//auto closureMemberNames = closureObject->GetPropertyNames(oldContext).ToLocalChecked();
for (size_t i = 0; i < closureMemberNames->Length(); i++) {
auto name = closureMemberNames->Get(closureContext, i).ToLocalChecked();
//auto name = closureMemberNames->Get(oldContext, i).ToLocalChecked();
if(!closureContext->Global()->Set(closureContext, name, closureObject->Get(closureContext, name).ToLocalChecked()).FromMaybe(false)) {
//if(!closureContext->Global()->Set(closureContext, name, closureObject->Get(oldContext, name).ToLocalChecked()).FromMaybe(false)) {
Q_ASSERT(false);
}
}
@ -1455,6 +1499,7 @@ ScriptContext* ScriptEngineV8::currentContext() const {
// I'm not sure how to do this without discarding const
_currContext = std::make_shared<ScriptContextV8Wrapper>(const_cast<ScriptEngineV8*>(this));
}*/
// V8TODO: add FunctionCallbackInfo or PropertyCallbackInfo when necessary
return _contexts.last().get();
}
@ -1501,7 +1546,7 @@ ScriptValue ScriptEngineV8::newFunction(ScriptEngine::FunctionSignature fun, int
ScriptEngineV8 *scriptEngine = reinterpret_cast<ScriptEngineV8*>
(object->GetAlignedPointerFromInternalField(1));
ScriptContextV8Wrapper scriptContext(scriptEngine, &info, scriptEngine->getContext(), scriptEngine->currentContext()->parentContext());
//V8TODO: this scriptContext needs to have FunctionCallbackInfo added
ScriptContextGuard scriptContextGuard(&scriptContext);
ScriptValue result = function(&scriptContext, scriptEngine);
ScriptValueV8Wrapper* unwrapped = ScriptValueV8Wrapper::unwrap(result);
if (unwrapped) {

View file

@ -202,6 +202,8 @@ public: // not for public use, but I don't like how Qt strings this along with p
ScriptContextV8Pointer pushContext(v8::Local<v8::Context> context);
void popContext();
// V8TODO: call this after initializing global object
void storeGlobalObjectContents();
protected:
// like `newFunction`, but allows mapping inline C++ lambdas with captures as callable V8ScriptValues
@ -240,6 +242,8 @@ protected:
//mutable ScriptContextV8Pointer _currContext;
// Current context stack. Main context is first on the list and current one is last.
QList<ScriptContextV8Pointer> _contexts;
v8::Persistent<v8::Object> _globalObjectContents;
bool areGlobalObjectContentsStored {false};
//V8TODO
//ArrayBufferClass* _arrayBufferClass;

View file

@ -39,9 +39,9 @@ static const void *internalPointsToMethodProxy = (void *)0x13373000;
// 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
class ScriptPropertyContextQtWrapper final : public ScriptContext {
class ScriptPropertyContextV8Wrapper final : public ScriptContext {
public: // construction
inline ScriptPropertyContextQtWrapper(const ScriptValue& object, ScriptContext* parentContext) :
inline ScriptPropertyContextV8Wrapper(const ScriptValue& object, ScriptContext* parentContext) :
_parent(parentContext), _object(object) {}
public: // ScriptContext implementation
@ -568,7 +568,7 @@ V8ScriptValue ScriptObjectV8Proxy::property(const V8ScriptValue& object, const V
QMetaProperty prop = metaObject->property(propId);
ScriptValue scriptThis = ScriptValue(new ScriptValueV8Wrapper(_engine, object));
ScriptPropertyContextQtWrapper ourContext(scriptThis, _engine->currentContext());
ScriptPropertyContextV8Wrapper ourContext(scriptThis, _engine->currentContext());
ScriptContextGuard guard(&ourContext);
QVariant varValue = prop.read(qobject);
@ -611,7 +611,7 @@ V8ScriptValue ScriptObjectV8Proxy::property(const V8ScriptValue& object, const V
ScriptEngine::QObjectWrapOptions options = ScriptEngine::ExcludeSuperClassContents |
//V8TODO ScriptEngine::ExcludeDeleteLater |
ScriptEngine::PreferExistingWrapperObject;
//V8TODO: why is it returning new object every time?
// It's not necessarily new, newQObject looks for it first in object wrapper map
return ScriptObjectV8Proxy::newQObject(_engine, proxy, ScriptEngine::ScriptOwnership, options);
//return _engine->newQObject(proxy, ScriptEngine::ScriptOwnership, options);
}
@ -642,7 +642,7 @@ void ScriptObjectV8Proxy::setProperty(V8ScriptValue& object, const V8ScriptStrin
QMetaProperty prop = metaObject->property(propId);
ScriptValue scriptThis = ScriptValue(new ScriptValueV8Wrapper(_engine, object));
ScriptPropertyContextQtWrapper ourContext(scriptThis, _engine->currentContext());
ScriptPropertyContextV8Wrapper ourContext(scriptThis, _engine->currentContext());
ScriptContextGuard guard(&ourContext);
int propTypeId = prop.userType();
@ -883,8 +883,10 @@ void ScriptMethodV8Proxy::call(const v8::FunctionCallbackInfo<v8::Value>& argume
}
if (isValidMetaSelected) {
//ScriptContextV8Wrapper ourContext(_engine, context);
//ScriptContextGuard guard(&ourContext);
// V8TODO: is this the correct wrapper?
ScriptContextV8Wrapper ourContext(_engine, &arguments, _engine->getContext(),
_engine->currentContext()->parentContext());
ScriptContextGuard guard(&ourContext);
const QMetaMethod& meta = _metas[bestMeta];
int returnTypeId = meta.returnType();
QVector <QGenericArgument> &qGenArgs = qGenArgsVectors[bestMeta];
@ -1333,8 +1335,15 @@ void ScriptSignalV8Proxy::connect(ScriptValue arg0, ScriptValue arg1) {
v8::Local<v8::Function> destFunction = v8::Local<v8::Function>::Cast(callback.get());
v8::Local<v8::String> destDataName = v8::String::NewFromUtf8(isolate, "__data__").ToLocalChecked();
v8::Local<v8::Value> destData;
auto destFunctionContext = destFunction->CreationContext();
// V8TODO: I'm not sure which context to use here
//auto destFunctionContext = destFunction->CreationContext();
auto destFunctionContext = _engine->getContext();
Q_ASSERT(thisObject().isObject());
V8ScriptValue v8ThisObject = ScriptValueV8Wrapper::fullUnwrap(_engine, thisObject());
Q_ASSERT(ScriptObjectV8Proxy::unwrapProxy(v8ThisObject));
ScriptSignalV8Proxy* thisProxy = dynamic_cast<ScriptSignalV8Proxy*>(ScriptObjectV8Proxy::unwrapProxy(v8ThisObject)->toQObject());
Q_ASSERT(thisProxy);
qDebug(scriptengine) << "ScriptSignalV8Proxy::connect: " << thisProxy->fullName() << " fullName: " << fullName();
//Q_ASSERT(destFunction->InternalFieldCount() == 4);
//Q_ASSERT(destData.get()->IsArray());
//v8::Local<v8::Value> destData = destFunction->GetInternalField(3);
@ -1344,15 +1353,27 @@ void ScriptSignalV8Proxy::connect(ScriptValue arg0, ScriptValue arg1) {
if (destData->IsArray()) {
v8::Local<v8::Array> destArray = v8::Local<v8::Array>::Cast(destData);
int length = destArray->Length();//destData.property("length").toInteger();
// V8TODO: Maybe copying array is unnecessary?
v8::Local<v8::Array> newArray = v8::Array::New(isolate, length + 1);
bool foundIt = false;
for (int idx = 0; idx < length && !foundIt; ++idx) {
v8::Local<v8::Value> entry = destArray->Get(destFunctionContext, idx).ToLocalChecked();
{
qDebug() << "ScriptSignalV8Proxy::connect: entry details: " << _engine->scriptValueDebugDetailsV8(V8ScriptValue(_engine, entry));
Q_ASSERT(entry->IsObject());
V8ScriptValue v8EntryObject(_engine, entry);
Q_ASSERT(ScriptObjectV8Proxy::unwrapProxy(v8EntryObject));
// For debugging
ScriptSignalV8Proxy* entryProxy = dynamic_cast<ScriptSignalV8Proxy*>(ScriptObjectV8Proxy::unwrapProxy(v8EntryObject)->toQObject());
Q_ASSERT(thisProxy);
qDebug(scriptengine) << "ScriptSignalV8Proxy::connect: entry proxy: " << entryProxy->fullName();
}
if (!newArray->Set(destFunctionContext, idx, entry).FromMaybe(false)) {
Q_ASSERT(false);
}
}
if (!newArray->Set(destFunctionContext, length, v8ThisObject.get()).FromMaybe(false)) {
//if (!newArray->Set(destFunctionContext, length, v8ThisObject.get()).FromMaybe(false)) {
Q_ASSERT(false);
}
if (!destFunction->Set(destFunctionContext, destDataName, newArray).FromMaybe(false)) {
@ -1448,8 +1469,16 @@ void ScriptSignalV8Proxy::disconnect(ScriptValue arg0, ScriptValue arg1) {
v8::Local<v8::Function> destFunction = v8::Local<v8::Function>::Cast(callback.get());
v8::Local<v8::String> destDataName = v8::String::NewFromUtf8(isolate, "__data__").ToLocalChecked();
v8::Local<v8::Value> destData;
auto destFunctionContext = destFunction->CreationContext();
//auto destFunctionContext = destFunction->CreationContext();
auto destFunctionContext = _engine->getContext();
Q_ASSERT(thisObject().isObject());
V8ScriptValue v8ThisObject = ScriptValueV8Wrapper::fullUnwrap(_engine, thisObject());
Q_ASSERT(ScriptObjectV8Proxy::unwrapProxy(v8ThisObject));
// For debugging
ScriptSignalV8Proxy* thisProxy = dynamic_cast<ScriptSignalV8Proxy*>(ScriptObjectV8Proxy::unwrapProxy(v8ThisObject)->toQObject());
Q_ASSERT(thisProxy);
qDebug(scriptengine) << "ScriptSignalV8Proxy::disconnect: " << thisProxy->fullName() << " fullName: " << fullName();
//V8ScriptValue destData = callback.data();
//Q_ASSERT(destData->IsArray());
if (!destFunction->Get(destFunctionContext, destDataName).ToLocal(&destData)) {
@ -1463,8 +1492,22 @@ void ScriptSignalV8Proxy::disconnect(ScriptValue arg0, ScriptValue arg1) {
int newIndex = 0;
for (int idx = 0; idx < length && !foundIt; ++idx) {
v8::Local<v8::Value> entry = destArray->Get(destFunctionContext, idx).ToLocalChecked();
// For debugging:
{
_engine->logBacktrace("ScriptSignalV8Proxy::disconnect");
qDebug() << "ScriptSignalV8Proxy::disconnect: entry details: " << _engine->scriptValueDebugDetailsV8(V8ScriptValue(_engine, entry));
Q_ASSERT(entry->IsObject());
V8ScriptValue v8EntryObject(_engine, entry);
Q_ASSERT(ScriptObjectV8Proxy::unwrapProxy(v8EntryObject));
// For debugging
ScriptSignalV8Proxy* entryProxy = dynamic_cast<ScriptSignalV8Proxy*>(ScriptObjectV8Proxy::unwrapProxy(v8EntryObject)->toQObject());
Q_ASSERT(thisProxy);
qDebug(scriptengine) << "ScriptSignalV8Proxy::disconnect: entry proxy: " << entryProxy->fullName();
}
if (entry->StrictEquals(v8ThisObject.get())) {
//V8TODO: compare proxies instead?
foundIt = true;
qDebug() << "ScriptSignalV8Proxy::disconnect foundIt";
//V8ScriptValueList args;
//args << idx << 1;
//destData.property("splice").call(destData, args);

View file

@ -235,12 +235,14 @@ private: // implementation
virtual int qt_metacall(QMetaObject::Call call, int id, void** arguments) override;
int discoverMetaCallIdx();
ConnectionList::iterator findConnection(V8ScriptValue thisObject, V8ScriptValue callback);
QString fullName() const;
//QString fullName() const;
public: // API
// arg1 was had Null default value, but that needs isolate pointer to create Null in V8
virtual void connect(ScriptValue arg0, ScriptValue arg1 = ScriptValue()) override;
virtual void disconnect(ScriptValue arg0, ScriptValue arg1 = ScriptValue()) override;
//Moved to public temporarily for debugging:
QString fullName() const;
//virtual void connect(V8ScriptValue arg0) override;
//virtual void disconnect(V8ScriptValue arg0) override;

View file

@ -162,6 +162,7 @@ namespace REPLACE_ME_WITH_UNIQUE_NAME {
* settings = null; // optional best pratice; allows the object to be reclaimed ASAP by the JS garbage collector
*/
ScriptValue getScopedSettings(const QString& scope) {
Q_ASSERT(engine);
auto engine = Scriptable::engine();
if (!engine) {
return ScriptValue();