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