diff options
author | Lars Knoll <[email protected]> | 2014-09-10 16:39:23 +0200 |
---|---|---|
committer | Simon Hausmann <[email protected]> | 2014-10-29 09:07:12 +0100 |
commit | 868478e92afaa9d0823f3a65ff3d7b44216087ea (patch) | |
tree | 82156a50555923810ad8a8ffcf2452e405d8d396 /src/qml/jsruntime/qv4dataview.cpp | |
parent | a2c97406cad22a73a4c68303ef54128cf756f577 (diff) |
Implement DataView
The second class that is required for typed
array support.
Change-Id: Idc2dcec7c1eee541f76dc5ab1aea6057ba03cb93
Reviewed-by: Simon Hausmann <[email protected]>
Diffstat (limited to 'src/qml/jsruntime/qv4dataview.cpp')
-rw-r--r-- | src/qml/jsruntime/qv4dataview.cpp | 316 |
1 files changed, 316 insertions, 0 deletions
diff --git a/src/qml/jsruntime/qv4dataview.cpp b/src/qml/jsruntime/qv4dataview.cpp new file mode 100644 index 0000000000..2750b2ceff --- /dev/null +++ b/src/qml/jsruntime/qv4dataview.cpp @@ -0,0 +1,316 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qv4dataview_p.h" +#include "qv4arraybuffer_p.h" + +#include "qendian.h" + +using namespace QV4; + +DEFINE_OBJECT_VTABLE(DataViewCtor); +DEFINE_OBJECT_VTABLE(DataView); + +DataViewCtor::Data::Data(ExecutionContext *scope) + : FunctionObject::Data(scope, QStringLiteral("DataView")) +{ + setVTable(staticVTable()); +} + +ReturnedValue DataViewCtor::construct(Managed *m, CallData *callData) +{ + Scope scope(m->engine()); + Scoped<ArrayBuffer> buffer(scope, callData->argument(0)); + if (!buffer) + return scope.engine->currentContext()->throwTypeError(); + + double bo = callData->argc > 1 ? callData->args[1].toNumber() : 0; + uint byteOffset = (uint)bo; + uint bufferLength = buffer->d()->data->size; + double bl = callData->argc < 3 || callData->args[2].isUndefined() ? (bufferLength - bo) : callData->args[2].toNumber(); + uint byteLength = (uint)bl; + if (bo != byteOffset || bl != byteLength || byteOffset + byteLength > bufferLength) + return scope.engine->currentContext()->throwRangeError(QStringLiteral("DataView: constructor arguments out of range")); + + Scoped<DataView> a(scope, scope.engine->memoryManager->alloc<DataView>(scope.engine)); + a->d()->buffer = buffer; + a->d()->byteLength = byteLength; + a->d()->byteOffset = byteOffset; + return a.asReturnedValue(); + +} + +ReturnedValue DataViewCtor::call(Managed *that, CallData *callData) +{ + return construct(that, callData); +} + + +DataView::Data::Data(ExecutionEngine *e) + : Object::Data(e->dataViewClass), + buffer(0), + byteLength(0), + byteOffset(0) +{ +} + + +void DataView::markObjects(Managed *that, ExecutionEngine *e) +{ + DataView *v = static_cast<DataView *>(that); + v->d()->buffer->mark(e); +} + +void DataViewPrototype::init(ExecutionEngine *engine, Object *ctor) +{ + Scope scope(engine); + ScopedObject o(scope); + ctor->defineReadonlyProperty(engine->id_length, Primitive::fromInt32(3)); + ctor->defineReadonlyProperty(engine->id_prototype, (o = this)); + defineDefaultProperty(engine->id_constructor, (o = ctor)); + defineAccessorProperty(QStringLiteral("buffer"), method_get_buffer, 0); + defineAccessorProperty(QStringLiteral("byteLength"), method_get_byteLength, 0); + defineAccessorProperty(QStringLiteral("byteOffset"), method_get_byteOffset, 0); + + defineDefaultProperty(QStringLiteral("getInt8"), method_getChar<signed char>, 0); + defineDefaultProperty(QStringLiteral("getUInt8"), method_getChar<unsigned char>, 0); + defineDefaultProperty(QStringLiteral("getInt16"), method_get<short>, 0); + defineDefaultProperty(QStringLiteral("getUInt16"), method_get<unsigned short>, 0); + defineDefaultProperty(QStringLiteral("getInt32"), method_get<int>, 0); + defineDefaultProperty(QStringLiteral("getUInt32"), method_get<unsigned int>, 0); + defineDefaultProperty(QStringLiteral("getFloat32"), method_getFloat<float>, 0); + defineDefaultProperty(QStringLiteral("getFloat64"), method_getFloat<double>, 0); + + defineDefaultProperty(QStringLiteral("setInt8"), method_setChar<signed char>, 0); + defineDefaultProperty(QStringLiteral("setUInt8"), method_setChar<unsigned char>, 0); + defineDefaultProperty(QStringLiteral("setInt16"), method_set<short>, 0); + defineDefaultProperty(QStringLiteral("setUInt16"), method_set<unsigned short>, 0); + defineDefaultProperty(QStringLiteral("setInt32"), method_set<int>, 0); + defineDefaultProperty(QStringLiteral("setUInt32"), method_set<unsigned int>, 0); + defineDefaultProperty(QStringLiteral("setFloat32"), method_setFloat<float>, 0); + defineDefaultProperty(QStringLiteral("setFloat64"), method_setFloat<double>, 0); +} + +ReturnedValue DataViewPrototype::method_get_buffer(CallContext *ctx) +{ + Scope scope(ctx); + Scoped<DataView> v(scope, ctx->d()->callData->thisObject); + if (!v) + return ctx->throwTypeError(); + + return Encode(v->d()->buffer->asReturnedValue()); +} + +ReturnedValue DataViewPrototype::method_get_byteLength(CallContext *ctx) +{ + Scope scope(ctx); + Scoped<DataView> v(scope, ctx->d()->callData->thisObject); + if (!v) + return ctx->throwTypeError(); + + return Encode(v->d()->byteLength); +} + +ReturnedValue DataViewPrototype::method_get_byteOffset(CallContext *ctx) +{ + Scope scope(ctx); + Scoped<DataView> v(scope, ctx->d()->callData->thisObject); + if (!v) + return ctx->throwTypeError(); + + return Encode(v->d()->byteOffset); +} + +template <typename T> +ReturnedValue DataViewPrototype::method_getChar(CallContext *ctx) +{ + Scope scope(ctx); + Scoped<DataView> v(scope, ctx->d()->callData->thisObject); + if (!v || ctx->d()->callData->argc < 1) + return ctx->throwTypeError(); + double l = ctx->d()->callData->args[0].toNumber(); + uint idx = (uint)l; + if (l != idx || idx + sizeof(T) > v->d()->byteLength) + return ctx->throwTypeError(); + idx += v->d()->byteOffset; + + T t = T(v->d()->buffer->d()->data->data()[idx]); + + return Encode((int)t); +} + +template <typename T> +ReturnedValue DataViewPrototype::method_get(CallContext *ctx) +{ + Scope scope(ctx); + Scoped<DataView> v(scope, ctx->d()->callData->thisObject); + if (!v || ctx->d()->callData->argc < 1) + return ctx->throwTypeError(); + double l = ctx->d()->callData->args[0].toNumber(); + uint idx = (uint)l; + if (l != idx || idx + sizeof(T) > v->d()->byteLength) + return ctx->throwTypeError(); + idx += v->d()->byteOffset; + + bool littleEndian = ctx->d()->callData->argc < 2 ? false : ctx->d()->callData->args[1].toBoolean(); + + T t = littleEndian + ? qFromLittleEndian<T>((uchar *)v->d()->buffer->d()->data->data() + idx) + : qFromBigEndian<T>((uchar *)v->d()->buffer->d()->data->data() + idx); + + return Encode(t); +} + +template <typename T> +ReturnedValue DataViewPrototype::method_getFloat(CallContext *ctx) +{ + Scope scope(ctx); + Scoped<DataView> v(scope, ctx->d()->callData->thisObject); + if (!v || ctx->d()->callData->argc < 1) + return ctx->throwTypeError(); + double l = ctx->d()->callData->args[0].toNumber(); + uint idx = (uint)l; + if (l != idx || idx + sizeof(T) > v->d()->byteLength) + return ctx->throwTypeError(); + idx += v->d()->byteOffset; + + bool littleEndian = ctx->d()->callData->argc < 2 ? false : ctx->d()->callData->args[1].toBoolean(); + + if (sizeof(T) == 4) { + // float + union { + uint i; + float f; + } u; + u.i = littleEndian + ? qFromLittleEndian<uint>((uchar *)v->d()->buffer->d()->data->data() + idx) + : qFromBigEndian<uint>((uchar *)v->d()->buffer->d()->data->data() + idx); + return Encode(u.f); + } else { + Q_ASSERT(sizeof(T) == 8); + union { + quint64 i; + double d; + } u; + u.i = littleEndian + ? qFromLittleEndian<quint64>((uchar *)v->d()->buffer->d()->data->data() + idx) + : qFromBigEndian<quint64>((uchar *)v->d()->buffer->d()->data->data() + idx); + return Encode(u.d); + } +} + +template <typename T> +ReturnedValue DataViewPrototype::method_setChar(CallContext *ctx) +{ + Scope scope(ctx); + Scoped<DataView> v(scope, ctx->d()->callData->thisObject); + if (!v || ctx->d()->callData->argc < 1) + return ctx->throwTypeError(); + double l = ctx->d()->callData->args[0].toNumber(); + uint idx = (uint)l; + if (l != idx || idx + sizeof(T) > v->d()->byteLength) + return ctx->throwTypeError(); + idx += v->d()->byteOffset; + + int val = ctx->d()->callData->argc >= 2 ? ctx->d()->callData->args[1].toInt32() : 0; + v->d()->buffer->d()->data->data()[idx] = (char)val; + + return Encode::undefined(); +} + +template <typename T> +ReturnedValue DataViewPrototype::method_set(CallContext *ctx) +{ + Scope scope(ctx); + Scoped<DataView> v(scope, ctx->d()->callData->thisObject); + if (!v || ctx->d()->callData->argc < 1) + return ctx->throwTypeError(); + double l = ctx->d()->callData->args[0].toNumber(); + uint idx = (uint)l; + if (l != idx || idx + sizeof(T) > v->d()->byteLength) + return ctx->throwTypeError(); + idx += v->d()->byteOffset; + + int val = ctx->d()->callData->argc >= 2 ? ctx->d()->callData->args[1].toInt32() : 0; + + bool littleEndian = ctx->d()->callData->argc < 3 ? false : ctx->d()->callData->args[2].toBoolean(); + + if (littleEndian) + qToLittleEndian<T>(val, (uchar *)v->d()->buffer->d()->data->data() + idx); + else + qToBigEndian<T>(val, (uchar *)v->d()->buffer->d()->data->data() + idx); + + return Encode::undefined(); +} + +template <typename T> +ReturnedValue DataViewPrototype::method_setFloat(CallContext *ctx) +{ + Scope scope(ctx); + Scoped<DataView> v(scope, ctx->d()->callData->thisObject); + if (!v || ctx->d()->callData->argc < 1) + return ctx->throwTypeError(); + double l = ctx->d()->callData->args[0].toNumber(); + uint idx = (uint)l; + if (l != idx || idx + sizeof(T) > v->d()->byteLength) + return ctx->throwTypeError(); + idx += v->d()->byteOffset; + + double val = ctx->d()->callData->argc >= 2 ? ctx->d()->callData->args[1].toNumber() : qSNaN(); + bool littleEndian = ctx->d()->callData->argc < 3 ? false : ctx->d()->callData->args[2].toBoolean(); + + if (sizeof(T) == 4) { + // float + union { + uint i; + float f; + } u; + u.f = val; + if (littleEndian) + qToLittleEndian(u.i, (uchar *)v->d()->buffer->d()->data->data() + idx); + else + qToBigEndian(u.i, (uchar *)v->d()->buffer->d()->data->data() + idx); + } else { + Q_ASSERT(sizeof(T) == 8); + union { + quint64 i; + double d; + } u; + u.d = val; + if (littleEndian) + qToLittleEndian(u.i, (uchar *)v->d()->buffer->d()->data->data() + idx); + else + qToBigEndian(u.i, (uchar *)v->d()->buffer->d()->data->data() + idx); + } + return Encode::undefined(); +} |