| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2009, 2011 Google Inc. All rights reserved. | 2 * Copyright (C) 2009, 2011 Google Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
| 6 * met: | 6 * met: |
| 7 * | 7 * |
| 8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
| (...skipping 19 matching lines...) Expand all Loading... |
| 30 | 30 |
| 31 #ifndef V8ArrayBufferViewCustom_h | 31 #ifndef V8ArrayBufferViewCustom_h |
| 32 #define V8ArrayBufferViewCustom_h | 32 #define V8ArrayBufferViewCustom_h |
| 33 | 33 |
| 34 #include "bindings/v8/V8Binding.h" | 34 #include "bindings/v8/V8Binding.h" |
| 35 #include "bindings/v8/V8ObjectConstructor.h" | 35 #include "bindings/v8/V8ObjectConstructor.h" |
| 36 #include "bindings/v8/custom/V8ArrayBufferCustom.h" | 36 #include "bindings/v8/custom/V8ArrayBufferCustom.h" |
| 37 #include "core/dom/ExceptionCode.h" | 37 #include "core/dom/ExceptionCode.h" |
| 38 | 38 |
| 39 #include "wtf/ArrayBuffer.h" | 39 #include "wtf/ArrayBuffer.h" |
| 40 #include "wtf/ArrayBufferView.h" |
| 40 | 41 |
| 41 namespace WebCore { | 42 namespace WebCore { |
| 42 | 43 |
| 43 const char tooLargeSize[] = "Size is too large (or is negative)."; | |
| 44 const char outOfRangeLengthAndOffset[] = "Index is out of range."; | |
| 45 | 44 |
| 46 // Copy the elements from the source array to the typed destination array. | 45 class V8ArrayBufferView { |
| 47 // Returns true if it succeeded, otherwise returns false. | 46 public: |
| 48 bool copyElements(v8::Handle<v8::Object> destArray, v8::Handle<v8::Object> srcAr
ray, uint32_t length, uint32_t offset, v8::Isolate*); | 47 static bool HasInstance(v8::Handle<v8::Value> value, v8::Isolate*, WrapperWo
rldType) |
| 48 { |
| 49 return value->IsArrayBufferView(); |
| 50 } |
| 51 static bool HasInstanceInAnyWorld(v8::Handle<v8::Value> value, v8::Isolate*) |
| 52 { |
| 53 return value->IsArrayBufferView(); |
| 54 } |
| 55 static ArrayBufferView* toNative(v8::Handle<v8::Object>); |
| 49 | 56 |
| 50 template<class JavaScriptWrapperArrayType, class ArrayClass> | 57 static inline void* toInternalPointer(ArrayBufferView* impl) |
| 51 void wrapArrayBufferView(const v8::FunctionCallbackInfo<v8::Value>& args, Wrappe
rTypeInfo* type, ArrayClass array, v8::ExternalArrayType arrayType, bool hasInde
xer) | 58 { |
| 52 { | 59 return impl; |
| 53 // Transform the holder into a wrapper object for the array. | |
| 54 ASSERT(!hasIndexer || static_cast<int32_t>(array.get()->length()) >= 0); | |
| 55 if (hasIndexer) | |
| 56 args.Holder()->SetIndexedPropertiesToExternalArrayData(array.get()->base
Address(), arrayType, array.get()->length()); | |
| 57 v8::Handle<v8::Object> wrapper = args.Holder(); | |
| 58 V8DOMWrapper::associateObjectWithWrapper<JavaScriptWrapperArrayType>(array.r
elease(), type, wrapper, args.GetIsolate(), WrapperConfiguration::Independent); | |
| 59 args.GetReturnValue().Set(wrapper); | |
| 60 } | |
| 61 | |
| 62 // Template function used by the ArrayBufferView*Constructor callbacks. | |
| 63 template<class ArrayClass, class ElementType, class JavaScriptWrapperArrayType> | |
| 64 void constructWebGLArrayWithArrayBufferArgument(const v8::FunctionCallbackInfo<v
8::Value>& args, WrapperTypeInfo* type, v8::ExternalArrayType arrayType, bool ha
sIndexer) | |
| 65 { | |
| 66 ArrayBuffer* buf = V8ArrayBuffer::toNative(args[0]->ToObject()); | |
| 67 if (!buf) { | |
| 68 throwTypeError("Could not convert argument 0 to a ArrayBuffer", args.Get
Isolate()); | |
| 69 return; | |
| 70 } | 60 } |
| 71 bool ok; | 61 }; |
| 72 uint32_t offset = 0; | |
| 73 int argLen = args.Length(); | |
| 74 if (argLen > 1) { | |
| 75 offset = toUInt32(args[1], ok); | |
| 76 if (!ok) { | |
| 77 throwTypeError("Could not convert argument 1 to a number", args.GetI
solate()); | |
| 78 return; | |
| 79 } | |
| 80 } | |
| 81 uint32_t length = 0; | |
| 82 if (argLen > 2) { | |
| 83 length = toUInt32(args[2], ok); | |
| 84 if (!ok) { | |
| 85 throwTypeError("Could not convert argument 2 to a number", args.GetI
solate()); | |
| 86 return; | |
| 87 } | |
| 88 } else { | |
| 89 if ((buf->byteLength() - offset) % sizeof(ElementType)) { | |
| 90 throwError(v8RangeError, "ArrayBuffer length minus the byteOffset is
not a multiple of the element size.", args.GetIsolate()); | |
| 91 return; | |
| 92 } | |
| 93 length = (buf->byteLength() - offset) / sizeof(ElementType); | |
| 94 } | |
| 95 | |
| 96 if (static_cast<int32_t>(length) < 0) { | |
| 97 throwError(v8RangeError, tooLargeSize, args.GetIsolate()); | |
| 98 return; | |
| 99 } | |
| 100 | |
| 101 RefPtr<ArrayClass> array = ArrayClass::create(buf, offset, length); | |
| 102 if (!array) { | |
| 103 throwError(v8RangeError, tooLargeSize, args.GetIsolate()); | |
| 104 return; | |
| 105 } | |
| 106 | |
| 107 wrapArrayBufferView<JavaScriptWrapperArrayType>(args, type, array, arrayType
, hasIndexer); | |
| 108 } | |
| 109 | |
| 110 // Template function used by the ArrayBufferView*Constructor callbacks. | |
| 111 template<class ArrayClass, class JavaScriptWrapperArrayType, class ElementType> | |
| 112 void constructWebGLArray(const v8::FunctionCallbackInfo<v8::Value>& args, Wrappe
rTypeInfo* type, v8::ExternalArrayType arrayType) | |
| 113 { | |
| 114 if (!args.IsConstructCall()) { | |
| 115 throwTypeError("DOM object constructor cannot be called as a function.",
args.GetIsolate()); | |
| 116 return; | |
| 117 } | |
| 118 | |
| 119 if (ConstructorMode::current() == ConstructorMode::WrapExistingObject) { | |
| 120 args.GetReturnValue().Set(args.Holder()); | |
| 121 return; | |
| 122 } | |
| 123 | |
| 124 int argLen = args.Length(); | |
| 125 if (!argLen) { | |
| 126 // This happens when we return a previously constructed | |
| 127 // ArrayBufferView, e.g. from the call to <Type>Array.subset(). | |
| 128 // The V8DOMWrapper will set the internal pointer in the | |
| 129 // created object. Unfortunately it doesn't look like it's | |
| 130 // possible to distinguish between this case and that where | |
| 131 // the user calls "new <Type>Array()" from JavaScript. We must | |
| 132 // construct an empty view to avoid crashes when fetching the | |
| 133 // length. | |
| 134 RefPtr<ArrayClass> array = ArrayClass::create(0); | |
| 135 // Do not call SetIndexedPropertiesToExternalArrayData on this | |
| 136 // object. Not only is there no point from a performance | |
| 137 // perspective, but doing so causes errors in the subset() case. | |
| 138 wrapArrayBufferView<JavaScriptWrapperArrayType>(args, type, array, array
Type, false); | |
| 139 return; | |
| 140 } | |
| 141 | |
| 142 // Supported constructors: | |
| 143 // WebGL<T>Array(n) where n is an integer: | |
| 144 // -- create an empty array of n elements | |
| 145 // WebGL<T>Array(arr) where arr is an array: | |
| 146 // -- create a WebGL<T>Array containing the contents of "arr" | |
| 147 // WebGL<T>Array(buf, offset, length) | |
| 148 // -- create a WebGL<T>Array pointing to the ArrayBuffer | |
| 149 // "buf", starting at the specified offset, for the given | |
| 150 // length | |
| 151 | |
| 152 if (args[0]->IsNull()) { | |
| 153 // Invalid first argument | |
| 154 throwTypeError(args.GetIsolate()); | |
| 155 return; | |
| 156 } | |
| 157 | |
| 158 // See whether the first argument is a ArrayBuffer. | |
| 159 if (V8ArrayBuffer::HasInstance(args[0], args.GetIsolate(), worldType(args.Ge
tIsolate()))) { | |
| 160 constructWebGLArrayWithArrayBufferArgument<ArrayClass, ElementType, Java
ScriptWrapperArrayType>(args, type, arrayType, true); | |
| 161 return; | |
| 162 } | |
| 163 | |
| 164 // See whether the first argument is the same type as impl. In that case, | |
| 165 // we can simply memcpy data from source to impl. | |
| 166 if (JavaScriptWrapperArrayType::HasInstance(args[0], args.GetIsolate(), worl
dType(args.GetIsolate()))) { | |
| 167 ArrayClass* source = JavaScriptWrapperArrayType::toNative(args[0]->ToObj
ect()); | |
| 168 uint32_t length = source->length(); | |
| 169 | |
| 170 if (static_cast<int32_t>(length) < 0) { | |
| 171 throwError(v8RangeError, tooLargeSize, args.GetIsolate()); | |
| 172 return; | |
| 173 } | |
| 174 | |
| 175 RefPtr<ArrayClass> array = ArrayClass::createUninitialized(length); | |
| 176 if (!array.get()) { | |
| 177 throwError(v8RangeError, tooLargeSize, args.GetIsolate()); | |
| 178 return; | |
| 179 } | |
| 180 | |
| 181 array->buffer()->setDeallocationObserver(V8ArrayBufferDeallocationObserv
er::instance()); | |
| 182 v8::V8::AdjustAmountOfExternalAllocatedMemory(array->byteLength()); | |
| 183 | |
| 184 memcpy(array->baseAddress(), source->baseAddress(), length * sizeof(Elem
entType)); | |
| 185 | |
| 186 wrapArrayBufferView<JavaScriptWrapperArrayType>(args, type, array, array
Type, true); | |
| 187 return; | |
| 188 } | |
| 189 | |
| 190 uint32_t len = 0; | |
| 191 v8::Handle<v8::Object> srcArray; | |
| 192 bool doInstantiation = false; | |
| 193 | |
| 194 if (args[0]->IsObject()) { | |
| 195 srcArray = args[0]->ToObject(); | |
| 196 if (srcArray.IsEmpty()) { | |
| 197 throwTypeError("Could not convert argument 0 to an array", args.GetI
solate()); | |
| 198 return; | |
| 199 } | |
| 200 v8::Local<v8::Value> val = srcArray->Get(v8::String::NewSymbol("length")
); | |
| 201 if (val.IsEmpty()) { | |
| 202 // Exception thrown during fetch of length property. | |
| 203 return; | |
| 204 } | |
| 205 len = toUInt32(val); | |
| 206 doInstantiation = true; | |
| 207 } else { | |
| 208 bool ok = false; | |
| 209 int32_t tempLength = toInt32(args[0], ok); // NaN/+inf/-inf returns 0, t
his is intended by WebIDL | |
| 210 if (ok && tempLength >= 0) { | |
| 211 len = static_cast<uint32_t>(tempLength); | |
| 212 doInstantiation = true; | |
| 213 } | |
| 214 } | |
| 215 | |
| 216 if (static_cast<int32_t>(len) < 0) { | |
| 217 throwError(v8RangeError, tooLargeSize, args.GetIsolate()); | |
| 218 return; | |
| 219 } | |
| 220 | |
| 221 RefPtr<ArrayClass> array; | |
| 222 if (doInstantiation) { | |
| 223 if (srcArray.IsEmpty()) | |
| 224 array = ArrayClass::create(len); | |
| 225 else | |
| 226 array = ArrayClass::createUninitialized(len); | |
| 227 } | |
| 228 | |
| 229 if (!array.get()) { | |
| 230 throwError(v8RangeError, tooLargeSize, args.GetIsolate()); | |
| 231 return; | |
| 232 } | |
| 233 | |
| 234 if (doInstantiation) { | |
| 235 array->buffer()->setDeallocationObserver(V8ArrayBufferDeallocationObserv
er::instance()); | |
| 236 v8::V8::AdjustAmountOfExternalAllocatedMemory(array->byteLength()); | |
| 237 } | |
| 238 | 62 |
| 239 | 63 |
| 240 // Transform the holder into a wrapper object for the array. | 64 } // namespace WebCore |
| 241 args.Holder()->SetIndexedPropertiesToExternalArrayData(array.get()->baseAddr
ess(), arrayType, array.get()->length()); | |
| 242 | |
| 243 if (!srcArray.IsEmpty()) { | |
| 244 bool copied = copyElements(args.Holder(), srcArray, len, 0, args.GetIsol
ate()); | |
| 245 if (!copied) { | |
| 246 for (unsigned i = 0; i < len; i++) { | |
| 247 v8::Local<v8::Value> val = srcArray->Get(i); | |
| 248 if (val.IsEmpty()) { | |
| 249 // Exception thrown during fetch. | |
| 250 return; | |
| 251 } | |
| 252 array->set(i, val->NumberValue()); | |
| 253 } | |
| 254 } | |
| 255 } | |
| 256 | |
| 257 v8::Handle<v8::Object> wrapper = args.Holder(); | |
| 258 V8DOMWrapper::associateObjectWithWrapper<JavaScriptWrapperArrayType>(array.r
elease(), type, wrapper, args.GetIsolate(), WrapperConfiguration::Independent); | |
| 259 args.GetReturnValue().Set(wrapper); | |
| 260 } | |
| 261 | |
| 262 template <class CPlusPlusArrayType, class JavaScriptWrapperArrayType> | |
| 263 void setWebGLArrayHelper(const v8::FunctionCallbackInfo<v8::Value>& args) | |
| 264 { | |
| 265 if (args.Length() < 1) { | |
| 266 throwNotEnoughArgumentsError(args.GetIsolate()); | |
| 267 return; | |
| 268 } | |
| 269 | |
| 270 CPlusPlusArrayType* impl = JavaScriptWrapperArrayType::toNative(args.Holder(
)); | |
| 271 | |
| 272 if (JavaScriptWrapperArrayType::HasInstance(args[0], args.GetIsolate(), worl
dType(args.GetIsolate()))) { | |
| 273 // void set(in WebGL<T>Array array, [Optional] in unsigned long offset); | |
| 274 CPlusPlusArrayType* src = JavaScriptWrapperArrayType::toNative(args[0]->
ToObject()); | |
| 275 uint32_t offset = 0; | |
| 276 if (args.Length() == 2) | |
| 277 offset = toUInt32(args[1]); | |
| 278 if (!impl->set(src, offset)) { | |
| 279 throwError(v8RangeError, outOfRangeLengthAndOffset, args.GetIsolate(
)); | |
| 280 return; | |
| 281 } | |
| 282 return; | |
| 283 } | |
| 284 | |
| 285 if (args[0]->IsObject()) { | |
| 286 // void set(in sequence<long> array, [Optional] in unsigned long offset)
; | |
| 287 v8::Local<v8::Object> array = args[0]->ToObject(); | |
| 288 uint32_t offset = 0; | |
| 289 if (args.Length() == 2) | |
| 290 offset = toUInt32(args[1]); | |
| 291 uint32_t length = toUInt32(array->Get(v8::String::NewSymbol("length"))); | |
| 292 if (!impl->checkInboundData(offset, length)) { | |
| 293 throwError(v8RangeError, outOfRangeLengthAndOffset, args.GetIsolate(
)); | |
| 294 return; | |
| 295 } | |
| 296 bool copied = copyElements(args.Holder(), array, length, offset, args.Ge
tIsolate()); | |
| 297 if (!copied) { | |
| 298 for (uint32_t i = 0; i < length; i++) | |
| 299 impl->set(offset + i, array->Get(i)->NumberValue()); | |
| 300 } | |
| 301 return; | |
| 302 } | |
| 303 | |
| 304 throwTypeError("Invalid argument", args.GetIsolate()); | |
| 305 } | |
| 306 | |
| 307 } | |
| 308 | |
| 309 #endif // V8ArrayBufferViewCustom_h | 65 #endif // V8ArrayBufferViewCustom_h |
| OLD | NEW |