1/* 2 * Copyright (C) 2009 Apple Inc. All rights reserved. 3 * Copyright (C) 2009 Google Inc. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#ifndef JSArrayBufferViewHelper_h 28#define JSArrayBufferViewHelper_h 29 30#include "JSArrayBuffer.h" 31#include "JSArrayBufferView.h" 32#include "JSDOMBinding.h" 33#include <interpreter/CallFrame.h> 34#include <runtime/ArgList.h> 35#include <runtime/Error.h> 36#include <runtime/JSCJSValue.h> 37#include <runtime/JSObject.h> 38#include <runtime/Operations.h> 39#include <wtf/ArrayBufferView.h> 40#include <wtf/TypedArrayBase.h> 41 42namespace WebCore { 43 44static const char* tooLargeSize = "Size is too large (or is negative)."; 45 46template<class C, typename T> 47bool copyTypedArrayBuffer(C* target, ArrayBufferView* source, unsigned sourceLength, unsigned offset) 48{ 49 ArrayBufferView::ViewType sourceType = source->getType(); 50 ASSERT(sourceType != ArrayBufferView::TypeDataView); 51 52 if (target->getType() == sourceType) { 53 if (!target->set(static_cast<C*>(source), offset)) 54 return false; 55 return true; 56 } 57 58 if (!target->checkInboundData(offset, sourceLength)) 59 return false; 60 61 switch (sourceType) { 62 case ArrayBufferView::TypeInt8: 63 for (unsigned i = 0; i < sourceLength; ++i) 64 target->set(i + offset, (T)(static_cast<TypedArrayBase<signed char> *>(source)->item(i))); 65 break; 66 case ArrayBufferView::TypeUint8: 67 case ArrayBufferView::TypeUint8Clamped: 68 for (unsigned i = 0; i < sourceLength; ++i) 69 target->set(i + offset, (T)(static_cast<TypedArrayBase<unsigned char> *>(source)->item(i))); 70 break; 71 case ArrayBufferView::TypeInt16: 72 for (unsigned i = 0; i < sourceLength; ++i) 73 target->set(i + offset, (T)(static_cast<TypedArrayBase<signed short> *>(source)->item(i))); 74 break; 75 case ArrayBufferView::TypeUint16: 76 for (unsigned i = 0; i < sourceLength; ++i) 77 target->set(i + offset, (T)(static_cast<TypedArrayBase<unsigned short> *>(source)->item(i))); 78 break; 79 case ArrayBufferView::TypeInt32: 80 for (unsigned i = 0; i < sourceLength; ++i) 81 target->set(i + offset, (T)(static_cast<TypedArrayBase<int> *>(source)->item(i))); 82 break; 83 case ArrayBufferView::TypeUint32: 84 for (unsigned i = 0; i < sourceLength; ++i) 85 target->set(i + offset, (T)(static_cast<TypedArrayBase<unsigned int> *>(source)->item(i))); 86 break; 87 case ArrayBufferView::TypeFloat32: 88 for (unsigned i = 0; i < sourceLength; ++i) 89 target->set(i + offset, (T)(static_cast<TypedArrayBase<float> *>(source)->item(i))); 90 break; 91 case ArrayBufferView::TypeFloat64: 92 for (unsigned i = 0; i < sourceLength; ++i) 93 target->set(i + offset, (T)(static_cast<TypedArrayBase<double> *>(source)->item(i))); 94 break; 95 default: 96 break; 97 } 98 99 return true; 100} 101 102template <class C, typename T> 103bool setWebGLArrayWithTypedArrayArgument(JSC::ExecState* exec, C* impl) 104{ 105 RefPtr<ArrayBufferView> array = toArrayBufferView(exec->argument(0)); 106 if (!array) 107 return false; 108 109 ArrayBufferView::ViewType arrayType = array->getType(); 110 if (arrayType == ArrayBufferView::TypeDataView) 111 return false; 112 113 unsigned offset = 0; 114 if (exec->argumentCount() == 2) 115 offset = exec->argument(1).toInt32(exec); 116 117 uint32_t length = asObject(exec->argument(0))->get(exec, exec->vm().propertyNames->length).toUInt32(exec); 118 119 if (!(copyTypedArrayBuffer<C, T>(impl, array.get(), length, offset))) 120 throwError(exec, createRangeError(exec, "Index is out of range.")); 121 122 return true; 123} 124 125template<class C, typename T> 126JSC::JSValue setWebGLArrayHelper(JSC::ExecState* exec, C* impl) 127{ 128 if (exec->argumentCount() < 1) 129 return JSC::throwError(exec, createNotEnoughArgumentsError(exec)); 130 131 if (setWebGLArrayWithTypedArrayArgument<C, T>(exec, impl)) 132 // void set(in WebGL<>Array array, [Optional] in unsigned long offset); 133 return JSC::jsUndefined(); 134 135 if (exec->argument(0).isObject()) { 136 // void set(in sequence<long> array, [Optional] in unsigned long offset); 137 JSC::JSObject* array = JSC::asObject(exec->argument(0)); 138 uint32_t offset = 0; 139 if (exec->argumentCount() == 2) 140 offset = exec->argument(1).toInt32(exec); 141 uint32_t length = array->get(exec, exec->vm().propertyNames->length).toInt32(exec); 142 if (!impl->checkInboundData(offset, length)) 143 throwError(exec, createRangeError(exec, "Index is out of range.")); 144 else { 145 for (uint32_t i = 0; i < length; i++) { 146 JSC::JSValue v = array->get(exec, i); 147 if (exec->hadException()) 148 return JSC::jsUndefined(); 149 impl->set(i + offset, v.toNumber(exec)); 150 } 151 } 152 153 return JSC::jsUndefined(); 154 } 155 156 return JSC::throwTypeError(exec, "Invalid argument"); 157} 158 159// Template function used by XXXArrayConstructors. 160// If this returns 0, it will already have thrown a JavaScript exception. 161template<class C, typename T> 162PassRefPtr<C> constructArrayBufferViewWithTypedArrayArgument(JSC::ExecState* exec) 163{ 164 RefPtr<ArrayBufferView> source = toArrayBufferView(exec->argument(0)); 165 if (!source) 166 return 0; 167 168 ArrayBufferView::ViewType sourceType = source->getType(); 169 if (sourceType == ArrayBufferView::TypeDataView) 170 return 0; 171 172 uint32_t length = asObject(exec->argument(0))->get(exec, exec->vm().propertyNames->length).toUInt32(exec); 173 RefPtr<C> array = C::createUninitialized(length); 174 if (!array) { 175 throwError(exec, createRangeError(exec, tooLargeSize)); 176 return array; 177 } 178 179 if (!(copyTypedArrayBuffer<C, T>(array.get(), source.get(), length, 0))) { 180 throwError(exec, createRangeError(exec, tooLargeSize)); 181 return array; 182 } 183 184 return array; 185} 186 187// Template function used by XXXArrayConstructors. 188// If this returns 0, it will already have thrown a JavaScript exception. 189template<class C, typename T> 190PassRefPtr<C> constructArrayBufferViewWithArrayBufferArgument(JSC::ExecState* exec) 191{ 192 RefPtr<ArrayBuffer> buffer = toArrayBuffer(exec->argument(0)); 193 if (!buffer) 194 return 0; 195 196 unsigned offset = (exec->argumentCount() > 1) ? exec->argument(1).toUInt32(exec) : 0; 197 unsigned int length = 0; 198 if (exec->argumentCount() > 2) 199 length = exec->argument(2).toUInt32(exec); 200 else { 201 if ((buffer->byteLength() - offset) % sizeof(T)) { 202 throwError(exec, createRangeError(exec, "ArrayBuffer length minus the byteOffset is not a multiple of the element size.")); 203 return 0; 204 } 205 length = (buffer->byteLength() - offset) / sizeof(T); 206 } 207 RefPtr<C> array = C::create(buffer, offset, length); 208 if (!array) 209 throwError(exec, createRangeError(exec, tooLargeSize)); 210 return array; 211} 212 213template<class C, typename T> 214PassRefPtr<C> constructArrayBufferView(JSC::ExecState* exec) 215{ 216 // There are 3 constructors: 217 // 218 // 1) (in int size) 219 // 2) (in ArrayBuffer buffer, [Optional] in int offset, [Optional] in unsigned int length) 220 // 3) (in sequence<T>) - This ends up being a JS "array-like" object 221 // 222 // For the 0 args case, just create a zero-length view. We could 223 // consider raising a SyntaxError for this case, but not all 224 // JavaScript DOM bindings can distinguish between "new 225 // <Type>Array()" and what occurs when a previously-constructed 226 // ArrayBufferView is returned to JavaScript; e.g., from 227 // "array.subset()". 228 if (exec->argumentCount() < 1) 229 return C::create(0); 230 231 if (exec->argument(0).isNull()) { 232 // Invalid first argument 233 throwTypeError(exec); 234 return 0; 235 } 236 237 if (exec->argument(0).isObject()) { 238 RefPtr<C> view = constructArrayBufferViewWithArrayBufferArgument<C, T>(exec); 239 if (view) 240 return view; 241 242 view = constructArrayBufferViewWithTypedArrayArgument<C, T>(exec); 243 if (view) 244 return view; 245 246 JSC::JSObject* srcArray = asObject(exec->argument(0)); 247 uint32_t length = srcArray->get(exec, exec->vm().propertyNames->length).toUInt32(exec); 248 RefPtr<C> array = C::createUninitialized(length); 249 if (!array) { 250 throwError(exec, createRangeError(exec, tooLargeSize)); 251 return array; 252 } 253 254 for (unsigned i = 0; i < length; ++i) { 255 JSC::JSValue v = srcArray->get(exec, i); 256 array->set(i, v.toNumber(exec)); 257 } 258 return array; 259 } 260 261 int length = exec->argument(0).toInt32(exec); 262 RefPtr<C> result; 263 if (length >= 0) 264 result = C::create(static_cast<unsigned>(length)); 265 if (!result) 266 throwError(exec, createRangeError(exec, tooLargeSize)); 267 return result; 268} 269 270template <typename JSType, typename WebCoreType> 271static JSC::JSValue toJSArrayBufferView(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, WebCoreType* object) 272{ 273 if (!object) 274 return JSC::jsNull(); 275 276 if (JSDOMWrapper* wrapper = getCachedWrapper(currentWorld(exec), object)) 277 return wrapper; 278 279 exec->heap()->reportExtraMemoryCost(object->byteLength()); 280 return createWrapper<JSType>(exec, globalObject, object); 281} 282 283} // namespace WebCore 284 285#endif // JSArrayBufferViewHelper_h 286