~ubuntu-branches/ubuntu/raring/qtwebkit-source/raring-proposed

« back to all changes in this revision

Viewing changes to Source/WebCore/bindings/v8/custom/V8ArrayBufferViewCustom.h

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2013-02-18 14:24:18 UTC
  • Revision ID: package-import@ubuntu.com-20130218142418-eon0jmjg3nj438uy
Tags: upstream-2.3
ImportĀ upstreamĀ versionĀ 2.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2009, 2011 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 <wtf/ArrayBuffer.h>
 
35
#include "ExceptionCode.h"
 
36
 
 
37
#include "V8ArrayBuffer.h"
 
38
#include "V8ArrayBufferCustom.h"
 
39
#include "V8Binding.h"
 
40
 
 
41
namespace WebCore {
 
42
 
 
43
const char tooLargeSize[] = "Size is too large (or is negative).";
 
44
const char outOfRangeLengthAndOffset[] = "Index is out of range.";
 
45
 
 
46
// Copy the elements from the source array to the typed destination array.
 
47
// Returns true if it succeeded, otherwise returns false.
 
48
bool copyElements(v8::Handle<v8::Object> destArray, v8::Handle<v8::Object> srcArray, uint32_t length, uint32_t offset, v8::Isolate*);
 
49
 
 
50
template<class ArrayClass>
 
51
v8::Handle<v8::Value> wrapArrayBufferView(const v8::Arguments& args, WrapperTypeInfo* type, ArrayClass array, v8::ExternalArrayType arrayType, bool hasIndexer)
 
52
{
 
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()->baseAddress(), arrayType, array.get()->length());
 
57
    v8::Handle<v8::Object> wrapper = args.Holder();
 
58
    v8::Persistent<v8::Object> wrapperHandle = V8DOMWrapper::createDOMWrapper(array.release(), type, wrapper);
 
59
    wrapperHandle.MarkIndependent();
 
60
    return wrapper;
 
61
}
 
62
 
 
63
// Template function used by the ArrayBufferView*Constructor callbacks.
 
64
template<class ArrayClass, class ElementType>
 
65
v8::Handle<v8::Value> constructWebGLArrayWithArrayBufferArgument(const v8::Arguments& args, WrapperTypeInfo* type, v8::ExternalArrayType arrayType, bool hasIndexer)
 
66
{
 
67
    ArrayBuffer* buf = V8ArrayBuffer::toNative(args[0]->ToObject());
 
68
    if (!buf)
 
69
        return throwTypeError("Could not convert argument 0 to a ArrayBuffer", args.GetIsolate());
 
70
    bool ok;
 
71
    uint32_t offset = 0;
 
72
    int argLen = args.Length();
 
73
    if (argLen > 1) {
 
74
        offset = toUInt32(args[1], ok);
 
75
        if (!ok)
 
76
            return throwTypeError("Could not convert argument 1 to a number", args.GetIsolate());
 
77
    }
 
78
    uint32_t length = 0;
 
79
    if (argLen > 2) {
 
80
        length = toUInt32(args[2], ok);
 
81
        if (!ok)
 
82
            return throwTypeError("Could not convert argument 2 to a number", args.GetIsolate());
 
83
    } else {
 
84
        if ((buf->byteLength() - offset) % sizeof(ElementType))
 
85
            return throwError(v8RangeError, "ArrayBuffer length minus the byteOffset is not a multiple of the element size.", args.GetIsolate());
 
86
        length = (buf->byteLength() - offset) / sizeof(ElementType);
 
87
    }
 
88
 
 
89
    if (static_cast<int32_t>(length) < 0)
 
90
        return throwError(v8RangeError, tooLargeSize, args.GetIsolate());
 
91
 
 
92
    RefPtr<ArrayClass> array = ArrayClass::create(buf, offset, length);
 
93
    if (!array)
 
94
        return throwError(v8RangeError, tooLargeSize, args.GetIsolate());
 
95
 
 
96
    return wrapArrayBufferView(args, type, array, arrayType, hasIndexer);
 
97
}
 
98
 
 
99
// Template function used by the ArrayBufferView*Constructor callbacks.
 
100
template<class ArrayClass, class JavaScriptWrapperArrayType, class ElementType>
 
101
v8::Handle<v8::Value> constructWebGLArray(const v8::Arguments& args, WrapperTypeInfo* type, v8::ExternalArrayType arrayType)
 
