Objective-C API: Rename JSValue.h/APIJSValue.h to JSCJSValue.h/JSValue.h
[WebKit-https.git] / Source / WebCore / bindings / js / JSArrayBufferViewHelper.h
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
42 namespace WebCore {
43
44 static const char* tooLargeSize = "Size is too large (or is negative).";
45
46 template<class C, typename T>
47 bool 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
102 template <class C, typename T>
103 bool 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, JSC::Identifier(exec, "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
125 template<class C, typename T>
126 JSC::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, JSC::Identifier(exec, "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.
161 template<class C, typename T>
162 PassRefPtr<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, JSC::Identifier(exec, "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.
189 template<class C, typename T>
190 PassRefPtr<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
213 template<class C, typename T>
214 PassRefPtr<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, JSC::Identifier(exec, "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
270 template <typename JSType, typename WebCoreType>
271 static 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