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