102
{
 
103
    if (!args.IsConstructCall())
 
104
        return throwTypeError("DOM object constructor cannot be called as a function.", args.GetIsolate());
 
105
 
 
106
    if (ConstructorMode::current() == ConstructorMode::WrapExistingObject)
 
107
        return args.Holder();
 
108
 
 
109
    int argLen = args.Length();
 
110
    if (!argLen) {
 
111
        // This happens when we return a previously constructed
 
112
        // ArrayBufferView, e.g. from the call to <Type>Array.subset().
 
113
        // The V8DOMWrapper will set the internal pointer in the
 
114
        // created object. Unfortunately it doesn't look like it's
 
115
        // possible to distinguish between this case and that where
 
116
        // the user calls "new <Type>Array()" from JavaScript. We must
 
117
        // construct an empty view to avoid crashes when fetching the
 
118
        // length.
 
119
        RefPtr<ArrayClass> array = ArrayClass::create(0);
 
120
        // Do not call SetIndexedPropertiesToExternalArrayData on this
 
121
        // object. Not only is there no point from a performance
 
122
        // perspective, but doing so causes errors in the subset() case.
 
123
        return wrapArrayBufferView(args, type, array, arrayType, false);
 
124
    }
 
125
 
 
126
    // Supported constructors:
 
127
    // WebGL<T>Array(n) where n is an integer:
 
128
    //   -- create an empty array of n elements
 
129
    // WebGL<T>Array(arr) where arr is an array:
 
130
    //   -- create a WebGL<T>Array containing the contents of "arr"
 
131
    // WebGL<T>Array(buf, offset, length)
 
132
    //   -- create a WebGL<T>Array pointing to the ArrayBuffer
 
133
    //      "buf", starting at the specified offset, for the given
 
134
    //      length
 
135
 
 
136
    if (args[0]->IsNull()) {
 
137
        // Invalid first argument
 
138
        return throwTypeError(0, args.GetIsolate());
 
139
    }
 
140
 
 
141
    // See whether the first argument is a ArrayBuffer.
 
142
    if (V8ArrayBuffer::HasInstance(args[0]))
 
143
      return constructWebGLArrayWithArrayBufferArgument<ArrayClass, ElementType>(args, type, arrayType, true);
 
144
 
 
145
    // See whether the first argument is the same type as impl. In that case,
 
146
    // we can simply memcpy data from source to impl.
 
147
    if (JavaScriptWrapperArrayType::HasInstance(args[0])) {
 
148
        ArrayClass* source = JavaScriptWrapperArrayType::toNative(args[0]->ToObject());
 
149
        uint32_t length = source->length();
 
150
 
 
151
        if (static_cast<int32_t>(length) < 0)
 
152
            return throwError(v8RangeError, tooLargeSize, args.GetIsolate());
 
153
 
 
154
        RefPtr<ArrayClass> array = ArrayClass::createUninitialized(length);
 
155
        if (!array.get())
 
156
            return throwError(v8RangeError, tooLargeSize, args.GetIsolate());
 
157
 
 
158
        array->buffer()->setDeallocationObserver(V8ArrayBufferDeallocationObserver::instance());
 
159
        v8::V8::AdjustAmountOfExternalAllocatedMemory(array->byteLength());
 
160
 
 
161
        memcpy(array->baseAddress(), source->baseAddress(), length * sizeof(ElementType));
 
162
 
 
163
        return wrapArrayBufferView(args, type, array, arrayType, true);
 
164
    }
 
165
 
 
166
    uint32_t len = 0;
 
167
    v8::Handle<v8::Object> srcArray;
 
168
    bool doInstantiation = false;
 
169
 
 
170
    if (args[0]->IsObject()) {
 
171
        srcArray = args[0]->ToObject();
 
172
        if (srcArray.IsEmpty())
 
173
            return throwTypeError("Could not convert argument 0 to an array", args.GetIsolate());
 
174
        len = toUInt32(srcArray->Get(v8::String::New("length")));
 
175
        doInstantiation = true;
 
176
    } else {
 
177
        bool ok = false;
 
178
        int32_t tempLength = toInt32(args[0], ok); // NaN/+inf/-inf returns 0, this is intended by WebIDL
 
179
        if (ok && tempLength >= 0) {
 
180
            len = static_cast<uint32_t>(tempLength);
 
181
            doInstantiation = true;
 
182
        }
 
183
    }
 
184
 
 
185
    if (static_cast<int32_t>(len) < 0)
 
186
        return throwError(v8RangeError, tooLargeSize, args.GetIsolate());
 
187
 
 
188
    RefPtr<ArrayClass> array;
 
189
    if (doInstantiation) {
 
190
        if (srcArray.IsEmpty())
 
191
            array = ArrayClass::create(len);
 
192
        else
 
193
            array = ArrayClass::createUninitialized(len);
 
194
    }
 
195
 
 
196
    if (!array.get())
 
197
        return throwError(v8RangeError, tooLargeSize, args.GetIsolate());
 
198
 
 
199
    if (doInstantiation) {
 
200
        array->buffer()->setDeallocationObserver(V8ArrayBufferDeallocationObserver::instance());
 
201
        v8::V8::AdjustAmountOfExternalAllocatedMemory(array->byteLength());
 
202
    }
 
203
 
 
204
 
 
205
    // Transform the holder into a wrapper object for the array.
 
206
    args.Holder()->SetIndexedPropertiesToExternalArrayData(array.get()->baseAddress(), arrayType, array.get()->length());
 
207
 
 
208
    if (!srcArray.IsEmpty()) {
 
209
        bool copied = copyElements(args.Holder(), srcArray, len, 0, args.GetIsolate());
 
210
        if (!copied) {
 
211
            for (unsigned i = 0; i < len; i++)
 
212
                array->set(i, srcArray->Get(i)->NumberValue());
 
213
        }
 
214
    }
 
215
 
 
216
    v8::Handle<v8::Object> wrapper = args.Holder();
 
217
    v8::Persistent<v8::Object> wrapperHandle = V8DOMWrapper::createDOMWrapper(array.release(), type, wrapper);
 
218
    wrapperHandle.MarkIndependent();
 
219
    return wrapper;
 
220
}
 
