diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp
index 69e246ff28..6e7eb0c9d4 100644
--- a/interface/src/avatar/MyAvatar.cpp
+++ b/interface/src/avatar/MyAvatar.cpp
@@ -2674,8 +2674,7 @@ QVariantList MyAvatar::getAvatarEntitiesVariant() {
EntityItemProperties entityProperties = entity->getProperties(desiredProperties);
{
std::lock_guard guard(_scriptEngineLock);
- ScriptValuePointer scriptProperties;
- scriptProperties = EntityItemPropertiesToScriptValue(_scriptEngine.data(), entityProperties);
+ ScriptValuePointer scriptProperties = EntityItemPropertiesToScriptValue(_scriptEngine.data(), entityProperties);
avatarEntityData["properties"] = scriptProperties->toVariant();
}
avatarEntitiesData.append(QVariant(avatarEntityData));
diff --git a/interface/src/ui/InteractiveWindow.cpp b/interface/src/ui/InteractiveWindow.cpp
index 2f49bc9615..e86b667696 100644
--- a/interface/src/ui/InteractiveWindow.cpp
+++ b/interface/src/ui/InteractiveWindow.cpp
@@ -102,8 +102,10 @@ ScriptValuePointer interactiveWindowPointerToScriptValue(ScriptEngine* engine, c
}
void interactiveWindowPointerFromScriptValue(const ScriptValuePointer& object, InteractiveWindowPointer& out) {
- if (const auto interactiveWindow = qobject_cast(object->toQObject())) {
- out = interactiveWindow;
+ if (!object) {
+ if (const auto interactiveWindow = qobject_cast(object->toQObject())) {
+ out = interactiveWindow;
+ }
}
}
diff --git a/interface/src/ui/JSConsole.cpp b/interface/src/ui/JSConsole.cpp
index cdb819ecb7..de35259816 100644
--- a/interface/src/ui/JSConsole.cpp
+++ b/interface/src/ui/JSConsole.cpp
@@ -375,10 +375,10 @@ void JSConsole::commandFinished() {
_ui->promptTextEdit->setFocus();
}
- bool error = (_scriptManager->engine()->hasUncaughtException() || result->isError());
+ bool error = (_scriptManager->engine()->hasUncaughtException() || (result && result->isError()));
QString gutter = error ? GUTTER_ERROR : GUTTER_PREVIOUS_COMMAND;
QString resultColor = error ? RESULT_ERROR_STYLE : RESULT_SUCCESS_STYLE;
- QString resultStr = "" + result->toString().toHtmlEscaped() + "";
+ QString resultStr = result ? "" + result->toString().toHtmlEscaped() + "" : "";
appendMessage(gutter, resultStr);
resetCurrentCommandHistory();
diff --git a/libraries/animation/src/AnimVariant.cpp b/libraries/animation/src/AnimVariant.cpp
index 9b596b2356..db877bf91a 100644
--- a/libraries/animation/src/AnimVariant.cpp
+++ b/libraries/animation/src/AnimVariant.cpp
@@ -89,11 +89,11 @@ void AnimVariantMap::animVariantMapFromScriptValue(const ScriptValuePointer& sou
while (property->hasNext()) {
property->next();
ScriptValuePointer value = property->value();
- if (value->isBool()) {
+ if (value && value->isBool()) {
set(property->name(), value->toBool());
- } else if (value->isString()) {
+ } else if (value && value->isString()) {
set(property->name(), value->toString());
- } else if (value->isNumber()) {
+ } else if (value && value->isNumber()) {
int asInteger = value->toInt32();
float asFloat = value->toNumber();
if (asInteger == asFloat) {
@@ -102,15 +102,15 @@ void AnimVariantMap::animVariantMapFromScriptValue(const ScriptValuePointer& sou
set(property->name(), asFloat);
}
} else { // Try to get x,y,z and possibly w
- if (value->isObject()) {
+ if (value && value->isObject()) {
ScriptValuePointer x = value->property("x");
- if (x->isNumber()) {
+ if (x && x->isNumber()) {
ScriptValuePointer y = value->property("y");
- if (y->isNumber()) {
+ if (y && y->isNumber()) {
ScriptValuePointer z = value->property("z");
- if (z->isNumber()) {
+ if (z && z->isNumber()) {
ScriptValuePointer w = value->property("w");
- if (w->isNumber()) {
+ if (w && w->isNumber()) {
set(property->name(), glm::quat(w->toNumber(), x->toNumber(), y->toNumber(), z->toNumber()));
} else {
set(property->name(), glm::vec3(x->toNumber(), y->toNumber(), z->toNumber()));
@@ -120,7 +120,7 @@ void AnimVariantMap::animVariantMapFromScriptValue(const ScriptValuePointer& sou
}
}
}
- qCWarning(animation) << "Ignoring unrecognized data" << value->toString() << "for animation property" << property->name();
+ qCWarning(animation) << "Ignoring unrecognized data " << (value ? value->toString() : "(undefined)") << " for animation property " << property->name();
Q_ASSERT(false);
}
}
diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp
index 6edda21992..935efd3030 100644
--- a/libraries/animation/src/Rig.cpp
+++ b/libraries/animation/src/Rig.cpp
@@ -1589,7 +1589,7 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos
ScriptValuePointer Rig::addAnimationStateHandler(ScriptValuePointer handler, ScriptValuePointer propertiesList) { // called in script thread
// validate argument types
- if (handler->isFunction() && (isListOfStrings(propertiesList) || propertiesList->isUndefined() || propertiesList->isNull())) {
+ if (handler && handler->isFunction() && (isListOfStrings(propertiesList) || propertiesList->isUndefined() || propertiesList->isNull())) {
QMutexLocker locker(&_stateMutex);
// Find a safe id, even if there are lots of many scripts add and remove handlers repeatedly.
while (!_nextStateHandlerId || _stateHandlers.contains(_nextStateHandlerId)) { // 0 is unused, and don't reuse existing after wrap.
@@ -1610,7 +1610,7 @@ ScriptValuePointer Rig::addAnimationStateHandler(ScriptValuePointer handler, Scr
void Rig::removeAnimationStateHandler(ScriptValuePointer identifier) { // called in script thread
// validate arguments
- if (identifier->isNumber()) {
+ if (identifier && identifier->isNumber()) {
QMutexLocker locker(&_stateMutex);
_stateHandlers.remove(identifier->toInt32()); // silently continues if handler not present. 0 is unused
} else {
diff --git a/libraries/audio/src/AudioEffectOptions.cpp b/libraries/audio/src/AudioEffectOptions.cpp
index dc7dd38b23..4fb7d93983 100644
--- a/libraries/audio/src/AudioEffectOptions.cpp
+++ b/libraries/audio/src/AudioEffectOptions.cpp
@@ -67,7 +67,7 @@ static const float LATE_MIX_RIGHT_DEFAULT = 90.0f;
static const float WET_DRY_MIX_DEFAULT = 50.0f;
static void setOption(ScriptValuePointer arguments, const QString name, float defaultValue, float& variable) {
- variable = arguments->property(name)->isNumber() ? (float)arguments->property(name)->toNumber() : defaultValue;
+ variable = arguments && arguments->property(name)->isNumber() ? (float)arguments->property(name)->toNumber() : defaultValue;
}
/*@jsdoc
diff --git a/libraries/audio/src/AudioInjectorOptions.cpp b/libraries/audio/src/AudioInjectorOptions.cpp
index b49adf6963..27ca80687f 100644
--- a/libraries/audio/src/AudioInjectorOptions.cpp
+++ b/libraries/audio/src/AudioInjectorOptions.cpp
@@ -67,7 +67,7 @@ ScriptValuePointer injectorOptionsToScriptValue(ScriptEngine* engine, const Audi
* removed.
*/
void injectorOptionsFromScriptValue(const ScriptValuePointer& object, AudioInjectorOptions& injectorOptions) {
- if (!object->isObject()) {
+ if (!object || !object->isObject()) {
qWarning() << "Audio injector options is not an object.";
return;
}
diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp
index 106eb53f15..df95f3de52 100644
--- a/libraries/avatars/src/AvatarData.cpp
+++ b/libraries/avatars/src/AvatarData.cpp
@@ -3184,11 +3184,11 @@ void RayToAvatarIntersectionResultFromScriptValue(const ScriptValuePointer& obje
value.face = boxFaceFromString(object->property("face")->toVariant().toString());
ScriptValuePointer intersection = object->property("intersection");
- if (intersection->isValid()) {
+ if (intersection && intersection->isValid()) {
vec3FromScriptValue(intersection, value.intersection);
}
ScriptValuePointer surfaceNormal = object->property("surfaceNormal");
- if (surfaceNormal->isValid()) {
+ if (surfaceNormal && surfaceNormal->isValid()) {
vec3FromScriptValue(surfaceNormal, value.surfaceNormal);
}
value.jointIndex = object->property("jointIndex")->toInt32();
diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h
index 8488873680..34b1846d7e 100644
--- a/libraries/script-engine/src/ScriptEngine.h
+++ b/libraries/script-engine/src/ScriptEngine.h
@@ -103,6 +103,7 @@ public:
virtual bool setProperty(const char* name, const QVariant& value) = 0;
virtual void setProcessEventsInterval(int interval) = 0;
virtual QThread* thread() const = 0;
+ virtual void setThread(QThread* thread) = 0;
virtual ScriptValuePointer undefinedValue() = 0;
virtual ScriptValuePointer uncaughtException() const = 0;
virtual QStringList uncaughtExceptionBacktrace() const = 0;
diff --git a/libraries/script-engine/src/ScriptEngineCast.h b/libraries/script-engine/src/ScriptEngineCast.h
index 22221e74a4..d597efc780 100644
--- a/libraries/script-engine/src/ScriptEngineCast.h
+++ b/libraries/script-engine/src/ScriptEngineCast.h
@@ -65,7 +65,8 @@ int scriptRegisterMetaType(ScriptEngine* eng,
ScriptValuePointer (*toScriptValue)(ScriptEngine*, const T& t),
void (*fromScriptValue)(const ScriptValuePointer&, T& t),
const ScriptValuePointer& prototype = ScriptValuePointer(),
- T* = 0) {
+ T* = 0)
+{
const int id = qRegisterMetaType(); // make sure it's registered
eng->registerCustomType(id, reinterpret_cast(toScriptValue),
reinterpret_cast(fromScriptValue), prototype);
diff --git a/libraries/script-engine/src/ScriptManager.cpp b/libraries/script-engine/src/ScriptManager.cpp
index b6886eaeb0..7ebd41ec9d 100644
--- a/libraries/script-engine/src/ScriptManager.cpp
+++ b/libraries/script-engine/src/ScriptManager.cpp
@@ -87,6 +87,8 @@ int scriptManagerPointerMetaID = qRegisterMetaType();
Q_DECLARE_METATYPE(ExternalResource::Bucket);
+Q_DECLARE_METATYPE(ScriptValuePointer);
+
// --- Static script initialization registry
static ScriptManager::StaticInitializerNode* rootInitializer = nullptr;
@@ -325,6 +327,7 @@ void ScriptManager::runInThread() {
QThread* workerThread = new QThread();
QString name = QString("js:") + getFilename().replace("about:","");
workerThread->setObjectName(name);
+ _engine->setThread(workerThread);
moveToThread(workerThread);
// NOTE: If you connect any essential signals for proper shutdown or cleanup of
@@ -1256,13 +1259,13 @@ ScriptValuePointer ScriptManager::currentModule() {
}
auto jsRequire = _engine->globalObject()->property("Script")->property("require");
auto cache = jsRequire->property("cache");
- auto candidate = ScriptValuePointer();
+ ScriptValuePointer candidate;
ScriptContextPointer parentContext; // using this variable to maintain parent variable lifespan
- for (auto context = _engine->currentContext(); context && !candidate->isObject(); parentContext = context->parentContext(), context = parentContext.data()) {
+ for (auto context = _engine->currentContext(); context && (!candidate || !candidate->isObject()); parentContext = context->parentContext(), context = parentContext.data()) {
auto contextInfo = context->functionContext();
candidate = cache->property(contextInfo->fileName());
}
- if (!candidate->isObject()) {
+ if (!candidate || !candidate->isObject()) {
return ScriptValuePointer();
}
return candidate;
@@ -1589,8 +1592,8 @@ void ScriptManager::include(const QStringList& includeFiles, ScriptValuePointer
}
_parentURL = parentURL;
- if (callback->isFunction()) {
- callWithEnvironment(capturedEntityIdentifier, capturedSandboxURL, ScriptValuePointer(callback), ScriptValuePointer(), ScriptValueList());
+ if (callback && callback->isFunction()) {
+ callWithEnvironment(capturedEntityIdentifier, capturedSandboxURL, callback, ScriptValuePointer(), ScriptValueList());
}
loader->deleteLater();
@@ -1603,7 +1606,7 @@ void ScriptManager::include(const QStringList& includeFiles, ScriptValuePointer
loader->start(processLevelMaxRetries);
- if (!callback->isFunction() && !loader->isFinished()) {
+ if ((!callback || !callback->isFunction()) && !loader->isFinished()) {
QEventLoop loop;
QObject::connect(loader, &BatchLoader::finished, &loop, &QEventLoop::quit);
loop.exec();
@@ -1963,7 +1966,7 @@ void ScriptManager::entityScriptContentAvailable(const EntityItemID& entityID, c
if (sandbox->hasUncaughtException()) {
exception = sandbox->cloneUncaughtException(QString("(preflight %1)").arg(entityID.toString()));
sandbox->clearExceptions();
- } else if (testConstructor->isError()) {
+ } else if (testConstructor && testConstructor->isError()) {
exception = testConstructor;
}
} else {
@@ -2038,7 +2041,7 @@ void ScriptManager::entityScriptContentAvailable(const EntityItemID& entityID, c
if (sandbox->hasUncaughtException()) {
exception = sandbox->cloneUncaughtException(QString("(preflight %1)").arg(entityID.toString()));
sandbox->clearExceptions();
- } else if (testConstructor->isError()) {
+ } else if (testConstructor && testConstructor->isError()) {
exception = testConstructor;
}
}
@@ -2048,7 +2051,7 @@ void ScriptManager::entityScriptContentAvailable(const EntityItemID& entityID, c
// exception = makeError("UNSAFE_ENTITY_SCRIPTS == 0");
}
- if (exception->isError()) {
+ if (exception && exception->isError()) {
// create a local copy using makeError to decouple from the sandbox engine
exception = _engine->makeError(exception);
setError(formatException(exception, _enableExtendedJSExceptions.get()), EntityScriptStatus::ERROR_RUNNING_SCRIPT);
@@ -2057,7 +2060,7 @@ void ScriptManager::entityScriptContentAvailable(const EntityItemID& entityID, c
}
// CONSTRUCTOR VIABILITY
- if (!testConstructor->isFunction()) {
+ if (!testConstructor || !testConstructor->isFunction()) {
QString testConstructorType = QString(testConstructor->toVariant().typeName());
if (testConstructorType == "") {
testConstructorType = "empty";
@@ -2100,7 +2103,7 @@ void ScriptManager::entityScriptContentAvailable(const EntityItemID& entityID, c
doWithEnvironment(entityID, sandboxURL, initialization);
- if (entityScriptObject->isError()) {
+ if (entityScriptObject && entityScriptObject->isError()) {
auto exception = entityScriptObject;
setError(formatException(exception, _enableExtendedJSExceptions.get()), EntityScriptStatus::ERROR_RUNNING_SCRIPT);
emit unhandledException(exception);
diff --git a/libraries/script-engine/src/qtscript/ScriptContextQtWrapper.cpp b/libraries/script-engine/src/qtscript/ScriptContextQtWrapper.cpp
index 41cd945ca2..798d93a0ea 100644
--- a/libraries/script-engine/src/qtscript/ScriptContextQtWrapper.cpp
+++ b/libraries/script-engine/src/qtscript/ScriptContextQtWrapper.cpp
@@ -52,7 +52,7 @@ ScriptFunctionContextPointer ScriptContextQtWrapper::functionContext() const {
ScriptContextPointer ScriptContextQtWrapper::parentContext() const {
QScriptContext* result = _context->parentContext();
- return ScriptContextPointer(new ScriptContextQtWrapper(_engine, result));
+ return result ? ScriptContextPointer(new ScriptContextQtWrapper(_engine, result)) : ScriptContextPointer();
}
ScriptValuePointer ScriptContextQtWrapper::thisObject() const {
diff --git a/libraries/script-engine/src/qtscript/ScriptEngineQtScript.cpp b/libraries/script-engine/src/qtscript/ScriptEngineQtScript.cpp
index fe3cc76c88..7700d778d2 100644
--- a/libraries/script-engine/src/qtscript/ScriptEngineQtScript.cpp
+++ b/libraries/script-engine/src/qtscript/ScriptEngineQtScript.cpp
@@ -62,13 +62,16 @@ static const QScriptValue::PropertyFlags READONLY_HIDDEN_PROP_FLAGS { READONLY_P
static const bool HIFI_AUTOREFRESH_FILE_SCRIPTS { true };
+Q_DECLARE_METATYPE(ScriptValuePointer);
+
Q_DECLARE_METATYPE(QScriptEngine::FunctionSignature)
int qfunctionSignatureMetaID = qRegisterMetaType();
int scriptEnginePointerMetaID = qRegisterMetaType();
bool ScriptEngineQtScript::IS_THREADSAFE_INVOCATION(const QThread* thread, const QString& method) {
- if (QThread::currentThread() == thread) {
+ const QThread* currentThread = QThread::currentThread();
+ if (currentThread == thread) {
return true;
}
qCCritical(scriptengine) << QString("Scripting::%1 @ %2 -- ignoring thread-unsafe call from %3")
@@ -380,11 +383,22 @@ static QScriptValue debugPrint(QScriptContext* context, QScriptEngine* engine) {
return QScriptValue();
}
+static QScriptValue ScriptValueToQScriptValue(QScriptEngine* engine, const ScriptValuePointer& src) {
+ return ScriptValueQtWrapper::fullUnwrap(static_cast(engine), src);
+}
+
+static void ScriptValueFromQScriptValue(const QScriptValue& src, ScriptValuePointer& dest) {
+ ScriptEngineQtScript* engine = static_cast(src.engine());
+ dest = ScriptValuePointer(new ScriptValueQtWrapper(engine, src));
+}
+
ScriptEngineQtScript::ScriptEngineQtScript(ScriptManager* scriptManager) :
QScriptEngine(),
_manager(scriptManager),
_arrayBufferClass(new ArrayBufferClass(this))
{
+ qScriptRegisterMetaType(this, ScriptValueToQScriptValue, ScriptValueFromQScriptValue);
+
if (_manager) {
connect(this, &QScriptEngine::signalHandlerException, this, [this](const QScriptValue& exception) {
if (hasUncaughtException()) {
@@ -397,6 +411,7 @@ ScriptEngineQtScript::ScriptEngineQtScript(ScriptManager* scriptManager) :
emit _manager->unhandledException(ScriptValuePointer(new ScriptValueQtWrapper(this, std::move(thrown))));
}
}, Qt::DirectConnection);
+ moveToThread(scriptManager->thread());
}
QScriptValue null = QScriptEngine::nullValue();
@@ -993,6 +1008,10 @@ QThread* ScriptEngineQtScript::thread() const {
return QScriptEngine::thread();
}
+void ScriptEngineQtScript::setThread(QThread* thread) {
+ moveToThread(thread);
+}
+
ScriptValuePointer ScriptEngineQtScript::uncaughtException() const {
QScriptValue result = QScriptEngine::uncaughtException();
return ScriptValuePointer(new ScriptValueQtWrapper(const_cast(this), std::move(result)));
@@ -1013,47 +1032,11 @@ bool ScriptEngineQtScript::raiseException(const ScriptValuePointer& exception) {
}
ScriptValuePointer ScriptEngineQtScript::create(int type, const void* ptr) {
- // first we'll try custom types registered with us
- ScriptEngine::MarshalFunction marshalFunc = nullptr;
- ScriptValuePointer prototype;
- {
- std::lock_guard guard(_customTypeProtect);
- TCustomTypeMap::const_iterator loc = _customTypes.find(type);
- if (loc != _customTypes.end()) {
- const CustomTypeInfo& typeInfo = loc->second;
- marshalFunc = typeInfo.marshalFunc;
- prototype = typeInfo.prototype;
- }
- }
- if (marshalFunc) {
- ScriptValuePointer result = marshalFunc(this, ptr);
- if (result && prototype) {
- result->setPrototype(prototype);
- }
- return result;
- }
-
- // falling back to having QtScript handle it
QScriptValue result = qScriptValueFromValue_helper(this, type, ptr);
return ScriptValuePointer(new ScriptValueQtWrapper(const_cast(this), std::move(result)));
}
bool ScriptEngineQtScript::convert(const ScriptValuePointer& value, int type, void* ptr) {
- // first we'll try custom types registered with us
- ScriptEngine::DemarshalFunction demarshalFunc = nullptr;
- {
- std::lock_guard guard(_customTypeProtect);
- TCustomTypeMap::const_iterator loc = _customTypes.find(type);
- if (loc != _customTypes.end()) {
- demarshalFunc = loc->second.demarshalFunc;
- }
- }
- if (demarshalFunc) {
- demarshalFunc(value, ptr);
- return true;
- }
-
- // falling back to having QtScript handle it
ScriptValueQtWrapper* unwrapped = ScriptValueQtWrapper::unwrap(value);
if (unwrapped == nullptr) {
return false;
@@ -1061,22 +1044,100 @@ bool ScriptEngineQtScript::convert(const ScriptValuePointer& value, int type, vo
return qscriptvalue_cast_helper(unwrapped->toQtValue(), type, ptr);
}
+template
+class CustomTypeInstance {
+public:
+ static ScriptEngine::MarshalFunction marshalFunc;
+ static ScriptEngine::DemarshalFunction demarshalFunc;
+
+ static QScriptValue internalMarshalFunc(QScriptEngine* engine, const void* src) {
+ ScriptEngineQtScript* unwrappedEngine = static_cast(engine);
+ ScriptValuePointer dest = marshalFunc(unwrappedEngine, src);
+ return ScriptValueQtWrapper::fullUnwrap(unwrappedEngine, dest);
+ }
+
+ static void internalDemarshalFunc(const QScriptValue& src, void* dest) {
+ ScriptEngineQtScript* unwrappedEngine = static_cast(src.engine());
+ ScriptValuePointer wrappedSrc(new ScriptValueQtWrapper(unwrappedEngine, src));
+ demarshalFunc(wrappedSrc, dest);
+ }
+};
+template
+ScriptEngine::MarshalFunction CustomTypeInstance::marshalFunc;
+template
+ScriptEngine::DemarshalFunction CustomTypeInstance::demarshalFunc;
+
+// I would *LOVE* it if there was a different way to do this, jeez!
+// Qt requires two functions that have no parameters that give any context,
+// one of the must return a QScriptValue (so we can't void* them into generics and stick them in the templates).
+// This *has* to be done via templates but the whole point of this is to avoid leaking types into the rest of
+// the system that would require anyone other than us to have a dependency on QtScript
+#define CUSTOM_TYPE_ENTRY(idx) \
+ case idx: \
+ CustomTypeInstance::marshalFunc = marshalFunc; \
+ CustomTypeInstance::demarshalFunc = demarshalFunc; \
+ internalMarshalFunc = CustomTypeInstance::internalMarshalFunc; \
+ internalDemarshalFunc = CustomTypeInstance::internalDemarshalFunc; \
+ break;
+#define CUSTOM_TYPE_ENTRY_10(idx) \
+ CUSTOM_TYPE_ENTRY((idx * 10)); \
+ CUSTOM_TYPE_ENTRY((idx * 10) + 1); \
+ CUSTOM_TYPE_ENTRY((idx * 10) + 2); \
+ CUSTOM_TYPE_ENTRY((idx * 10) + 3); \
+ CUSTOM_TYPE_ENTRY((idx * 10) + 4); \
+ CUSTOM_TYPE_ENTRY((idx * 10) + 5); \
+ CUSTOM_TYPE_ENTRY((idx * 10) + 6); \
+ CUSTOM_TYPE_ENTRY((idx * 10) + 7); \
+ CUSTOM_TYPE_ENTRY((idx * 10) + 8); \
+ CUSTOM_TYPE_ENTRY((idx * 10) + 9);
+
void ScriptEngineQtScript::registerCustomType(int type,
ScriptEngine::MarshalFunction marshalFunc,
ScriptEngine::DemarshalFunction demarshalFunc,
const ScriptValuePointer& prototype)
{
- ScriptValueQtWrapper* unwrapped = ScriptValueQtWrapper::unwrap(prototype);
- if (unwrapped == nullptr) {
+ QScriptValue unwrapped = ScriptValueQtWrapper::fullUnwrap(this, prototype);
+ QScriptEngine::MarshalFunction internalMarshalFunc;
+ QScriptEngine::DemarshalFunction internalDemarshalFunc;
+
+ if (_nextCustomType >= 300) { // have we ran out of translators?
+ Q_ASSERT(false);
return;
}
- std::lock_guard guard(_customTypeProtect);
- TCustomTypeMap::iterator loc = _customTypes.find(type);
- if(loc == _customTypes.end()) {
- _customTypes.insert(TCustomTypeMap::value_type(type, CustomTypeInfo())).first;
+ switch (_nextCustomType++) {
+ CUSTOM_TYPE_ENTRY_10(0);
+ CUSTOM_TYPE_ENTRY_10(1);
+ CUSTOM_TYPE_ENTRY_10(2);
+ CUSTOM_TYPE_ENTRY_10(3);
+ CUSTOM_TYPE_ENTRY_10(4);
+ CUSTOM_TYPE_ENTRY_10(5);
+ CUSTOM_TYPE_ENTRY_10(6);
+ CUSTOM_TYPE_ENTRY_10(7);
+ CUSTOM_TYPE_ENTRY_10(8);
+ CUSTOM_TYPE_ENTRY_10(9);
+ CUSTOM_TYPE_ENTRY_10(10);
+ CUSTOM_TYPE_ENTRY_10(11);
+ CUSTOM_TYPE_ENTRY_10(12);
+ CUSTOM_TYPE_ENTRY_10(13);
+ CUSTOM_TYPE_ENTRY_10(14);
+ CUSTOM_TYPE_ENTRY_10(15);
+ CUSTOM_TYPE_ENTRY_10(16);
+ CUSTOM_TYPE_ENTRY_10(17);
+ CUSTOM_TYPE_ENTRY_10(18);
+ CUSTOM_TYPE_ENTRY_10(19);
+ CUSTOM_TYPE_ENTRY_10(20);
+ CUSTOM_TYPE_ENTRY_10(21);
+ CUSTOM_TYPE_ENTRY_10(22);
+ CUSTOM_TYPE_ENTRY_10(23);
+ CUSTOM_TYPE_ENTRY_10(24);
+ CUSTOM_TYPE_ENTRY_10(25);
+ CUSTOM_TYPE_ENTRY_10(26);
+ CUSTOM_TYPE_ENTRY_10(27);
+ CUSTOM_TYPE_ENTRY_10(28);
+ CUSTOM_TYPE_ENTRY_10(29);
+ CUSTOM_TYPE_ENTRY_10(30);
}
- CustomTypeInfo& typeInfo = loc->second;
- typeInfo.marshalFunc = marshalFunc;
- typeInfo.demarshalFunc = demarshalFunc;
+
+ qScriptRegisterMetaType_helper(this, type, internalMarshalFunc, internalDemarshalFunc, unwrapped);
}
diff --git a/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h b/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h
index 78b71e37b4..1c8d9ce781 100644
--- a/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h
+++ b/libraries/script-engine/src/qtscript/ScriptEngineQtScript.h
@@ -89,6 +89,7 @@ public: // ScriptEngine implementation
virtual bool setProperty(const char* name, const QVariant& value);
virtual void setProcessEventsInterval(int interval);
virtual QThread* thread() const;
+ virtual void setThread(QThread* thread);
virtual ScriptValuePointer undefinedValue();
virtual ScriptValuePointer uncaughtException() const;
virtual QStringList uncaughtExceptionBacktrace() const;
@@ -404,18 +405,9 @@ protected:
*/
Q_INVOKABLE void executeOnScriptThread(std::function function, const Qt::ConnectionType& type = Qt::QueuedConnection );
- // store for handling custom type marshaling/demarshaling
- struct CustomTypeInfo {
- ScriptEngine::MarshalFunction marshalFunc;
- ScriptEngine::DemarshalFunction demarshalFunc;
- ScriptValuePointer prototype;
- };
- typedef std::map TCustomTypeMap;
- TCustomTypeMap _customTypes;
- std::mutex _customTypeProtect;
-
QPointer _manager;
+ int _nextCustomType = 0;
ScriptValuePointer _nullValue;
ScriptValuePointer _undefinedValue;
mutable ScriptContextQtPointer _currContext;