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
22static 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)
26Q_DECLARE_METATYPE(QScriptClass*)
27Q_DECLARE_METATYPE(QByteArray*)
28int qScriptClassPointerMetaTypeId = qRegisterMetaType<QScriptClass*>();
29int qByteArrayPointerMetaTypeId = qRegisterMetaType<QByteArray*>();
30
31ArrayBufferClass::ArrayBufferClass(ScriptEngineQtScript* scriptEngine) :
32QObject(scriptEngine),
33QScriptClass(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
69QScriptValue 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
89QScriptValue ArrayBufferClass::newInstance(const QByteArray& ba) {
90 QScriptValue data = engine()->newVariant(QVariant::fromValue(ba));
91 return engine()->newObject(this, data);
92}
93
94QScriptValue 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
117QScriptClass::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
128QScriptValue 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
137QScriptValue::PropertyFlags ArrayBufferClass::propertyFlags(const QScriptValue& object,
138 const QScriptString& name, uint id) {
139 return QScriptValue::Undeletable;
140}
141
142QString ArrayBufferClass::name() const {
143 return _name.toString();
144}
145
146QScriptValue ArrayBufferClass::prototype() const {
147 return _proto;
148}
149
150QScriptValue 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
162void 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