221
 
 
222
template <class CPlusPlusArrayType, class JavaScriptWrapperArrayType>
 
223
v8::Handle<v8::Value> setWebGLArrayHelper(const v8::Arguments& args)
 
224
{
 
225
    if (args.Length() < 1)
 
226
        return throwNotEnoughArgumentsError(args.GetIsolate());
 
227
 
 
228
    CPlusPlusArrayType* impl = JavaScriptWrapperArrayType::toNative(args.Holder());
 
229
 
 
230
    if (JavaScriptWrapperArrayType::HasInstance(args[0])) {
 
231
        // void set(in WebGL<T>Array array, [Optional] in unsigned long offset);
 
232
        CPlusPlusArrayType* src = JavaScriptWrapperArrayType::toNative(args[0]->ToObject());
 
233
        uint32_t offset = 0;
 
234
        if (args.Length() == 2)
 
235
            offset = toUInt32(args[1]);
 
236
        if (!impl->set(src, offset))
 
237
            return throwError(v8RangeError, outOfRangeLengthAndOffset, args.GetIsolate());
 
238
        return v8::Undefined();
 
239
    }
 
240
 
 
241
    if (args[0]->IsObject()) {
 
242
        // void set(in sequence<long> array, [Optional] in unsigned long offset);
 
243
        v8::Local<v8::Object> array = args[0]->ToObject();
 
244
        uint32_t offset = 0;
 
245
        if (args.Length() == 2)
 
246
            offset = toUInt32(args[1]);
 
247
        uint32_t length = toUInt32(array->Get(v8::String::New("length")));
 
248
        if (!impl->checkInboundData(offset, length))
 
249
            return throwError(v8RangeError, outOfRangeLengthAndOffset, args.GetIsolate());
 
250
        bool copied = copyElements(args.Holder(), array, length, offset, args.GetIsolate());
 
251
        if (!copied) {
 
252
            for (uint32_t i = 0; i < length; i++)
 
253
                impl->set(offset + i, array->Get(i)->NumberValue());
 
254
        }
 
255
        return v8::Undefined();
 
256
    }
 
257
 
 
258
    return throwTypeError("Invalid argument", args.GetIsolate());
 
259
}
 
260
 
 
261
}
 
262
 
 
263
#endif // V8ArrayBufferViewCustom_h