diff --git a/libraries/script-engine/src/ScriptManagerScriptingInterface.cpp b/libraries/script-engine/src/ScriptManagerScriptingInterface.cpp index 36da99b751a..c3717913295 100644 --- a/libraries/script-engine/src/ScriptManagerScriptingInterface.cpp +++ b/libraries/script-engine/src/ScriptManagerScriptingInterface.cpp @@ -133,3 +133,35 @@ QString ScriptManagerScriptingInterface::btoa(const QByteArray &binary) { QByteArray ScriptManagerScriptingInterface::atob(const QString &base64) { return QByteArray::fromBase64(base64.toUtf8()); } + +void ScriptManagerScriptingInterface::test__ArrayBufferView(const ScriptValue& value) { + if (!value.isArrayBufferView()) { + qInfo() << "value is not an ArrayBufferView"; + return; + } + + auto view = value.toArrayBufferView(); + + QString str; + QTextStream stream(&str); + + const char* data = reinterpret_cast(view->buffer()); + auto offset = view->byteOffset(); + auto length = view->byteLength(); + + stream << "ArrayBufferView(" << offset << ", " << length << ") [ "; + + if (data) { + for (size_t i = 0; i < length; i++) { + stream << (uint8_t)data[offset + i]; + + if (i < length - 1) { stream << ", "; } + } + } else { + stream << "(no buffer)"; + } + + stream << " ]"; + + qInfo() << str; +} diff --git a/libraries/script-engine/src/ScriptManagerScriptingInterface.h b/libraries/script-engine/src/ScriptManagerScriptingInterface.h index 0a2ccb66e39..16c31e1e9b0 100644 --- a/libraries/script-engine/src/ScriptManagerScriptingInterface.h +++ b/libraries/script-engine/src/ScriptManagerScriptingInterface.h @@ -620,6 +620,8 @@ class ScriptManagerScriptingInterface : public QObject { */ Q_INVOKABLE QString btoa(const QByteArray &binary); + Q_INVOKABLE void test__ArrayBufferView(const ScriptValue& value); + signals: /*@jsdoc diff --git a/libraries/script-engine/src/ScriptValue.cpp b/libraries/script-engine/src/ScriptValue.cpp index 2c8f9e25811..ba479410bde 100644 --- a/libraries/script-engine/src/ScriptValue.cpp +++ b/libraries/script-engine/src/ScriptValue.cpp @@ -40,6 +40,7 @@ class ScriptValueProxyNull final : public ScriptValueProxy { virtual bool isUndefined() const override; virtual bool isValid() const override; virtual bool isVariant() const override; + virtual bool isArrayBufferView() const override; virtual ScriptValueIteratorPointer newIterator() const override; virtual ScriptValue property(const QString& name, const ScriptValue::ResolveFlags& mode = ScriptValue::ResolvePrototype) const override; @@ -67,6 +68,7 @@ class ScriptValueProxyNull final : public ScriptValueProxy { virtual quint32 toUInt32() const override; virtual QVariant toVariant() const override; virtual QObject* toQObject() const override; + virtual std::shared_ptr toArrayBufferView() const override; }; static ScriptValueProxyNull SCRIPT_VALUE_NULL; @@ -164,6 +166,10 @@ bool ScriptValueProxyNull::isVariant() const { return false; } +bool ScriptValueProxyNull::isArrayBufferView() const { + return false; +} + ScriptValueIteratorPointer ScriptValueProxyNull::newIterator() const { Q_ASSERT(false); qCWarning(scriptengine_script, "ScriptValue::newIterator called on empty value"); @@ -254,3 +260,7 @@ QVariant ScriptValueProxyNull::toVariant() const { QObject* ScriptValueProxyNull::toQObject() const { return nullptr; } + +std::shared_ptr ScriptValueProxyNull::toArrayBufferView() const { + return nullptr; +} diff --git a/libraries/script-engine/src/ScriptValue.h b/libraries/script-engine/src/ScriptValue.h index 1560c99a3ec..84d8304c8f1 100644 --- a/libraries/script-engine/src/ScriptValue.h +++ b/libraries/script-engine/src/ScriptValue.h @@ -36,6 +36,13 @@ using ScriptEnginePointer = std::shared_ptr; using ScriptValueList = QList; using ScriptValueIteratorPointer = std::shared_ptr; +class ScriptBufferView { +public: + virtual void* buffer() const = 0; + virtual size_t byteOffset() const = 0; + virtual size_t byteLength() const = 0; +}; + /// [ScriptInterface] Provides an engine-independent interface for QScriptValue class ScriptValue { public: @@ -87,6 +94,7 @@ class ScriptValue { inline bool isUndefined() const; inline bool isValid() const; inline bool isVariant() const; + inline bool isArrayBufferView() const; inline ScriptValueIteratorPointer newIterator() const; inline ScriptValue property(const QString& name, const ResolveFlags& mode = ResolvePrototype) const; inline ScriptValue property(quint32 arrayIndex, const ResolveFlags& mode = ResolvePrototype) const; @@ -118,6 +126,7 @@ class ScriptValue { inline quint32 toUInt32() const; inline QVariant toVariant() const; inline QObject* toQObject() const; + inline std::shared_ptr toArrayBufferView() const; protected: ScriptValueProxy* _proxy; @@ -150,6 +159,7 @@ class ScriptValueProxy { virtual bool isUndefined() const = 0; virtual bool isValid() const = 0; virtual bool isVariant() const = 0; + virtual bool isArrayBufferView() const = 0; virtual ScriptValueIteratorPointer newIterator() const = 0; virtual ScriptValue property(const QString& name, const ScriptValue::ResolveFlags& mode = ScriptValue::ResolvePrototype) const = 0; @@ -177,6 +187,7 @@ class ScriptValueProxy { virtual quint32 toUInt32() const = 0; virtual QVariant toVariant() const = 0; virtual QObject* toQObject() const = 0; + virtual std::shared_ptr toArrayBufferView() const = 0; protected: virtual ~ScriptValueProxy() {} // prevent explicit deletion of base class @@ -305,6 +316,11 @@ bool ScriptValue::isVariant() const { return _proxy->isVariant(); } +bool ScriptValue::isArrayBufferView() const { + Q_ASSERT(_proxy != nullptr); + return _proxy->isArrayBufferView(); +} + ScriptValueIteratorPointer ScriptValue::newIterator() const { Q_ASSERT(_proxy != nullptr); return _proxy->newIterator(); @@ -406,6 +422,11 @@ QObject* ScriptValue::toQObject() const { return _proxy->toQObject(); } +std::shared_ptr ScriptValue::toArrayBufferView() const { + Q_ASSERT(_proxy != nullptr); + return _proxy->toArrayBufferView(); +} + #endif // hifi_ScriptValue_h /// @} diff --git a/libraries/script-engine/src/v8/ScriptValueV8Wrapper.cpp b/libraries/script-engine/src/v8/ScriptValueV8Wrapper.cpp index 7f9faf21f20..1625efa6ed4 100644 --- a/libraries/script-engine/src/v8/ScriptValueV8Wrapper.cpp +++ b/libraries/script-engine/src/v8/ScriptValueV8Wrapper.cpp @@ -646,6 +646,18 @@ QObject* ScriptValueV8Wrapper::toQObject() const { } } +std::shared_ptr ScriptValueV8Wrapper::toArrayBufferView() const { + auto value = _value.constGet(); + if (value->IsArrayBufferView()) { + v8::Isolate* isolate = _engine->getIsolate(); + auto view = v8::ArrayBufferView::Cast(*value); + auto persistent = std::make_shared>(isolate, view->Buffer()); + return std::make_shared(isolate, persistent, view->ByteOffset(), view->ByteLength()); + } else { + return nullptr; + } +} + bool ScriptValueV8Wrapper::equals(const ScriptValue& other) const { auto isolate = _engine->getIsolate(); v8::Locker locker(isolate); @@ -782,3 +794,12 @@ bool ScriptValueV8Wrapper::isVariant() const { return false; //return _value.isVariant(); } + +bool ScriptValueV8Wrapper::isArrayBufferView() const { + auto isolate = _engine->getIsolate(); + v8::Locker locker(isolate); + v8::Isolate::Scope isolateScope(isolate); + v8::HandleScope handleScope(isolate); + v8::Context::Scope contextScope(_engine->getContext()); + return _value.constGet()->IsArrayBufferView(); +} diff --git a/libraries/script-engine/src/v8/ScriptValueV8Wrapper.h b/libraries/script-engine/src/v8/ScriptValueV8Wrapper.h index 14340dc2f41..ad59f68b8bf 100644 --- a/libraries/script-engine/src/v8/ScriptValueV8Wrapper.h +++ b/libraries/script-engine/src/v8/ScriptValueV8Wrapper.h @@ -28,6 +28,30 @@ //#define OVERTE_V8_SCRIPT_VALUE_WRAPPER_DELETE_GUARD +class ScriptBufferViewV8Wrapper final : public ScriptBufferView { +public: + void* buffer() const override { + return _buffer->Get(_isolate)->Data(); + } + + size_t byteOffset() const override { + return _offset; + } + + size_t byteLength() const override { + return _length; + } + + ScriptBufferViewV8Wrapper(v8::Isolate *isolate, std::shared_ptr> buffer, size_t offset, size_t length) : _isolate(isolate), _buffer(buffer), _offset(offset), _length(length) {} + +private: + v8::Isolate *_isolate; + std::shared_ptr> _buffer; + + size_t _offset; + size_t _length; +}; + /// [V8] Implements ScriptValue for V8 and translates calls for V8ScriptValue class ScriptValueV8Wrapper final : public ScriptValueProxy { public: // construction @@ -94,6 +118,7 @@ class ScriptValueV8Wrapper final : public ScriptValueProxy { virtual bool isUndefined() const override; virtual bool isValid() const override; virtual bool isVariant() const override; + virtual bool isArrayBufferView() const override; virtual bool toBool() const override; virtual qint32 toInt32() const override; virtual double toInteger() const override; @@ -103,6 +128,7 @@ class ScriptValueV8Wrapper final : public ScriptValueProxy { virtual quint32 toUInt32() const override; virtual QVariant toVariant() const override; virtual QObject* toQObject() const override; + virtual std::shared_ptr toArrayBufferView() const override; #ifdef OVERTE_V8_SCRIPT_VALUE_WRAPPER_DELETE_GUARD // These can be used for debugging crashes caused access after delete