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#include "config.h"
32
33#if ENABLE(WEBGL)
34
35#include "V8WebGLRenderingContext.h"
36
37#include "ExceptionCode.h"
38#include "NotImplemented.h"
39#include "V8ArrayBufferView.h"
40#include "V8Binding.h"
41#include "V8BindingMacros.h"
42#include "V8WebKitLoseContext.h"
43#include "V8Float32Array.h"
44#include "V8HTMLCanvasElement.h"
45#include "V8HTMLImageElement.h"
46#include "V8HTMLVideoElement.h"
47#include "V8ImageData.h"
48#include "V8Int16Array.h"
49#include "V8Int32Array.h"
50#include "V8Int8Array.h"
51#include "V8OESStandardDerivatives.h"
52#include "V8OESTextureFloat.h"
53#include "V8OESVertexArrayObject.h"
54#include "V8Proxy.h"
55#include "V8Uint16Array.h"
56#include "V8Uint32Array.h"
57#include "V8Uint8Array.h"
58#include "V8WebGLBuffer.h"
59#include "V8WebGLFramebuffer.h"
60#include "V8WebGLProgram.h"
61#include "V8WebGLRenderbuffer.h"
62#include "V8WebGLShader.h"
63#include "V8WebGLTexture.h"
64#include "V8WebGLUniformLocation.h"
65#include "V8WebGLVertexArrayObjectOES.h"
66#include "WebGLRenderingContext.h"
67#include <wtf/FastMalloc.h>
68
69namespace WebCore {
70
71// Allocates new storage via tryFastMalloc.
72// Returns NULL if array failed to convert for any reason.
73static float* jsArrayToFloatArray(v8::Handle<v8::Array> array, uint32_t len)
74{
75    // Convert the data element-by-element.
76    float* data;
77    if (!tryFastMalloc(len * sizeof(float)).getValue(data))
78        return 0;
79    for (uint32_t i = 0; i < len; i++) {
80        v8::Local<v8::Value> val = array->Get(v8::Integer::New(i));
81        if (!val->IsNumber()) {
82            fastFree(data);
83            return 0;
84        }
85        data[i] = toFloat(val);
86    }
87    return data;
88}
89
90// Allocates new storage via tryFastMalloc.
91// Returns NULL if array failed to convert for any reason.
92static int* jsArrayToIntArray(v8::Handle<v8::Array> array, uint32_t len)
93{
94    // Convert the data element-by-element.
95    int* data;
96    if (!tryFastMalloc(len * sizeof(int)).getValue(data))
97        return 0;
98    for (uint32_t i = 0; i < len; i++) {
99        v8::Local<v8::Value> val = array->Get(v8::Integer::New(i));
100        bool ok;
101        int ival = toInt32(val, ok);
102        if (!ok) {
103            fastFree(data);
104            return 0;
105        }
106        data[i] = ival;
107    }
108    return data;
109}
110
111static v8::Handle<v8::Value> toV8Object(const WebGLGetInfo& info)
112{
113    switch (info.getType()) {
114    case WebGLGetInfo::kTypeBool:
115        return v8::Boolean::New(info.getBool());
116    case WebGLGetInfo::kTypeBoolArray: {
117        const Vector<bool>& value = info.getBoolArray();
118        v8::Local<v8::Array> array = v8::Array::New(value.size());
119        for (size_t ii = 0; ii < value.size(); ++ii)
120            array->Set(v8::Integer::New(ii), v8::Boolean::New(value[ii]));
121        return array;
122    }
123    case WebGLGetInfo::kTypeFloat:
124        return v8::Number::New(info.getFloat());
125    case WebGLGetInfo::kTypeInt:
126        return v8::Integer::New(info.getInt());
127    case WebGLGetInfo::kTypeNull:
128        return v8::Null();
129    case WebGLGetInfo::kTypeString:
130        return v8::String::New(fromWebCoreString(info.getString()), info.getString().length());
131    case WebGLGetInfo::kTypeUnsignedInt:
132        return v8::Integer::NewFromUnsigned(info.getUnsignedInt());
133    case WebGLGetInfo::kTypeWebGLBuffer:
134        return toV8(info.getWebGLBuffer());
135    case WebGLGetInfo::kTypeWebGLFloatArray:
136        return toV8(info.getWebGLFloatArray());
137    case WebGLGetInfo::kTypeWebGLFramebuffer:
138        return toV8(info.getWebGLFramebuffer());
139    case WebGLGetInfo::kTypeWebGLIntArray:
140        return toV8(info.getWebGLIntArray());
141    // FIXME: implement WebGLObjectArray
142    // case WebGLGetInfo::kTypeWebGLObjectArray:
143    case WebGLGetInfo::kTypeWebGLProgram:
144        return toV8(info.getWebGLProgram());
145    case WebGLGetInfo::kTypeWebGLRenderbuffer:
146        return toV8(info.getWebGLRenderbuffer());
147    case WebGLGetInfo::kTypeWebGLTexture:
148        return toV8(info.getWebGLTexture());
149    case WebGLGetInfo::kTypeWebGLUnsignedByteArray:
150        return toV8(info.getWebGLUnsignedByteArray());
151    case WebGLGetInfo::kTypeWebGLVertexArrayObjectOES:
152        return toV8(info.getWebGLVertexArrayObjectOES());
153    default:
154        notImplemented();
155        return v8::Undefined();
156    }
157}
158
159static v8::Handle<v8::Value> toV8Object(WebGLExtension* extension, v8::Handle<v8::Object> contextObject)
160{
161    if (!extension)
162        return v8::Null();
163    v8::Handle<v8::Value> extensionObject;
164    const char* referenceName;
165    switch (extension->getName()) {
166    case WebGLExtension::WebKitLoseContextName:
167        extensionObject = toV8(static_cast<WebKitLoseContext*>(extension));
168        referenceName = "webKitLoseContextName";
169        break;
170    case WebGLExtension::OESStandardDerivativesName:
171        extensionObject = toV8(static_cast<OESStandardDerivatives*>(extension));
172        referenceName = "oesStandardDerivativesName";
173        break;
174    case WebGLExtension::OESTextureFloatName:
175        extensionObject = toV8(static_cast<OESTextureFloat*>(extension));
176        referenceName = "oesTextureFloatName";
177        break;
178    case WebGLExtension::OESVertexArrayObjectName:
179        extensionObject = toV8(static_cast<OESVertexArrayObject*>(extension));
180        referenceName = "oesVertexArrayObjectName";
181        break;
182    }
183    ASSERT(!extensionObject.IsEmpty());
184    V8DOMWrapper::setNamedHiddenReference(contextObject, referenceName, extensionObject);
185    return extensionObject;
186}
187
188enum ObjectType {
189    kBuffer, kRenderbuffer, kTexture, kVertexAttrib
190};
191
192static v8::Handle<v8::Value> getObjectParameter(const v8::Arguments& args, ObjectType objectType)
193{
194    if (args.Length() != 2) {
195        V8Proxy::setDOMException(SYNTAX_ERR);
196        return notHandledByInterceptor();
197    }
198
199    ExceptionCode ec = 0;
200    WebGLRenderingContext* context = V8WebGLRenderingContext::toNative(args.Holder());
201    unsigned target = toInt32(args[0]);
202    unsigned pname = toInt32(args[1]);
203    WebGLGetInfo info;
204    switch (objectType) {
205    case kBuffer:
206        info = context->getBufferParameter(target, pname, ec);
207        break;
208    case kRenderbuffer:
209        info = context->getRenderbufferParameter(target, pname, ec);
210        break;
211    case kTexture:
212        info = context->getTexParameter(target, pname, ec);
213        break;
214    case kVertexAttrib:
215        // target => index
216        info = context->getVertexAttrib(target, pname, ec);
217        break;
218    default:
219        notImplemented();
220        break;
221    }
222    if (ec) {
223        V8Proxy::setDOMException(ec);
224        return v8::Undefined();
225    }
226    return toV8Object(info);
227}
228
229static WebGLUniformLocation* toWebGLUniformLocation(v8::Handle<v8::Value> value, bool& ok)
230{
231    ok = false;
232    WebGLUniformLocation* location = 0;
233    if (V8WebGLUniformLocation::HasInstance(value)) {
234        location = V8WebGLUniformLocation::toNative(value->ToObject());
235        ok = true;
236    }
237    return location;
238}
239
240enum WhichProgramCall {
241    kProgramParameter, kUniform
242};
243
244v8::Handle<v8::Value> V8WebGLRenderingContext::getAttachedShadersCallback(const v8::Arguments& args)
245{
246    INC_STATS("DOM.WebGLRenderingContext.getAttachedShaders()");
247
248    if (args.Length() < 1) {
249        V8Proxy::setDOMException(SYNTAX_ERR);
250        return notHandledByInterceptor();
251    }
252
253    ExceptionCode ec = 0;
254    WebGLRenderingContext* context = V8WebGLRenderingContext::toNative(args.Holder());
255    if (args.Length() > 0 && !isUndefinedOrNull(args[0]) && !V8WebGLProgram::HasInstance(args[0])) {
256        V8Proxy::throwTypeError();
257        return notHandledByInterceptor();
258    }
259    WebGLProgram* program = V8WebGLProgram::HasInstance(args[0]) ? V8WebGLProgram::toNative(v8::Handle<v8::Object>::Cast(args[0])) : 0;
260    Vector<WebGLShader*> shaders;
261    bool succeed = context->getAttachedShaders(program, shaders, ec);
262    if (ec) {
263        V8Proxy::setDOMException(ec);
264        return v8::Null();
265    }
266    if (!succeed)
267        return v8::Null();
268    v8::Local<v8::Array> array = v8::Array::New(shaders.size());
269    for (size_t ii = 0; ii < shaders.size(); ++ii)
270        array->Set(v8::Integer::New(ii), toV8(shaders[ii]));
271    return array;
272}
273
274v8::Handle<v8::Value> V8WebGLRenderingContext::getBufferParameterCallback(const v8::Arguments& args)
275{
276    INC_STATS("DOM.WebGLRenderingContext.getBufferParameter()");
277    return getObjectParameter(args, kBuffer);
278}
279
280v8::Handle<v8::Value> V8WebGLRenderingContext::getExtensionCallback(const v8::Arguments& args)
281{
282    INC_STATS("DOM.WebGLRenderingContext.getExtensionCallback()");
283    WebGLRenderingContext* imp = V8WebGLRenderingContext::toNative(args.Holder());
284    if (args.Length() < 1) {
285        V8Proxy::setDOMException(SYNTAX_ERR);
286        return notHandledByInterceptor();
287    }
288    STRING_TO_V8PARAMETER_EXCEPTION_BLOCK(V8Parameter<>, name, args[0]);
289    WebGLExtension* extension = imp->getExtension(name);
290    return toV8Object(extension, args.Holder());
291}
292
293v8::Handle<v8::Value> V8WebGLRenderingContext::getFramebufferAttachmentParameterCallback(const v8::Arguments& args)
294{
295    INC_STATS("DOM.WebGLRenderingContext.getFramebufferAttachmentParameter()");
296
297    if (args.Length() != 3) {
298        V8Proxy::setDOMException(SYNTAX_ERR);
299        return notHandledByInterceptor();
300    }
301
302    ExceptionCode ec = 0;
303    WebGLRenderingContext* context = V8WebGLRenderingContext::toNative(args.Holder());
304    unsigned target = toInt32(args[0]);
305    unsigned attachment = toInt32(args[1]);
306    unsigned pname = toInt32(args[2]);
307    WebGLGetInfo info = context->getFramebufferAttachmentParameter(target, attachment, pname, ec);
308    if (ec) {
309        V8Proxy::setDOMException(ec);
310        return v8::Undefined();
311    }
312    return toV8Object(info);
313}
314
315v8::Handle<v8::Value> V8WebGLRenderingContext::getParameterCallback(const v8::Arguments& args)
316{
317    INC_STATS("DOM.WebGLRenderingContext.getParameter()");
318
319    if (args.Length() != 1) {
320        V8Proxy::setDOMException(SYNTAX_ERR);
321        return notHandledByInterceptor();
322    }
323
324    ExceptionCode ec = 0;
325    WebGLRenderingContext* context = V8WebGLRenderingContext::toNative(args.Holder());
326    unsigned pname = toInt32(args[0]);
327    WebGLGetInfo info = context->getParameter(pname, ec);
328    if (ec) {
329        V8Proxy::setDOMException(ec);
330        return v8::Undefined();
331    }
332    return toV8Object(info);
333}
334
335v8::Handle<v8::Value> V8WebGLRenderingContext::getProgramParameterCallback(const v8::Arguments& args)
336{
337    INC_STATS("DOM.WebGLRenderingContext.getProgramParameter()");
338
339    if (args.Length() != 2) {
340        V8Proxy::setDOMException(SYNTAX_ERR);
341        return notHandledByInterceptor();
342    }
343
344    ExceptionCode ec = 0;
345    WebGLRenderingContext* context = V8WebGLRenderingContext::toNative(args.Holder());
346    if (args.Length() > 0 && !isUndefinedOrNull(args[0]) && !V8WebGLProgram::HasInstance(args[0])) {
347        V8Proxy::throwTypeError();
348        return notHandledByInterceptor();
349    }
350    WebGLProgram* program = V8WebGLProgram::HasInstance(args[0]) ? V8WebGLProgram::toNative(v8::Handle<v8::Object>::Cast(args[0])) : 0;
351    unsigned pname = toInt32(args[1]);
352    WebGLGetInfo info = context->getProgramParameter(program, pname, ec);
353    if (ec) {
354        V8Proxy::setDOMException(ec);
355        return v8::Undefined();
356    }
357    return toV8Object(info);
358}
359
360v8::Handle<v8::Value> V8WebGLRenderingContext::getRenderbufferParameterCallback(const v8::Arguments& args)
361{
362    INC_STATS("DOM.WebGLRenderingContext.getRenderbufferParameter()");
363    return getObjectParameter(args, kRenderbuffer);
364}
365
366v8::Handle<v8::Value> V8WebGLRenderingContext::getShaderParameterCallback(const v8::Arguments& args)
367{
368    INC_STATS("DOM.WebGLRenderingContext.getShaderParameter()");
369
370    if (args.Length() != 2) {
371        V8Proxy::setDOMException(SYNTAX_ERR);
372        return notHandledByInterceptor();
373    }
374
375    ExceptionCode ec = 0;
376    WebGLRenderingContext* context = V8WebGLRenderingContext::toNative(args.Holder());
377    if (args.Length() > 0 && !isUndefinedOrNull(args[0]) && !V8WebGLShader::HasInstance(args[0])) {
378        V8Proxy::throwTypeError();
379        return notHandledByInterceptor();
380    }
381    WebGLShader* shader = V8WebGLShader::HasInstance(args[0]) ? V8WebGLShader::toNative(v8::Handle<v8::Object>::Cast(args[0])) : 0;
382    unsigned pname = toInt32(args[1]);
383    WebGLGetInfo info = context->getShaderParameter(shader, pname, ec);
384    if (ec) {
385        V8Proxy::setDOMException(ec);
386        return v8::Undefined();
387    }
388    return toV8Object(info);
389}
390
391v8::Handle<v8::Value> V8WebGLRenderingContext::getSupportedExtensionsCallback(const v8::Arguments& args)
392{
393    INC_STATS("DOM.WebGLRenderingContext.getSupportedExtensionsCallback()");
394    WebGLRenderingContext* imp = V8WebGLRenderingContext::toNative(args.Holder());
395    if (imp->isContextLost())
396        return v8::Null();
397
398    Vector<String> value = imp->getSupportedExtensions();
399    v8::Local<v8::Array> array = v8::Array::New(value.size());
400    for (size_t ii = 0; ii < value.size(); ++ii)
401        array->Set(v8::Integer::New(ii), v8::String::New(fromWebCoreString(value[ii]), value[ii].length()));
402    return array;
403}
404
405v8::Handle<v8::Value> V8WebGLRenderingContext::getTexParameterCallback(const v8::Arguments& args)
406{
407    INC_STATS("DOM.WebGLRenderingContext.getTexParameter()");
408    return getObjectParameter(args, kTexture);
409}
410
411v8::Handle<v8::Value> V8WebGLRenderingContext::getUniformCallback(const v8::Arguments& args)
412{
413    INC_STATS("DOM.WebGLRenderingContext.getUniform()");
414
415    if (args.Length() != 2) {
416        V8Proxy::setDOMException(SYNTAX_ERR);
417        return notHandledByInterceptor();
418    }
419
420    ExceptionCode ec = 0;
421    WebGLRenderingContext* context = V8WebGLRenderingContext::toNative(args.Holder());
422    if (args.Length() > 0 && !isUndefinedOrNull(args[0]) && !V8WebGLProgram::HasInstance(args[0])) {
423        V8Proxy::throwTypeError();
424        return notHandledByInterceptor();
425    }
426    WebGLProgram* program = V8WebGLProgram::HasInstance(args[0]) ? V8WebGLProgram::toNative(v8::Handle<v8::Object>::Cast(args[0])) : 0;
427
428    if (args.Length() > 1 && !isUndefinedOrNull(args[1]) && !V8WebGLUniformLocation::HasInstance(args[1])) {
429        V8Proxy::throwTypeError();
430        return notHandledByInterceptor();
431    }
432    bool ok = false;
433    WebGLUniformLocation* location = toWebGLUniformLocation(args[1], ok);
434
435    WebGLGetInfo info = context->getUniform(program, location, ec);
436    if (ec) {
437        V8Proxy::setDOMException(ec);
438        return v8::Undefined();
439    }
440    return toV8Object(info);
441}
442
443v8::Handle<v8::Value> V8WebGLRenderingContext::getVertexAttribCallback(const v8::Arguments& args)
444{
445    INC_STATS("DOM.WebGLRenderingContext.getVertexAttrib()");
446    return getObjectParameter(args, kVertexAttrib);
447}
448
449enum FunctionToCall {
450    kUniform1v, kUniform2v, kUniform3v, kUniform4v,
451    kVertexAttrib1v, kVertexAttrib2v, kVertexAttrib3v, kVertexAttrib4v
452};
453
454bool isFunctionToCallForAttribute(FunctionToCall functionToCall)
455{
456    switch (functionToCall) {
457    case kVertexAttrib1v:
458    case kVertexAttrib2v:
459    case kVertexAttrib3v:
460    case kVertexAttrib4v:
461        return true;
462    default:
463        break;
464    }
465    return false;
466}
467
468static v8::Handle<v8::Value> vertexAttribAndUniformHelperf(const v8::Arguments& args,
469                                                           FunctionToCall functionToCall) {
470    // Forms:
471    // * glUniform1fv(WebGLUniformLocation location, Array data);
472    // * glUniform1fv(WebGLUniformLocation location, Float32Array data);
473    // * glUniform2fv(WebGLUniformLocation location, Array data);
474    // * glUniform2fv(WebGLUniformLocation location, Float32Array data);
475    // * glUniform3fv(WebGLUniformLocation location, Array data);
476    // * glUniform3fv(WebGLUniformLocation location, Float32Array data);
477    // * glUniform4fv(WebGLUniformLocation location, Array data);
478    // * glUniform4fv(WebGLUniformLocation location, Float32Array data);
479    // * glVertexAttrib1fv(GLint index, Array data);
480    // * glVertexAttrib1fv(GLint index, Float32Array data);
481    // * glVertexAttrib2fv(GLint index, Array data);
482    // * glVertexAttrib2fv(GLint index, Float32Array data);
483    // * glVertexAttrib3fv(GLint index, Array data);
484    // * glVertexAttrib3fv(GLint index, Float32Array data);
485    // * glVertexAttrib4fv(GLint index, Array data);
486    // * glVertexAttrib4fv(GLint index, Float32Array data);
487
488    if (args.Length() != 2) {
489        V8Proxy::setDOMException(SYNTAX_ERR);
490        return notHandledByInterceptor();
491    }
492
493    bool ok = false;
494    int index = -1;
495    WebGLUniformLocation* location = 0;
496
497    if (isFunctionToCallForAttribute(functionToCall))
498        index = toInt32(args[0]);
499    else {
500        if (args.Length() > 0 && !isUndefinedOrNull(args[0]) && !V8WebGLUniformLocation::HasInstance(args[0])) {
501            V8Proxy::throwTypeError();
502            return notHandledByInterceptor();
503        }
504        location = toWebGLUniformLocation(args[0], ok);
505    }
506
507    WebGLRenderingContext* context = V8WebGLRenderingContext::toNative(args.Holder());
508
509    if (V8Float32Array::HasInstance(args[1])) {
510        Float32Array* array = V8Float32Array::toNative(args[1]->ToObject());
511        ASSERT(array != NULL);
512        ExceptionCode ec = 0;
513        switch (functionToCall) {
514            case kUniform1v: context->uniform1fv(location, array, ec); break;
515            case kUniform2v: context->uniform2fv(location, array, ec); break;
516            case kUniform3v: context->uniform3fv(location, array, ec); break;
517            case kUniform4v: context->uniform4fv(location, array, ec); break;
518            case kVertexAttrib1v: context->vertexAttrib1fv(index, array); break;
519            case kVertexAttrib2v: context->vertexAttrib2fv(index, array); break;
520            case kVertexAttrib3v: context->vertexAttrib3fv(index, array); break;
521            case kVertexAttrib4v: context->vertexAttrib4fv(index, array); break;
522            default: ASSERT_NOT_REACHED(); break;
523        }
524        if (ec)
525            V8Proxy::setDOMException(ec);
526        return v8::Undefined();
527    }
528
529    if (args[1].IsEmpty() || !args[1]->IsArray()) {
530        V8Proxy::throwTypeError();
531        return notHandledByInterceptor();
532    }
533    v8::Handle<v8::Array> array =
534      v8::Local<v8::Array>::Cast(args[1]);
535    uint32_t len = array->Length();
536    float* data = jsArrayToFloatArray(array, len);
537    if (!data) {
538        // FIXME: consider different / better exception type.
539        V8Proxy::setDOMException(SYNTAX_ERR);
540        return notHandledByInterceptor();
541    }
542    ExceptionCode ec = 0;
543    switch (functionToCall) {
544        case kUniform1v: context->uniform1fv(location, data, len, ec); break;
545        case kUniform2v: context->uniform2fv(location, data, len, ec); break;
546        case kUniform3v: context->uniform3fv(location, data, len, ec); break;
547        case kUniform4v: context->uniform4fv(location, data, len, ec); break;
548        case kVertexAttrib1v: context->vertexAttrib1fv(index, data, len); break;
549        case kVertexAttrib2v: context->vertexAttrib2fv(index, data, len); break;
550        case kVertexAttrib3v: context->vertexAttrib3fv(index, data, len); break;
551        case kVertexAttrib4v: context->vertexAttrib4fv(index, data, len); break;
552        default: ASSERT_NOT_REACHED(); break;
553    }
554    fastFree(data);
555    if (ec)
556        V8Proxy::setDOMException(ec);
557    return v8::Undefined();
558}
559
560static v8::Handle<v8::Value> uniformHelperi(const v8::Arguments& args,
561                                            FunctionToCall functionToCall) {
562    // Forms:
563    // * glUniform1iv(GLUniformLocation location, Array data);
564    // * glUniform1iv(GLUniformLocation location, Int32Array data);
565    // * glUniform2iv(GLUniformLocation location, Array data);
566    // * glUniform2iv(GLUniformLocation location, Int32Array data);
567    // * glUniform3iv(GLUniformLocation location, Array data);
568    // * glUniform3iv(GLUniformLocation location, Int32Array data);
569    // * glUniform4iv(GLUniformLocation location, Array data);
570    // * glUniform4iv(GLUniformLocation location, Int32Array data);
571
572    if (args.Length() != 2) {
573        V8Proxy::setDOMException(SYNTAX_ERR);
574        return notHandledByInterceptor();
575    }
576
577    WebGLRenderingContext* context = V8WebGLRenderingContext::toNative(args.Holder());
578    if (args.Length() > 0 && !isUndefinedOrNull(args[0]) && !V8WebGLUniformLocation::HasInstance(args[0])) {
579        V8Proxy::throwTypeError();
580        return notHandledByInterceptor();
581    }
582    bool ok = false;
583    WebGLUniformLocation* location = toWebGLUniformLocation(args[0], ok);
584
585    if (V8Int32Array::HasInstance(args[1])) {
586        Int32Array* array = V8Int32Array::toNative(args[1]->ToObject());
587        ASSERT(array != NULL);
588        ExceptionCode ec = 0;
589        switch (functionToCall) {
590            case kUniform1v: context->uniform1iv(location, array, ec); break;
591            case kUniform2v: context->uniform2iv(location, array, ec); break;
592            case kUniform3v: context->uniform3iv(location, array, ec); break;
593            case kUniform4v: context->uniform4iv(location, array, ec); break;
594            default: ASSERT_NOT_REACHED(); break;
595        }
596        if (ec)
597            V8Proxy::setDOMException(ec);
598        return v8::Undefined();
599    }
600
601    if (args[1].IsEmpty() || !args[1]->IsArray()) {
602        V8Proxy::throwTypeError();
603        return notHandledByInterceptor();
604    }
605    v8::Handle<v8::Array> array =
606      v8::Local<v8::Array>::Cast(args[1]);
607    uint32_t len = array->Length();
608    int* data = jsArrayToIntArray(array, len);
609    if (!data) {
610        // FIXME: consider different / better exception type.
611        V8Proxy::setDOMException(SYNTAX_ERR);
612        return notHandledByInterceptor();
613    }
614    ExceptionCode ec = 0;
615    switch (functionToCall) {
616        case kUniform1v: context->uniform1iv(location, data, len, ec); break;
617        case kUniform2v: context->uniform2iv(location, data, len, ec); break;
618        case kUniform3v: context->uniform3iv(location, data, len, ec); break;
619        case kUniform4v: context->uniform4iv(location, data, len, ec); break;
620        default: ASSERT_NOT_REACHED(); break;
621    }
622    fastFree(data);
623    if (ec)
624        V8Proxy::setDOMException(ec);
625    return v8::Undefined();
626}
627
628v8::Handle<v8::Value> V8WebGLRenderingContext::uniform1fvCallback(const v8::Arguments& args)
629{
630    INC_STATS("DOM.WebGLRenderingContext.uniform1fv()");
631    return vertexAttribAndUniformHelperf(args, kUniform1v);
632}
633
634v8::Handle<v8::Value> V8WebGLRenderingContext::uniform1ivCallback(const v8::Arguments& args)
635{
636    INC_STATS("DOM.WebGLRenderingContext.uniform1iv()");
637    return uniformHelperi(args, kUniform1v);
638}
639
640v8::Handle<v8::Value> V8WebGLRenderingContext::uniform2fvCallback(const v8::Arguments& args)
641{
642    INC_STATS("DOM.WebGLRenderingContext.uniform2fv()");
643    return vertexAttribAndUniformHelperf(args, kUniform2v);
644}
645
646v8::Handle<v8::Value> V8WebGLRenderingContext::uniform2ivCallback(const v8::Arguments& args)
647{
648    INC_STATS("DOM.WebGLRenderingContext.uniform2iv()");
649    return uniformHelperi(args, kUniform2v);
650}
651
652v8::Handle<v8::Value> V8WebGLRenderingContext::uniform3fvCallback(const v8::Arguments& args)
653{
654    INC_STATS("DOM.WebGLRenderingContext.uniform3fv()");
655    return vertexAttribAndUniformHelperf(args, kUniform3v);
656}
657
658v8::Handle<v8::Value> V8WebGLRenderingContext::uniform3ivCallback(const v8::Arguments& args)
659{
660    INC_STATS("DOM.WebGLRenderingContext.uniform3iv()");
661    return uniformHelperi(args, kUniform3v);
662}
663
664v8::Handle<v8::Value> V8WebGLRenderingContext::uniform4fvCallback(const v8::Arguments& args)
665{
666    INC_STATS("DOM.WebGLRenderingContext.uniform4fv()");
667    return vertexAttribAndUniformHelperf(args, kUniform4v);
668}
669
670v8::Handle<v8::Value> V8WebGLRenderingContext::uniform4ivCallback(const v8::Arguments& args)
671{
672    INC_STATS("DOM.WebGLRenderingContext.uniform4iv()");
673    return uniformHelperi(args, kUniform4v);
674}
675
676static v8::Handle<v8::Value> uniformMatrixHelper(const v8::Arguments& args,
677                                                 int matrixSize)
678{
679    // Forms:
680    // * glUniformMatrix2fv(GLint location, GLboolean transpose, Array data);
681    // * glUniformMatrix2fv(GLint location, GLboolean transpose, Float32Array data);
682    // * glUniformMatrix3fv(GLint location, GLboolean transpose, Array data);
683    // * glUniformMatrix3fv(GLint location, GLboolean transpose, Float32Array data);
684    // * glUniformMatrix4fv(GLint location, GLboolean transpose, Array data);
685    // * glUniformMatrix4fv(GLint location, GLboolean transpose, Float32Array data);
686    //
687    // FIXME: need to change to accept Float32Array as well.
688    if (args.Length() != 3) {
689        V8Proxy::setDOMException(SYNTAX_ERR);
690        return notHandledByInterceptor();
691    }
692
693    WebGLRenderingContext* context = V8WebGLRenderingContext::toNative(args.Holder());
694
695    if (args.Length() > 0 && !isUndefinedOrNull(args[0]) && !V8WebGLUniformLocation::HasInstance(args[0])) {
696        V8Proxy::throwTypeError();
697        return notHandledByInterceptor();
698    }
699    bool ok = false;
700    WebGLUniformLocation* location = toWebGLUniformLocation(args[0], ok);
701
702    bool transpose = args[1]->BooleanValue();
703    if (V8Float32Array::HasInstance(args[2])) {
704        Float32Array* array = V8Float32Array::toNative(args[2]->ToObject());
705        ASSERT(array != NULL);
706        ExceptionCode ec = 0;
707        switch (matrixSize) {
708            case 2: context->uniformMatrix2fv(location, transpose, array, ec); break;
709            case 3: context->uniformMatrix3fv(location, transpose, array, ec); break;
710            case 4: context->uniformMatrix4fv(location, transpose, array, ec); break;
711            default: ASSERT_NOT_REACHED(); break;
712        }
713        if (ec)
714            V8Proxy::setDOMException(ec);
715        return v8::Undefined();
716    }
717
718    if (args[2].IsEmpty() || !args[2]->IsArray()) {
719        V8Proxy::throwTypeError();
720        return notHandledByInterceptor();
721    }
722    v8::Handle<v8::Array> array =
723      v8::Local<v8::Array>::Cast(args[2]);
724    uint32_t len = array->Length();
725    float* data = jsArrayToFloatArray(array, len);
726    if (!data) {
727        // FIXME: consider different / better exception type.
728        V8Proxy::setDOMException(SYNTAX_ERR);
729        return notHandledByInterceptor();
730    }
731    ExceptionCode ec = 0;
732    switch (matrixSize) {
733        case 2: context->uniformMatrix2fv(location, transpose, data, len, ec); break;
734        case 3: context->uniformMatrix3fv(location, transpose, data, len, ec); break;
735        case 4: context->uniformMatrix4fv(location, transpose, data, len, ec); break;
736        default: ASSERT_NOT_REACHED(); break;
737    }
738    fastFree(data);
739    if (ec)
740        V8Proxy::setDOMException(ec);
741    return v8::Undefined();
742}
743
744v8::Handle<v8::Value> V8WebGLRenderingContext::uniformMatrix2fvCallback(const v8::Arguments& args)
745{
746    INC_STATS("DOM.WebGLRenderingContext.uniformMatrix2fv()");
747    return uniformMatrixHelper(args, 2);
748}
749
750v8::Handle<v8::Value> V8WebGLRenderingContext::uniformMatrix3fvCallback(const v8::Arguments& args)
751{
752    INC_STATS("DOM.WebGLRenderingContext.uniformMatrix3fv()");
753    return uniformMatrixHelper(args, 3);
754}
755
756v8::Handle<v8::Value> V8WebGLRenderingContext::uniformMatrix4fvCallback(const v8::Arguments& args)
757{
758    INC_STATS("DOM.WebGLRenderingContext.uniformMatrix4fv()");
759    return uniformMatrixHelper(args, 4);
760}
761
762v8::Handle<v8::Value> V8WebGLRenderingContext::vertexAttrib1fvCallback(const v8::Arguments& args)
763{
764    INC_STATS("DOM.WebGLRenderingContext.vertexAttrib1fv()");
765    return vertexAttribAndUniformHelperf(args, kVertexAttrib1v);
766}
767
768v8::Handle<v8::Value> V8WebGLRenderingContext::vertexAttrib2fvCallback(const v8::Arguments& args)
769{
770    INC_STATS("DOM.WebGLRenderingContext.vertexAttrib2fv()");
771    return vertexAttribAndUniformHelperf(args, kVertexAttrib2v);
772}
773
774v8::Handle<v8::Value> V8WebGLRenderingContext::vertexAttrib3fvCallback(const v8::Arguments& args)
775{
776    INC_STATS("DOM.WebGLRenderingContext.vertexAttrib3fv()");
777    return vertexAttribAndUniformHelperf(args, kVertexAttrib3v);
778}
779
780v8::Handle<v8::Value> V8WebGLRenderingContext::vertexAttrib4fvCallback(const v8::Arguments& args)
781{
782    INC_STATS("DOM.WebGLRenderingContext.vertexAttrib4fv()");
783    return vertexAttribAndUniformHelperf(args, kVertexAttrib4v);
784}
785
786} // namespace WebCore
787
788#endif // ENABLE(WEBGL)
789