dom/bindings/TypedArray.h

changeset 0
6474c204b198
     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 */

mercurial