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 |