1 /* 2 * Copyright (C) 2009 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #ifndef V8ArrayBufferViewCustom_h 32 #define V8ArrayBufferViewCustom_h 33 34 #include "ArrayBuffer.h" 35 36 #include "V8ArrayBuffer.h" 37 #include "V8Binding.h" 38 #include "V8Proxy.h" 39 40 namespace WebCore { 41 42 // Template function used by the ArrayBufferView*Constructor callbacks. 43 template<class ArrayClass, class ElementType> 44 v8::Handle<v8::Value> constructWebGLArrayWithArrayBufferArgument(const v8::Arguments& args, WrapperTypeInfo* type, v8::ExternalArrayType arrayType, bool hasIndexer) 45 { 46 ArrayBuffer* buf = V8ArrayBuffer::toNative(args[0]->ToObject()); 47 if (!buf) 48 return throwError("Could not convert argument 0 to a ArrayBuffer"); 49 bool ok; 50 uint32_t offset = 0; 51 int argLen = args.Length(); 52 if (argLen > 1) { 53 offset = toUInt32(args[1], ok); 54 if (!ok) 55 return throwError("Could not convert argument 1 to a number"); 56 } 57 if ((buf->byteLength() - offset) % sizeof(ElementType)) 58 return throwError("ArrayBuffer length minus the byteOffset is not a multiple of the element size.", V8Proxy::RangeError); 59 uint32_t length = (buf->byteLength() - offset) / sizeof(ElementType); 60 if (argLen > 2) { 61 length = toUInt32(args[2], ok); 62 if (!ok) 63 return throwError("Could not convert argument 2 to a number"); 64 } 65 66 RefPtr<ArrayClass> array = ArrayClass::create(buf, offset, length); 67 if (!array) { 68 V8Proxy::setDOMException(INDEX_SIZE_ERR); 69 return notHandledByInterceptor(); 70 } 71 // Transform the holder into a wrapper object for the array. 72 V8DOMWrapper::setDOMWrapper(args.Holder(), type, array.get()); 73 if (hasIndexer) 74 args.Holder()->SetIndexedPropertiesToExternalArrayData(array.get()->baseAddress(), arrayType, array.get()->length()); 75 return toV8(array.release(), args.Holder()); 76 } 77 78 // Template function used by the ArrayBufferView*Constructor callbacks. 79 template<class ArrayClass, class ElementType> 80 v8::Handle<v8::Value> constructWebGLArray(const v8::Arguments& args, WrapperTypeInfo* type, v8::ExternalArrayType arrayType) 81 { 82 if (!args.IsConstructCall()) 83 return throwError("DOM object constructor cannot be called as a function."); 84 85 int argLen = args.Length(); 86 if (!argLen) { 87 // This happens when we return a previously constructed 88 // ArrayBufferView, e.g. from the call to <Type>Array.subset(). 89 // The V8DOMWrapper will set the internal pointer in the 90 // created object. Unfortunately it doesn't look like it's 91 // possible to distinguish between this case and that where 92 // the user calls "new <Type>Array()" from JavaScript. We must 93 // construct an empty view to avoid crashes when fetching the 94 // length. 95 RefPtr<ArrayClass> array = ArrayClass::create(0); 96 // Transform the holder into a wrapper object for the array. 97 V8DOMWrapper::setDOMWrapper(args.Holder(), type, array.get()); 98 // Do not call SetIndexedPropertiesToExternalArrayData on this 99 // object. Not only is there no point from a performance 100 // perspective, but doing so causes errors in the subset() case. 101 return toV8(array.release(), args.Holder()); 102 } 103 104 // Supported constructors: 105 // WebGL<T>Array(n) where n is an integer: 106 // -- create an empty array of n elements 107 // WebGL<T>Array(arr) where arr is an array: 108 // -- create a WebGL<T>Array containing the contents of "arr" 109 // WebGL<T>Array(buf, offset, length) 110 // -- create a WebGL<T>Array pointing to the ArrayBuffer 111 // "buf", starting at the specified offset, for the given 112 // length 113 114 if (args[0]->IsNull()) { 115 // Invalid first argument 116 // FIXME: use forthcoming V8Proxy::throwTypeError(). 117 return V8Proxy::throwError(V8Proxy::TypeError, "Type error"); 118 } 119 120 // See whether the first argument is a ArrayBuffer. 121 if (V8ArrayBuffer::HasInstance(args[0])) 122 return constructWebGLArrayWithArrayBufferArgument<ArrayClass, ElementType>(args, type, arrayType, true); 123 124 uint32_t len = 0; 125 v8::Handle<v8::Object> srcArray; 126 bool doInstantiation = false; 127 128 if (args[0]->IsObject()) { 129 srcArray = args[0]->ToObject(); 130 if (srcArray.IsEmpty()) 131 return throwError("Could not convert argument 0 to an array"); 132 len = toUInt32(srcArray->Get(v8::String::New("length"))); 133 doInstantiation = true; 134 } else { 135 bool ok = false; 136 int32_t tempLength = toInt32(args[0], ok); // NaN/+inf/-inf returns 0, this is intended by WebIDL 137 if (ok && tempLength >= 0) { 138 len = static_cast<uint32_t>(tempLength); 139 doInstantiation = true; 140 } 141 } 142 143 RefPtr<ArrayClass> array; 144 if (doInstantiation) 145 array = ArrayClass::create(len); 146 if (!array.get()) 147 return throwError("ArrayBufferView size is not a small enough positive integer.", V8Proxy::RangeError); 148 149 if (!srcArray.IsEmpty()) { 150 // Need to copy the incoming array into the newly created ArrayBufferView. 151 for (unsigned i = 0; i < len; i++) { 152 v8::Local<v8::Value> val = srcArray->Get(v8::Integer::NewFromUnsigned(i)); 153 array->set(i, val->NumberValue()); 154 } 155 } 156 157 // Transform the holder into a wrapper object for the array. 158 V8DOMWrapper::setDOMWrapper(args.Holder(), type, array.get()); 159 args.Holder()->SetIndexedPropertiesToExternalArrayData(array.get()->baseAddress(), arrayType, array.get()->length()); 160 return toV8(array.release(), args.Holder()); 161 } 162 163 template <class CPlusPlusArrayType, class JavaScriptWrapperArrayType> 164 v8::Handle<v8::Value> setWebGLArrayHelper(const v8::Arguments& args) 165 { 166 if (args.Length() < 1) { 167 V8Proxy::setDOMException(SYNTAX_ERR); 168 return notHandledByInterceptor(); 169 } 170 171 CPlusPlusArrayType* impl = JavaScriptWrapperArrayType::toNative(args.Holder()); 172 173 if (JavaScriptWrapperArrayType::HasInstance(args[0])) { 174 // void set(in WebGL<T>Array array, [Optional] in unsigned long offset); 175 CPlusPlusArrayType* src = JavaScriptWrapperArrayType::toNative(args[0]->ToObject()); 176 uint32_t offset = 0; 177 if (args.Length() == 2) 178 offset = toUInt32(args[1]); 179 ExceptionCode ec = 0; 180 impl->set(src, offset, ec); 181 V8Proxy::setDOMException(ec); 182 return v8::Undefined(); 183 } 184 185 if (args[0]->IsObject()) { 186 // void set(in sequence<long> array, [Optional] in unsigned long offset); 187 v8::Local<v8::Object> array = args[0]->ToObject(); 188 uint32_t offset = 0; 189 if (args.Length() == 2) 190 offset = toUInt32(args[1]); 191 uint32_t length = toUInt32(array->Get(v8::String::New("length"))); 192 if (offset > impl->length() 193 || offset + length > impl->length() 194 || offset + length < offset) 195 // Out of range offset or overflow 196 V8Proxy::setDOMException(INDEX_SIZE_ERR); 197 else 198 for (uint32_t i = 0; i < length; i++) 199 impl->set(offset + i, array->Get(v8::Integer::NewFromUnsigned(i))->NumberValue()); 200 201 return v8::Undefined(); 202 } 203 204 V8Proxy::setDOMException(SYNTAX_ERR); 205 return notHandledByInterceptor(); 206 } 207 208 } 209 210 #endif // V8ArrayBufferViewCustom_h 211