JSArrayBufferViewHelper.h revision ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddb
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 "ArrayBufferView.h" 31#include "ExceptionCode.h" 32#include "JSArrayBuffer.h" 33#include "JSDOMBinding.h" 34#include <interpreter/CallFrame.h> 35#include <runtime/ArgList.h> 36#include <runtime/Error.h> 37#include <runtime/JSObject.h> 38#include <runtime/JSValue.h> 39 40namespace WebCore { 41 42template <class T> 43JSC::JSValue setWebGLArrayHelper(JSC::ExecState* exec, T* impl, T* (*conversionFunc)(JSC::JSValue)) 44{ 45 if (exec->argumentCount() < 1) 46 return JSC::throwSyntaxError(exec); 47 48 T* array = (*conversionFunc)(exec->argument(0)); 49 if (array) { 50 // void set(in WebGL<T>Array array, [Optional] in unsigned long offset); 51 unsigned offset = 0; 52 if (exec->argumentCount() == 2) 53 offset = exec->argument(1).toInt32(exec); 54 ExceptionCode ec = 0; 55 impl->set(array, offset, ec); 56 setDOMException(exec, ec); 57 return JSC::jsUndefined(); 58 } 59 60 if (exec->argument(0).isObject()) { 61 // void set(in sequence<long> array, [Optional] in unsigned long offset); 62 JSC::JSObject* array = JSC::asObject(exec->argument(0)); 63 uint32_t offset = 0; 64 if (exec->argumentCount() == 2) 65 offset = exec->argument(1).toInt32(exec); 66 uint32_t length = array->get(exec, JSC::Identifier(exec, "length")).toInt32(exec); 67 if (offset > impl->length() 68 || offset + length > impl->length() 69 || offset + length < offset) 70 setDOMException(exec, INDEX_SIZE_ERR); 71 else { 72 for (uint32_t i = 0; i < length; i++) { 73 JSC::JSValue v = array->get(exec, i); 74 if (exec->hadException()) 75 return JSC::jsUndefined(); 76 impl->set(i + offset, v.toNumber(exec)); 77 } 78 } 79 80 return JSC::jsUndefined(); 81 } 82 83 return JSC::throwSyntaxError(exec); 84} 85 86// Template function used by XXXArrayConstructors. 87// If this returns 0, it will already have thrown a JavaScript exception. 88template<class C, typename T> 89PassRefPtr<C> constructArrayBufferViewWithArrayBufferArgument(JSC::ExecState* exec) 90{ 91 RefPtr<ArrayBuffer> buffer = toArrayBuffer(exec->argument(0)); 92 if (!buffer) 93 return 0; 94 95 unsigned offset = (exec->argumentCount() > 1) ? exec->argument(1).toUInt32(exec) : 0; 96 if ((buffer->byteLength() - offset) % sizeof(T)) 97 throwError(exec, createRangeError(exec, "ArrayBuffer length minus the byteOffset is not a multiple of the element size.")); 98 unsigned int length = (buffer->byteLength() - offset) / sizeof(T); 99 if (exec->argumentCount() > 2) 100 length = exec->argument(2).toUInt32(exec); 101 RefPtr<C> array = C::create(buffer, offset, length); 102 if (!array) 103 setDOMException(exec, INDEX_SIZE_ERR); 104 return array; 105} 106 107template<typename T> 108inline T convertArrayValue(JSC::ExecState* exec, JSC::JSValue v) 109{ 110 // For integral types, NaN values must be converted to zero. 111 return static_cast<T>(v.toInteger(exec)); 112} 113 114template<> 115inline float convertArrayValue(JSC::ExecState* exec, JSC::JSValue v) 116{ 117 return static_cast<float>(v.toNumber(exec)); 118} 119 120template<> 121inline double convertArrayValue(JSC::ExecState* exec, JSC::JSValue v) 122{ 123 return static_cast<double>(v.toNumber(exec)); 124} 125 126template<class C, typename T> 127PassRefPtr<C> constructArrayBufferView(JSC::ExecState* exec) 128{ 129 // There are 3 constructors: 130 // 131 // 1) (in int size) 132 // 2) (in ArrayBuffer buffer, [Optional] in int offset, [Optional] in unsigned int length) 133 // 3) (in sequence<T>) - This ends up being a JS "array-like" object 134 // 135 // For the 0 args case, just create a zero-length view. We could 136 // consider raising a SyntaxError for this case, but not all 137 // JavaScript DOM bindings can distinguish between "new 138 // <Type>Array()" and what occurs when a previously-constructed 139 // ArrayBufferView is returned to JavaScript; e.g., from 140 // "array.slice()". 141 if (exec->argumentCount() < 1) 142 return C::create(0); 143 144 if (exec->argument(0).isNull()) { 145 // Invalid first argument 146 throwTypeError(exec); 147 return 0; 148 } 149 150 if (exec->argument(0).isObject()) { 151 RefPtr<C> view = constructArrayBufferViewWithArrayBufferArgument<C, T>(exec); 152 if (view) 153 return view; 154 155 JSC::JSObject* array = asObject(exec->argument(0)); 156 unsigned length = array->get(exec, JSC::Identifier(exec, "length")).toUInt32(exec); 157 void* tempValues; 158 if (!tryFastCalloc(length, sizeof(T)).getValue(tempValues)) { 159 JSC::throwError(exec, createError(exec, "Error")); 160 return 0; 161 } 162 163 OwnFastMallocPtr<T> values(static_cast<T*>(tempValues)); 164 for (unsigned i = 0; i < length; ++i) { 165 JSC::JSValue v = array->get(exec, i); 166 values.get()[i] = convertArrayValue<T>(exec, v); 167 } 168 169 RefPtr<C> result = C::create(values.get(), length); 170 if (!result) 171 setDOMException(exec, INDEX_SIZE_ERR); 172 return result; 173 } 174 175 int length = exec->argument(0).toInt32(exec); 176 RefPtr<C> result; 177 if (length >= 0) 178 result = C::create(static_cast<unsigned>(length)); 179 if (!result) 180 throwError(exec, createRangeError(exec, "ArrayBufferView size is not a small enough positive integer.")); 181 return result; 182} 183 184template <typename JSType, typename WebCoreType> 185static JSC::JSValue toJSArrayBufferView(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, WebCoreType* object) 186{ 187 if (!object) 188 return JSC::jsNull(); 189 190 if (DOMObject* wrapper = getCachedDOMObjectWrapper(exec, object)) 191 return wrapper; 192 193 exec->heap()->reportExtraMemoryCost(object->byteLength()); 194 return createDOMObjectWrapper<JSType>(exec, globalObject, object); 195} 196 197} // namespace WebCore 198 199#endif // JSArrayBufferViewHelper_h 200