diff -r 000000000000 -r 6474c204b198 dom/bindings/TypedArray.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dom/bindings/TypedArray.h Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,335 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/ +/* vim: set ts=2 sw=2 et tw=79: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_dom_TypedArray_h +#define mozilla_dom_TypedArray_h + +#include "jsapi.h" +#include "jsfriendapi.h" +#include "js/RootingAPI.h" +#include "js/TracingAPI.h" +#include "mozilla/Attributes.h" +#include "mozilla/Move.h" +#include "mozilla/dom/BindingDeclarations.h" +#include "nsWrapperCache.h" + +namespace mozilla { +namespace dom { + +/* + * Class that just handles the JSObject storage and tracing for typed arrays + */ +struct TypedArrayObjectStorage : AllTypedArraysBase { +protected: + JSObject* mObj; + + TypedArrayObjectStorage(JSObject *obj) : mObj(obj) + { + } + + explicit TypedArrayObjectStorage(TypedArrayObjectStorage&& aOther) + : mObj(aOther.mObj) + { + aOther.mObj = nullptr; + } + +public: + inline void TraceSelf(JSTracer* trc) + { + if (mObj) { + JS_CallObjectTracer(trc, &mObj, "TypedArray.mObj"); + } + } + +private: + TypedArrayObjectStorage(const TypedArrayObjectStorage&) MOZ_DELETE; +}; + +/* + * Various typed array classes for argument conversion. We have a base class + * that has a way of initializing a TypedArray from an existing typed array, and + * a subclass of the base class that supports creation of a relevant typed array + * or array buffer object. + */ +template +struct TypedArray_base : public TypedArrayObjectStorage { + typedef T element_type; + + TypedArray_base(JSObject* obj) + : TypedArrayObjectStorage(obj), + mData(nullptr), + mLength(0), + mComputed(false) + { + MOZ_ASSERT(obj != nullptr); + } + + TypedArray_base() + : TypedArrayObjectStorage(nullptr), + mData(nullptr), + mLength(0), + mComputed(false) + { + } + + explicit TypedArray_base(TypedArray_base&& aOther) + : TypedArrayObjectStorage(Move(aOther)), + mData(aOther.mData), + mLength(aOther.mLength) + { + aOther.mData = nullptr; + aOther.mLength = 0; + } + +private: + mutable T* mData; + mutable uint32_t mLength; + mutable bool mComputed; + +public: + inline bool Init(JSObject* obj) + { + MOZ_ASSERT(!inited()); + DoInit(obj); + return inited(); + } + + inline bool inited() const { + return !!mObj; + } + + inline T *Data() const { + MOZ_ASSERT(mComputed); + return mData; + } + + inline uint32_t Length() const { + MOZ_ASSERT(mComputed); + return mLength; + } + + inline JSObject *Obj() const { + MOZ_ASSERT(inited()); + return mObj; + } + + inline bool WrapIntoNewCompartment(JSContext* cx) + { + return JS_WrapObject(cx, + JS::MutableHandle::fromMarkedLocation(&mObj)); + } + + inline void ComputeLengthAndData() const + { + MOZ_ASSERT(inited()); + MOZ_ASSERT(!mComputed); + GetLengthAndData(mObj, &mLength, &mData); + mComputed = true; + } + +protected: + inline void DoInit(JSObject* obj) + { + mObj = UnwrapArray(obj); + } + + inline void ComputeData() const { + MOZ_ASSERT(inited()); + if (!mComputed) { + GetLengthAndData(mObj, &mLength, &mData); + mComputed = true; + } + } + +private: + TypedArray_base(const TypedArray_base&) MOZ_DELETE; +}; + + +template +struct TypedArray : public TypedArray_base { + TypedArray(JSObject* obj) : + TypedArray_base(obj) + {} + + TypedArray() : + TypedArray_base() + {} + + explicit TypedArray(TypedArray&& aOther) + : TypedArray_base(Move(aOther)) + { + } + + static inline JSObject* + Create(JSContext* cx, nsWrapperCache* creator, uint32_t length, + const T* data = nullptr) { + JS::Rooted creatorWrapper(cx); + Maybe ac; + if (creator && (creatorWrapper = creator->GetWrapperPreserveColor())) { + ac.construct(cx, creatorWrapper); + } + + return CreateCommon(cx, length, data); + } + + static inline JSObject* + Create(JSContext* cx, uint32_t length, const T* data = nullptr) { + return CreateCommon(cx, length, data); + } + +private: + static inline JSObject* + CreateCommon(JSContext* cx, uint32_t length, const T* data) { + JSObject* obj = CreateNew(cx, length); + if (!obj) { + return nullptr; + } + if (data) { + T* buf = static_cast(GetData(obj)); + memcpy(buf, data, length*sizeof(T)); + } + return obj; + } + + TypedArray(const TypedArray&) MOZ_DELETE; +}; + +typedef TypedArray + Int8Array; +typedef TypedArray + Uint8Array; +typedef TypedArray + Uint8ClampedArray; +typedef TypedArray + Int16Array; +typedef TypedArray + Uint16Array; +typedef TypedArray + Int32Array; +typedef TypedArray + Uint32Array; +typedef TypedArray + Float32Array; +typedef TypedArray + Float64Array; +typedef TypedArray_base + ArrayBufferView; +typedef TypedArray + ArrayBuffer; + +// A class for converting an nsTArray to a TypedArray +// Note: A TypedArrayCreator must not outlive the nsTArray it was created from. +// So this is best used to pass from things that understand nsTArray to +// things that understand TypedArray, as with Promise::ArgumentToJSValue. +template +class TypedArrayCreator +{ + typedef nsTArray ArrayType; + + public: + TypedArrayCreator(const ArrayType& aArray) + : mArray(aArray) + {} + + JSObject* Create(JSContext* aCx) const + { + return TypedArrayType::Create(aCx, mArray.Length(), mArray.Elements()); + } + + private: + const ArrayType& mArray; +}; + +// A class for rooting an existing TypedArray struct +template +class MOZ_STACK_CLASS TypedArrayRooter : private JS::CustomAutoRooter +{ +public: + TypedArrayRooter(JSContext* cx, + ArrayType* aArray MOZ_GUARD_OBJECT_NOTIFIER_PARAM) : + JS::CustomAutoRooter(cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT), + mArray(aArray) + { + } + + virtual void trace(JSTracer* trc) MOZ_OVERRIDE + { + mArray->TraceSelf(trc); + } + +private: + TypedArrayObjectStorage* const mArray; +}; + +// And a specialization for dealing with nullable typed arrays +template struct Nullable; +template +class MOZ_STACK_CLASS TypedArrayRooter > : + private JS::CustomAutoRooter +{ +public: + TypedArrayRooter(JSContext* cx, + Nullable* aArray MOZ_GUARD_OBJECT_NOTIFIER_PARAM) : + JS::CustomAutoRooter(cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT), + mArray(aArray) + { + } + + virtual void trace(JSTracer* trc) MOZ_OVERRIDE + { + if (!mArray->IsNull()) { + mArray->Value().TraceSelf(trc); + } + } + +private: + Nullable* const mArray; +}; + +// Class for easily setting up a rooted typed array object on the stack +template +class MOZ_STACK_CLASS RootedTypedArray : public ArrayType, + private TypedArrayRooter +{ +public: + RootedTypedArray(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) : + ArrayType(), + TypedArrayRooter(cx, + MOZ_THIS_IN_INITIALIZER_LIST() + MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT) + { + } + + RootedTypedArray(JSContext* cx, JSObject* obj MOZ_GUARD_OBJECT_NOTIFIER_PARAM) : + ArrayType(obj), + TypedArrayRooter(cx, + MOZ_THIS_IN_INITIALIZER_LIST() + MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT) + { + } +}; + +} // namespace dom +} // namespace mozilla + +#endif /* mozilla_dom_TypedArray_h */