diff --git a/libraries/script-engine/src/ScriptValue.cpp b/libraries/script-engine/src/ScriptValue.cpp index ac9bc774f1..3e08db16cf 100644 --- a/libraries/script-engine/src/ScriptValue.cpp +++ b/libraries/script-engine/src/ScriptValue.cpp @@ -44,6 +44,7 @@ public: virtual ScriptValue property(quint32 arrayIndex, const ScriptValue::ResolveFlags& mode = ScriptValue::ResolvePrototype) const override; virtual void setData(const ScriptValue& val) override; + virtual bool hasProperty(const QString &name) const override; virtual void setProperty(const QString& name, const ScriptValue& value, const ScriptValue::PropertyFlags& flags = ScriptValue::KeepExistingFlags) override; @@ -178,6 +179,13 @@ void ScriptValueProxyNull::setData(const ScriptValue& val) { qCWarning(scriptengine_script, "ScriptValue::setData called on empty value"); } +bool ScriptValueProxyNull::hasProperty(const QString& name) const { + Q_ASSERT(false); + qCWarning(scriptengine_script, "ScriptValue::hasProperty called on empty value"); + return false; +} + + void ScriptValueProxyNull::setProperty(const QString& name, const ScriptValue& value, const ScriptValue::PropertyFlags& flags) { Q_ASSERT(false); diff --git a/libraries/script-engine/src/ScriptValue.h b/libraries/script-engine/src/ScriptValue.h index 4f2d5725fd..5f25a33cf8 100644 --- a/libraries/script-engine/src/ScriptValue.h +++ b/libraries/script-engine/src/ScriptValue.h @@ -88,6 +88,7 @@ public: inline ScriptValue property(const QString& name, const ResolveFlags& mode = ResolvePrototype) const; inline ScriptValue property(quint32 arrayIndex, const ResolveFlags& mode = ResolvePrototype) const; inline void setData(const ScriptValue& val); + inline bool hasProperty(const QString &name) const; inline void setProperty(const QString& name, const ScriptValue& value, const PropertyFlags& flags = KeepExistingFlags); @@ -152,6 +153,7 @@ public: virtual ScriptValue property(quint32 arrayIndex, const ScriptValue::ResolveFlags& mode = ScriptValue::ResolvePrototype) const = 0; virtual void setData(const ScriptValue& val) = 0; + virtual bool hasProperty(const QString &name) const = 0; virtual void setProperty(const QString& name, const ScriptValue& value, const ScriptValue::PropertyFlags& flags = ScriptValue::KeepExistingFlags) = 0; @@ -318,6 +320,12 @@ void ScriptValue::setData(const ScriptValue& val) { return _proxy->setData(val); } + +bool ScriptValue::hasProperty(const QString& name) const { + Q_ASSERT(_proxy != nullptr); + return _proxy->hasProperty(name); +} + void ScriptValue::setProperty(const QString& name, const ScriptValue& value, const PropertyFlags& flags) { Q_ASSERT(_proxy != nullptr); return _proxy->setProperty(name, value, flags); diff --git a/libraries/script-engine/src/ScriptValueUtils.cpp b/libraries/script-engine/src/ScriptValueUtils.cpp index 2fa1d46de0..4733dd7b72 100644 --- a/libraries/script-engine/src/ScriptValueUtils.cpp +++ b/libraries/script-engine/src/ScriptValueUtils.cpp @@ -140,7 +140,7 @@ bool vec2FromScriptValue(const ScriptValue& object, glm::vec2& vec2) { ScriptValue vec3ToScriptValue(ScriptEngine* engine, const glm::vec3& vec3) { auto prototype = engine->globalObject().property("__hifi_vec3__"); - if (!prototype.property("defined").toBool()) { + if (!prototype.hasProperty("defined") || !prototype.property("defined").toBool()) { prototype = engine->evaluate( "__hifi_vec3__ = Object.defineProperties({}, { " "defined: { value: true }," @@ -648,7 +648,7 @@ ScriptValue qColorToScriptValue(ScriptEngine* engine, const QColor& color) { } /**jsdoc - * An axis-aligned cube, defined as the bottom right near (minimum axes values) corner of the cube plus the dimension of its + * An axis-aligned cube, defined as the bottom right near (minimum axes values) corner of the cube plus the dimension of its * sides. * @typedef {object} AACube * @property {number} x - X coordinate of the brn corner of the cube. @@ -812,8 +812,8 @@ bool qSizeFFromScriptValue(const ScriptValue& object, QSizeF& qSizeF) { * The details of an animation that is playing. * @typedef {object} Avatar.AnimationDetails * @property {string} role - Not used. - * @property {string} url - The URL to the animation file. Animation files need to be in glTF or FBX format but only need to - * contain the avatar skeleton and animation data. glTF models may be in JSON or binary format (".gltf" or ".glb" URLs + * @property {string} url - The URL to the animation file. Animation files need to be in glTF or FBX format but only need to + * contain the avatar skeleton and animation data. glTF models may be in JSON or binary format (".gltf" or ".glb" URLs * respectively). *

Warning: glTF animations currently do not always animate correctly.

* @property {number} fps - The frames per second(FPS) rate for the animation playback. 30 FPS is normal speed. diff --git a/libraries/script-engine/src/v8/ScriptValueV8Wrapper.cpp b/libraries/script-engine/src/v8/ScriptValueV8Wrapper.cpp index f8b833d6dc..a5ac13f62d 100644 --- a/libraries/script-engine/src/v8/ScriptValueV8Wrapper.cpp +++ b/libraries/script-engine/src/v8/ScriptValueV8Wrapper.cpp @@ -172,6 +172,28 @@ ScriptValueIteratorPointer ScriptValueV8Wrapper::newIterator() const { return std::make_shared(_engine, _value); } +bool ScriptValueV8Wrapper::hasProperty(const QString& name) const { + auto isolate = _engine->getIsolate(); + v8::Locker locker(_engine->getIsolate()); + v8::Isolate::Scope isolateScope(_engine->getIsolate()); + v8::HandleScope handleScope(isolate); + v8::Context::Scope contextScope(_engine->getContext()); + if (_value.constGet()->IsObject()) { + //V8TODO: what about flags? + v8::Local resultLocal; + v8::Local key = v8::String::NewFromUtf8(_engine->getIsolate(), name.toStdString().c_str(),v8::NewStringType::kNormal).ToLocalChecked(); + const v8::Local object = v8::Local::Cast(_value.constGet()); + if (object->Get(_value.constGetContext(), key).ToLocal(&resultLocal)) { + return true; + } else { + return false; + } + } + return false; +} + + + ScriptValue ScriptValueV8Wrapper::property(const QString& name, const ScriptValue::ResolveFlags &mode) const { auto isolate = _engine->getIsolate(); v8::Locker locker(_engine->getIsolate()); diff --git a/libraries/script-engine/src/v8/ScriptValueV8Wrapper.h b/libraries/script-engine/src/v8/ScriptValueV8Wrapper.h index f0b11bbb95..36ceb2e7f1 100644 --- a/libraries/script-engine/src/v8/ScriptValueV8Wrapper.h +++ b/libraries/script-engine/src/v8/ScriptValueV8Wrapper.h @@ -54,6 +54,9 @@ public: // ScriptValue implementation virtual ScriptValue property(quint32 arrayIndex, const ScriptValue::ResolveFlags& mode = ScriptValue::ResolvePrototype) const override; virtual void setData(const ScriptValue& val) override; + + virtual bool hasProperty(const QString &name) const; + virtual void setProperty(const QString& name, const ScriptValue& value, const ScriptValue::PropertyFlags& flags = ScriptValue::KeepExistingFlags) override; diff --git a/tests/script-engine/src/ScriptEngineTests.cpp b/tests/script-engine/src/ScriptEngineTests.cpp index 8e65ebb36a..9a55d62e47 100644 --- a/tests/script-engine/src/ScriptEngineTests.cpp +++ b/tests/script-engine/src/ScriptEngineTests.cpp @@ -87,7 +87,8 @@ void ScriptEngineTests::scriptTest() { qInfo() << "Running test script: " << script; ac->loadOneScript(script); }*/ - ac->loadOneScript("tests/script-engine/tests/003_vector_math.js"); + ac->loadOneScript("tests/003_vector_math.js"); + ac->loadOneScript("tests/004_require.js"); qDebug() << ac->getRunning();