History

working to clean up the QtScript implementation and move towards completion of the proxy interface

Heather Anderson committed 5 years ago

Commit 2dd9d781 parent 1e018db38 files · +2240 −923Browse files

Showing the changes to libraries/script-engine/src/qtscript/ArrayBufferClass.cpp (1 of 38 files). Show all

Unified · Split

libraries/script-engine/src/qtscript/ArrayBufferClass.cpp+180−0
@@ -0,0 +1,180 @@
1+//
2+// ArrayBufferClass.cpp
3+//
4+//
5+// Created by Clement on 7/3/14.
6+// Copyright 2014 High Fidelity, Inc.
7+//
8+// Distributed under the Apache License, Version 2.0.
9+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
10+//
11+
12+#include "ArrayBufferClass.h"
13+
14+#include <QDebug>
15+
16+#include "ArrayBufferPrototype.h"
17+#include "DataViewClass.h"
18+#include "ScriptEngineQtScript.h"
19+#include "TypedArrays.h"
20+
21+
22+static const QString CLASS_NAME = "ArrayBuffer";
23+
24+// FIXME: Q_DECLARE_METATYPE is global and really belongs in a shared header file, not per .cpp like this
25+// (see DataViewClass.cpp, etc. which would also have to be updated to resolve)
26+Q_DECLARE_METATYPE(QScriptClass*)
27+Q_DECLARE_METATYPE(QByteArray*)
28+int qScriptClassPointerMetaTypeId = qRegisterMetaType<QScriptClass*>();
29+int qByteArrayPointerMetaTypeId = qRegisterMetaType<QByteArray*>();
30+
31+ArrayBufferClass::ArrayBufferClass(ScriptEngineQtScript* scriptEngine) :
32+QObject(scriptEngine),
33+QScriptClass(scriptEngine) {
34+ qScriptRegisterMetaType<QByteArray>(engine(), toScriptValue, fromScriptValue);
35+ QScriptValue global = engine()->globalObject();
36+
37+ // Save string handles for quick lookup
38+ _name = engine()->toStringHandle(CLASS_NAME.toLatin1());
39+ _byteLength = engine()->toStringHandle(BYTE_LENGTH_PROPERTY_NAME.toLatin1());
40+
41+ // build prototype
42+ _proto = engine()->newQObject(new ArrayBufferPrototype(this),
43+ QScriptEngine::QtOwnership,
44+ QScriptEngine::SkipMethodsInEnumeration |
45+ QScriptEngine::ExcludeSuperClassMethods |
46+ QScriptEngine::ExcludeSuperClassProperties);
47+ _proto.setPrototype(global.property("Object").property("prototype"));
48+
49+ // Register constructor
50+ _ctor = engine()->newFunction(construct, _proto);
51+ _ctor.setData(engine()->toScriptValue(this));
52+
53+ engine()->globalObject().setProperty(name(), _ctor);
54+
55+ // Registering other array types
56+ // The script engine is there parent so it'll delete them with itself
57+ new DataViewClass(scriptEngine);
58+ new Int8ArrayClass(scriptEngine);
59+ new Uint8ArrayClass(scriptEngine);
60+ new Uint8ClampedArrayClass(scriptEngine);
61+ new Int16ArrayClass(scriptEngine);
62+ new Uint16ArrayClass(scriptEngine);
63+ new Int32ArrayClass(scriptEngine);
64+ new Uint32ArrayClass(scriptEngine);
65+ new Float32ArrayClass(scriptEngine);
66+ new Float64ArrayClass(scriptEngine);
67+}
68+
69+QScriptValue ArrayBufferClass::newInstance(qint32 size) {
70+ const qint32 MAX_LENGTH = 100000000;
71+ if (size < 0) {
72+ engine()->evaluate("throw \"ArgumentError: negative length\"");
73+ return QScriptValue();
74+ }
75+ if (size > MAX_LENGTH) {
76+ engine()->evaluate("throw \"ArgumentError: absurd length\"");
77+ return QScriptValue();
78+ }
79+ // We've patched qt to fix https://highfidelity.atlassian.net/browse/BUGZ-46 on mac and windows only.
80+#if defined(Q_OS_WIN) || defined(Q_OS_MAC)
81+ engine()->reportAdditionalMemoryCost(size);
82+#endif
83+ QScriptEngine* eng = engine();
84+ QVariant variant = QVariant::fromValue(QByteArray(size, 0));
85+ QScriptValue data = eng->newVariant(variant);
86+ return engine()->newObject(this, data);
87+}
88+
89+QScriptValue ArrayBufferClass::newInstance(const QByteArray& ba) {
90+ QScriptValue data = engine()->newVariant(QVariant::fromValue(ba));
91+ return engine()->newObject(this, data);
92+}
93+
94+QScriptValue ArrayBufferClass::construct(QScriptContext* context, QScriptEngine* engine) {
95+ ArrayBufferClass* cls = qscriptvalue_cast<ArrayBufferClass*>(context->callee().data());
96+ if (!cls) {
97+ // return if callee (function called) is not of type ArrayBuffer
98+ return QScriptValue();
99+ }
100+ QScriptValue arg = context->argument(0);
101+ if (!arg.isValid() || !arg.isNumber()) {
102+ return QScriptValue();
103+ }
104+
105+ quint32 size = arg.toInt32();
106+ QScriptValue newObject = cls->newInstance(size);
107+
108+ if (context->isCalledAsConstructor()) {
109+ // if called with keyword new, replace this object.
110+ context->setThisObject(newObject);
111+ return engine->undefinedValue();
112+ }
113+
114+ return newObject;
115+}
116+
117+QScriptClass::QueryFlags ArrayBufferClass::queryProperty(const QScriptValue& object,
118+ const QScriptString& name,
119+ QueryFlags flags, uint* id) {
120+ QByteArray* ba = qscriptvalue_cast<QByteArray*>(object.data());
121+ if (ba && name == _byteLength) {
122+ // if the property queried is byteLength, only handle read access
123+ return flags &= HandlesReadAccess;
124+ }
125+ return 0; // No access
126+}
127+
128+QScriptValue ArrayBufferClass::property(const QScriptValue& object,
129+ const QScriptString& name, uint id) {
130+ QByteArray* ba = qscriptvalue_cast<QByteArray*>(object.data());
131+ if (ba && name == _byteLength) {
132+ return ba->length();
133+ }
134+ return QScriptValue();
135+}
136+
137+QScriptValue::PropertyFlags ArrayBufferClass::propertyFlags(const QScriptValue& object,
138+ const QScriptString& name, uint id) {
139+ return QScriptValue::Undeletable;
140+}
141+
142+QString ArrayBufferClass::name() const {
143+ return _name.toString();
144+}
145+
146+QScriptValue ArrayBufferClass::prototype() const {
147+ return _proto;
148+}
149+
150+QScriptValue ArrayBufferClass::toScriptValue(QScriptEngine* engine, const QByteArray& ba) {
151+ QScriptValue ctor = engine->globalObject().property(CLASS_NAME);
152+ ArrayBufferClass* cls = qscriptvalue_cast<ArrayBufferClass*>(ctor.data());
153+ if (!cls) {
154+ if (engine->currentContext()) {
155+ engine->currentContext()->throwError("arrayBufferClass::toScriptValue -- could not get " + CLASS_NAME + " class constructor");
156+ }
157+ return QScriptValue::NullValue;
158+ }
159+ return cls->newInstance(ba);
160+}
161+
162+void ArrayBufferClass::fromScriptValue(const QScriptValue& object, QByteArray& byteArray) {
163+ if (object.isString()) {
164+ // UTF-8 encoded String
165+ byteArray = object.toString().toUtf8();
166+ } else if (object.isArray()) {
167+ // Array of uint8s eg: [ 128, 3, 25, 234 ]
168+ auto Uint8Array = object.engine()->globalObject().property("Uint8Array");
169+ auto typedArray = Uint8Array.construct(QScriptValueList{object});
170+ if (QByteArray* buffer = qscriptvalue_cast<QByteArray*>(typedArray.property("buffer"))) {
171+ byteArray = *buffer;
172+ }
173+ } else if (object.isObject()) {
174+ // ArrayBuffer instance (or any JS class that supports coercion into QByteArray*)
175+ if (QByteArray* buffer = qscriptvalue_cast<QByteArray*>(object.data())) {
176+ byteArray = *buffer;
177+ }
178+ }
179+}
180+