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