1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/bindings/TypedArray.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,335 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/ 1.5 +/* vim: set ts=2 sw=2 et tw=79: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this file, 1.8 + * You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#ifndef mozilla_dom_TypedArray_h 1.11 +#define mozilla_dom_TypedArray_h 1.12 + 1.13 +#include "jsapi.h" 1.14 +#include "jsfriendapi.h" 1.15 +#include "js/RootingAPI.h" 1.16 +#include "js/TracingAPI.h" 1.17 +#include "mozilla/Attributes.h" 1.18 +#include "mozilla/Move.h" 1.19 +#include "mozilla/dom/BindingDeclarations.h" 1.20 +#include "nsWrapperCache.h" 1.21 + 1.22 +namespace mozilla { 1.23 +namespace dom { 1.24 + 1.25 +/* 1.26 + * Class that just handles the JSObject storage and tracing for typed arrays 1.27 + */ 1.28 +struct TypedArrayObjectStorage : AllTypedArraysBase { 1.29 +protected: 1.30 + JSObject* mObj; 1.31 + 1.32 + TypedArrayObjectStorage(JSObject *obj) : mObj(obj) 1.33 + { 1.34 + } 1.35 + 1.36 + explicit TypedArrayObjectStorage(TypedArrayObjectStorage&& aOther) 1.37 + : mObj(aOther.mObj) 1.38 + { 1.39 + aOther.mObj = nullptr; 1.40 + } 1.41 + 1.42 +public: 1.43 + inline void TraceSelf(JSTracer* trc) 1.44 + { 1.45 + if (mObj) { 1.46 + JS_CallObjectTracer(trc, &mObj, "TypedArray.mObj"); 1.47 + } 1.48 + } 1.49 + 1.50 +private: 1.51 + TypedArrayObjectStorage(const TypedArrayObjectStorage&) MOZ_DELETE; 1.52 +}; 1.53 + 1.54 +/* 1.55 + * Various typed array classes for argument conversion. We have a base class 1.56 + * that has a way of initializing a TypedArray from an existing typed array, and 1.57 + * a subclass of the base class that supports creation of a relevant typed array 1.58 + * or array buffer object. 1.59 + */ 1.60 +template<typename T, 1.61 + JSObject* UnwrapArray(JSObject*), 1.62 + void GetLengthAndData(JSObject*, uint32_t*, T**)> 1.63 +struct TypedArray_base : public TypedArrayObjectStorage { 1.64 + typedef T element_type; 1.65 + 1.66 + TypedArray_base(JSObject* obj) 1.67 + : TypedArrayObjectStorage(obj), 1.68 + mData(nullptr), 1.69 + mLength(0), 1.70 + mComputed(false) 1.71 + { 1.72 + MOZ_ASSERT(obj != nullptr); 1.73 + } 1.74 + 1.75 + TypedArray_base() 1.76 + : TypedArrayObjectStorage(nullptr), 1.77 + mData(nullptr), 1.78 + mLength(0), 1.79 + mComputed(false) 1.80 + { 1.81 + } 1.82 + 1.83 + explicit TypedArray_base(TypedArray_base&& aOther) 1.84 + : TypedArrayObjectStorage(Move(aOther)), 1.85 + mData(aOther.mData), 1.86 + mLength(aOther.mLength) 1.87 + { 1.88 + aOther.mData = nullptr; 1.89 + aOther.mLength = 0; 1.90 + } 1.91 + 1.92 +private: 1.93 + mutable T* mData; 1.94 + mutable uint32_t mLength; 1.95 + mutable bool mComputed; 1.96 + 1.97 +public: 1.98 + inline bool Init(JSObject* obj) 1.99 + { 1.100 + MOZ_ASSERT(!inited()); 1.101 + DoInit(obj); 1.102 + return inited(); 1.103 + } 1.104 + 1.105 + inline bool inited() const { 1.106 + return !!mObj; 1.107 + } 1.108 + 1.109 + inline T *Data() const { 1.110 + MOZ_ASSERT(mComputed); 1.111 + return mData; 1.112 + } 1.113 + 1.114 + inline uint32_t Length() const { 1.115 + MOZ_ASSERT(mComputed); 1.116 + return mLength; 1.117 + } 1.118 + 1.119 + inline JSObject *Obj() const { 1.120 + MOZ_ASSERT(inited()); 1.121 + return mObj; 1.122 + } 1.123 + 1.124 + inline bool WrapIntoNewCompartment(JSContext* cx) 1.125 + { 1.126 + return JS_WrapObject(cx, 1.127 + JS::MutableHandle<JSObject*>::fromMarkedLocation(&mObj)); 1.128 + } 1.129 + 1.130 + inline void ComputeLengthAndData() const 1.131 + { 1.132 + MOZ_ASSERT(inited()); 1.133 + MOZ_ASSERT(!mComputed); 1.134 + GetLengthAndData(mObj, &mLength, &mData); 1.135 + mComputed = true; 1.136 + } 1.137 + 1.138 +protected: 1.139 + inline void DoInit(JSObject* obj) 1.140 + { 1.141 + mObj = UnwrapArray(obj); 1.142 + } 1.143 + 1.144 + inline void ComputeData() const { 1.145 + MOZ_ASSERT(inited()); 1.146 + if (!mComputed) { 1.147 + GetLengthAndData(mObj, &mLength, &mData); 1.148 + mComputed = true; 1.149 + } 1.150 + } 1.151 + 1.152 +private: 1.153 + TypedArray_base(const TypedArray_base&) MOZ_DELETE; 1.154 +}; 1.155 + 1.156 + 1.157 +template<typename T, 1.158 + JSObject* UnwrapArray(JSObject*), 1.159 + T* GetData(JSObject*), 1.160 + void GetLengthAndData(JSObject*, uint32_t*, T**), 1.161 + JSObject* CreateNew(JSContext*, uint32_t)> 1.162 +struct TypedArray : public TypedArray_base<T, UnwrapArray, GetLengthAndData> { 1.163 + TypedArray(JSObject* obj) : 1.164 + TypedArray_base<T, UnwrapArray, GetLengthAndData>(obj) 1.165 + {} 1.166 + 1.167 + TypedArray() : 1.168 + TypedArray_base<T, UnwrapArray, GetLengthAndData>() 1.169 + {} 1.170 + 1.171 + explicit TypedArray(TypedArray&& aOther) 1.172 + : TypedArray_base<T, UnwrapArray, GetLengthAndData>(Move(aOther)) 1.173 + { 1.174 + } 1.175 + 1.176 + static inline JSObject* 1.177 + Create(JSContext* cx, nsWrapperCache* creator, uint32_t length, 1.178 + const T* data = nullptr) { 1.179 + JS::Rooted<JSObject*> creatorWrapper(cx); 1.180 + Maybe<JSAutoCompartment> ac; 1.181 + if (creator && (creatorWrapper = creator->GetWrapperPreserveColor())) { 1.182 + ac.construct(cx, creatorWrapper); 1.183 + } 1.184 + 1.185 + return CreateCommon(cx, length, data); 1.186 + } 1.187 + 1.188 + static inline JSObject* 1.189 + Create(JSContext* cx, uint32_t length, const T* data = nullptr) { 1.190 + return CreateCommon(cx, length, data); 1.191 + } 1.192 + 1.193 +private: 1.194 + static inline JSObject* 1.195 + CreateCommon(JSContext* cx, uint32_t length, const T* data) { 1.196 + JSObject* obj = CreateNew(cx, length); 1.197 + if (!obj) { 1.198 + return nullptr; 1.199 + } 1.200 + if (data) { 1.201 + T* buf = static_cast<T*>(GetData(obj)); 1.202 + memcpy(buf, data, length*sizeof(T)); 1.203 + } 1.204 + return obj; 1.205 + } 1.206 + 1.207 + TypedArray(const TypedArray&) MOZ_DELETE; 1.208 +}; 1.209 + 1.210 +typedef TypedArray<int8_t, js::UnwrapInt8Array, JS_GetInt8ArrayData, 1.211 + js::GetInt8ArrayLengthAndData, JS_NewInt8Array> 1.212 + Int8Array; 1.213 +typedef TypedArray<uint8_t, js::UnwrapUint8Array, JS_GetUint8ArrayData, 1.214 + js::GetUint8ArrayLengthAndData, JS_NewUint8Array> 1.215 + Uint8Array; 1.216 +typedef TypedArray<uint8_t, js::UnwrapUint8ClampedArray, JS_GetUint8ClampedArrayData, 1.217 + js::GetUint8ClampedArrayLengthAndData, JS_NewUint8ClampedArray> 1.218 + Uint8ClampedArray; 1.219 +typedef TypedArray<int16_t, js::UnwrapInt16Array, JS_GetInt16ArrayData, 1.220 + js::GetInt16ArrayLengthAndData, JS_NewInt16Array> 1.221 + Int16Array; 1.222 +typedef TypedArray<uint16_t, js::UnwrapUint16Array, JS_GetUint16ArrayData, 1.223 + js::GetUint16ArrayLengthAndData, JS_NewUint16Array> 1.224 + Uint16Array; 1.225 +typedef TypedArray<int32_t, js::UnwrapInt32Array, JS_GetInt32ArrayData, 1.226 + js::GetInt32ArrayLengthAndData, JS_NewInt32Array> 1.227 + Int32Array; 1.228 +typedef TypedArray<uint32_t, js::UnwrapUint32Array, JS_GetUint32ArrayData, 1.229 + js::GetUint32ArrayLengthAndData, JS_NewUint32Array> 1.230 + Uint32Array; 1.231 +typedef TypedArray<float, js::UnwrapFloat32Array, JS_GetFloat32ArrayData, 1.232 + js::GetFloat32ArrayLengthAndData, JS_NewFloat32Array> 1.233 + Float32Array; 1.234 +typedef TypedArray<double, js::UnwrapFloat64Array, JS_GetFloat64ArrayData, 1.235 + js::GetFloat64ArrayLengthAndData, JS_NewFloat64Array> 1.236 + Float64Array; 1.237 +typedef TypedArray_base<uint8_t, js::UnwrapArrayBufferView, js::GetArrayBufferViewLengthAndData> 1.238 + ArrayBufferView; 1.239 +typedef TypedArray<uint8_t, js::UnwrapArrayBuffer, JS_GetArrayBufferData, 1.240 + js::GetArrayBufferLengthAndData, JS_NewArrayBuffer> 1.241 + ArrayBuffer; 1.242 + 1.243 +// A class for converting an nsTArray to a TypedArray 1.244 +// Note: A TypedArrayCreator must not outlive the nsTArray it was created from. 1.245 +// So this is best used to pass from things that understand nsTArray to 1.246 +// things that understand TypedArray, as with Promise::ArgumentToJSValue. 1.247 +template<typename TypedArrayType> 1.248 +class TypedArrayCreator 1.249 +{ 1.250 + typedef nsTArray<typename TypedArrayType::element_type> ArrayType; 1.251 + 1.252 + public: 1.253 + TypedArrayCreator(const ArrayType& aArray) 1.254 + : mArray(aArray) 1.255 + {} 1.256 + 1.257 + JSObject* Create(JSContext* aCx) const 1.258 + { 1.259 + return TypedArrayType::Create(aCx, mArray.Length(), mArray.Elements()); 1.260 + } 1.261 + 1.262 + private: 1.263 + const ArrayType& mArray; 1.264 +}; 1.265 + 1.266 +// A class for rooting an existing TypedArray struct 1.267 +template<typename ArrayType> 1.268 +class MOZ_STACK_CLASS TypedArrayRooter : private JS::CustomAutoRooter 1.269 +{ 1.270 +public: 1.271 + TypedArrayRooter(JSContext* cx, 1.272 + ArrayType* aArray MOZ_GUARD_OBJECT_NOTIFIER_PARAM) : 1.273 + JS::CustomAutoRooter(cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT), 1.274 + mArray(aArray) 1.275 + { 1.276 + } 1.277 + 1.278 + virtual void trace(JSTracer* trc) MOZ_OVERRIDE 1.279 + { 1.280 + mArray->TraceSelf(trc); 1.281 + } 1.282 + 1.283 +private: 1.284 + TypedArrayObjectStorage* const mArray; 1.285 +}; 1.286 + 1.287 +// And a specialization for dealing with nullable typed arrays 1.288 +template<typename Inner> struct Nullable; 1.289 +template<typename ArrayType> 1.290 +class MOZ_STACK_CLASS TypedArrayRooter<Nullable<ArrayType> > : 1.291 + private JS::CustomAutoRooter 1.292 +{ 1.293 +public: 1.294 + TypedArrayRooter(JSContext* cx, 1.295 + Nullable<ArrayType>* aArray MOZ_GUARD_OBJECT_NOTIFIER_PARAM) : 1.296 + JS::CustomAutoRooter(cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT), 1.297 + mArray(aArray) 1.298 + { 1.299 + } 1.300 + 1.301 + virtual void trace(JSTracer* trc) MOZ_OVERRIDE 1.302 + { 1.303 + if (!mArray->IsNull()) { 1.304 + mArray->Value().TraceSelf(trc); 1.305 + } 1.306 + } 1.307 + 1.308 +private: 1.309 + Nullable<ArrayType>* const mArray; 1.310 +}; 1.311 + 1.312 +// Class for easily setting up a rooted typed array object on the stack 1.313 +template<typename ArrayType> 1.314 +class MOZ_STACK_CLASS RootedTypedArray : public ArrayType, 1.315 + private TypedArrayRooter<ArrayType> 1.316 +{ 1.317 +public: 1.318 + RootedTypedArray(JSContext* cx MOZ_GUARD_OBJECT_NOTIFIER_PARAM) : 1.319 + ArrayType(), 1.320 + TypedArrayRooter<ArrayType>(cx, 1.321 + MOZ_THIS_IN_INITIALIZER_LIST() 1.322 + MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT) 1.323 + { 1.324 + } 1.325 + 1.326 + RootedTypedArray(JSContext* cx, JSObject* obj MOZ_GUARD_OBJECT_NOTIFIER_PARAM) : 1.327 + ArrayType(obj), 1.328 + TypedArrayRooter<ArrayType>(cx, 1.329 + MOZ_THIS_IN_INITIALIZER_LIST() 1.330 + MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT) 1.331 + { 1.332 + } 1.333 +}; 1.334 + 1.335 +} // namespace dom 1.336 +} // namespace mozilla 1.337 + 1.338 +#endif /* mozilla_dom_TypedArray_h */